@@ -277,13 +277,37 @@ hashtable_unicode_compare(const void *key1, const void *key2)
277
277
}
278
278
}
279
279
280
+ /* Return true if this interpreter should share the main interpreter's
281
+ intern_dict. That's important for interpreters which load basic
282
+ single-phase init extension modules (m_size == -1). There could be interned
283
+ immortal strings that are shared between interpreters, due to the
284
+ PyDict_Update(mdict, m_copy) call in import_find_extension().
285
+
286
+ It's not safe to deallocate those strings until all interpreters that
287
+ potentially use them are freed. By storing them in the main interpreter, we
288
+ ensure they get freed after all other interpreters are freed.
289
+ */
290
+ static bool
291
+ has_shared_intern_dict (PyInterpreterState * interp )
292
+ {
293
+ PyInterpreterState * main_interp = _PyInterpreterState_Main ();
294
+ return interp != main_interp && interp -> feature_flags & Py_RTFLAGS_USE_MAIN_OBMALLOC ;
295
+ }
296
+
280
297
static int
281
298
init_interned_dict (PyInterpreterState * interp )
282
299
{
283
300
assert (get_interned_dict (interp ) == NULL );
284
- PyObject * interned = interned = PyDict_New ();
285
- if (interned == NULL ) {
286
- return -1 ;
301
+ PyObject * interned ;
302
+ if (has_shared_intern_dict (interp )) {
303
+ interned = get_interned_dict (_PyInterpreterState_Main ());
304
+ Py_INCREF (interned );
305
+ }
306
+ else {
307
+ interned = PyDict_New ();
308
+ if (interned == NULL ) {
309
+ return -1 ;
310
+ }
287
311
}
288
312
_Py_INTERP_CACHED_OBJECT (interp , interned_strings ) = interned ;
289
313
return 0 ;
@@ -294,7 +318,10 @@ clear_interned_dict(PyInterpreterState *interp)
294
318
{
295
319
PyObject * interned = get_interned_dict (interp );
296
320
if (interned != NULL ) {
297
- PyDict_Clear (interned );
321
+ if (!has_shared_intern_dict (interp )) {
322
+ // only clear if the dict belongs to this interpreter
323
+ PyDict_Clear (interned );
324
+ }
298
325
Py_DECREF (interned );
299
326
_Py_INTERP_CACHED_OBJECT (interp , interned_strings ) = NULL ;
300
327
}
@@ -15306,6 +15333,13 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp)
15306
15333
}
15307
15334
assert (PyDict_CheckExact (interned ));
15308
15335
15336
+ if (has_shared_intern_dict (interp )) {
15337
+ // the dict doesn't belong to this interpreter, skip the debug
15338
+ // checks on it and just clear the pointer to it
15339
+ clear_interned_dict (interp );
15340
+ return ;
15341
+ }
15342
+
15309
15343
#ifdef INTERNED_STATS
15310
15344
fprintf (stderr , "releasing %zd interned strings\n" ,
15311
15345
PyDict_GET_SIZE (interned ));
@@ -15827,8 +15861,10 @@ _PyUnicode_Fini(PyInterpreterState *interp)
15827
15861
{
15828
15862
struct _Py_unicode_state * state = & interp -> unicode ;
15829
15863
15830
- // _PyUnicode_ClearInterned() must be called before _PyUnicode_Fini()
15831
- assert (get_interned_dict (interp ) == NULL );
15864
+ if (!has_shared_intern_dict (interp )) {
15865
+ // _PyUnicode_ClearInterned() must be called before _PyUnicode_Fini()
15866
+ assert (get_interned_dict (interp ) == NULL );
15867
+ }
15832
15868
15833
15869
_PyUnicode_FiniEncodings (& state -> fs_codec );
15834
15870
0 commit comments