49
49
import java .util .ArrayList ;
50
50
import java .util .Arrays ;
51
51
import java .util .HashMap ;
52
+ import java .util .LinkedList ;
53
+ import java .util .List ;
52
54
import java .util .Map ;
53
55
import java .util .Objects ;
54
56
import java .util .concurrent .ConcurrentHashMap ;
98
100
import com .oracle .truffle .api .CompilerDirectives ;
99
101
import com .oracle .truffle .api .CompilerDirectives .CompilationFinal ;
100
102
import com .oracle .truffle .api .CompilerDirectives .TruffleBoundary ;
101
- import com .oracle .truffle .api .RootCallTarget ;
102
103
import com .oracle .truffle .api .TruffleFile ;
103
104
import com .oracle .truffle .api .TruffleLanguage .Env ;
104
105
import com .oracle .truffle .api .TruffleLogger ;
@@ -186,7 +187,21 @@ private record ClosureInfo(Object closure, Object delegate, Object executable, l
186
187
private final HashMap <Object , ClosureInfo > callableClosureByExecutable = new HashMap <>();
187
188
private final HashMap <Long , ClosureInfo > callableClosures = new HashMap <>();
188
189
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 <>();
190
205
191
206
public static TruffleLogger getLogger (Class <?> clazz ) {
192
207
return PythonLanguage .getLogger (LOGGER_CAPI_NAME + "." + clazz .getSimpleName ());
@@ -209,6 +224,11 @@ public long getAndIncMaxModuleNumber() {
209
224
return maxModuleNumber ++;
210
225
}
211
226
227
+ @ TruffleBoundary
228
+ void addLoadedExtensionLibrary (Object nativeLibrary ) {
229
+ loadedExtensions .add (nativeLibrary );
230
+ }
231
+
212
232
@ TruffleBoundary
213
233
public static Object asHex (Object ptr ) {
214
234
if (ptr instanceof Number ) {
@@ -631,6 +651,7 @@ public Object initCApiModule(Node location, Object sharedLibrary, TruffleString
631
651
PythonModule module = (PythonModule ) result ;
632
652
module .setAttribute (T___FILE__ , spec .path );
633
653
module .setAttribute (T___LIBRARY__ , sharedLibrary );
654
+ addLoadedExtensionLibrary (sharedLibrary );
634
655
635
656
// add to 'sys.modules'
636
657
PDict sysModules = context .getSysModules ();
0 commit comments