Skip to content

Commit d88cea7

Browse files
committed
Keep native libraries alive as long as the CApiContext
1 parent 8650677 commit d88cea7

File tree

2 files changed

+24
-2
lines changed

2 files changed

+24
-2
lines changed

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CApiContext.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
import java.util.ArrayList;
5050
import java.util.Arrays;
5151
import java.util.HashMap;
52+
import java.util.LinkedList;
53+
import java.util.List;
5254
import java.util.Map;
5355
import java.util.Objects;
5456
import java.util.concurrent.ConcurrentHashMap;
@@ -98,7 +100,6 @@
98100
import com.oracle.truffle.api.CompilerDirectives;
99101
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
100102
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
101-
import com.oracle.truffle.api.RootCallTarget;
102103
import com.oracle.truffle.api.TruffleFile;
103104
import com.oracle.truffle.api.TruffleLanguage.Env;
104105
import com.oracle.truffle.api.TruffleLogger;
@@ -186,7 +187,21 @@ private record ClosureInfo(Object closure, Object delegate, Object executable, l
186187
private final HashMap<Object, ClosureInfo> callableClosureByExecutable = new HashMap<>();
187188
private final HashMap<Long, ClosureInfo> callableClosures = new HashMap<>();
188189
private Object nativeLibrary;
189-
public RootCallTarget signatureContainer;
190+
191+
/**
192+
* This list holds a strong reference to all loaded extension libraries to keep the library
193+
* objects alive. This is necessary because NFI will {@code dlclose} the library (and thus
194+
* {@code munmap} all code) if the library object is no longer reachable. However, it can happen
195+
* that we still store raw function pointers (as Java {@code long} values) in a native object
196+
* that is referenced by a
197+
* {@link com.oracle.graal.python.builtins.objects.cext.capi.transitions.CApiTransitions.NativeObjectReference}.
198+
* For example, the {code tp_dealloc} functions may be executed a long time after all managed
199+
* objects of the extension died and the native library has been {@code dlclosed}'d.
200+
*
201+
* Since we have no control over the timing when certain garbage will be collected, we need to
202+
* ensure that the code is still mapped.
203+
*/
204+
private final List<Object> loadedExtensions = new LinkedList<>();
190205

191206
public static TruffleLogger getLogger(Class<?> clazz) {
192207
return PythonLanguage.getLogger(LOGGER_CAPI_NAME + "." + clazz.getSimpleName());
@@ -209,6 +224,11 @@ public long getAndIncMaxModuleNumber() {
209224
return maxModuleNumber++;
210225
}
211226

227+
@TruffleBoundary
228+
void addLoadedExtensionLibrary(Object nativeLibrary) {
229+
loadedExtensions.add(nativeLibrary);
230+
}
231+
212232
@TruffleBoundary
213233
public static Object asHex(Object ptr) {
214234
if (ptr instanceof Number) {
@@ -631,6 +651,7 @@ public Object initCApiModule(Node location, Object sharedLibrary, TruffleString
631651
PythonModule module = (PythonModule) result;
632652
module.setAttribute(T___FILE__, spec.path);
633653
module.setAttribute(T___LIBRARY__, sharedLibrary);
654+
addLoadedExtensionLibrary(sharedLibrary);
634655

635656
// add to 'sys.modules'
636657
PDict sysModules = context.getSysModules();

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/cext/capi/CExtNodes.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1921,6 +1921,7 @@ static Object doGeneric(CApiContext capiContext, ModuleSpec moduleSpec, Object m
19211921

19221922
writeAttrNode.execute(module, SpecialAttributeNames.T___DOC__, mDoc);
19231923
writeAttrNode.execute(module, SpecialAttributeNames.T___LIBRARY__, library);
1924+
capiContext.addLoadedExtensionLibrary(library);
19241925
return module;
19251926
}
19261927
}

0 commit comments

Comments
 (0)