@@ -282,13 +282,37 @@ hashtable_unicode_compare(const void *key1, const void *key2)
282
282
}
283
283
}
284
284
285
+ /* Return true if this interpreter should share the main interpreter's
286
+ intern_dict. That's important for interpreters which load basic
287
+ single-phase init extension modules (m_size == -1). There could be interned
288
+ immortal strings that are shared between interpreters, due to the
289
+ PyDict_Update(mdict, m_copy) call in import_find_extension().
290
+
291
+ It's not safe to deallocate those strings until all interpreters that
292
+ potentially use them are freed. By storing them in the main interpreter, we
293
+ ensure they get freed after all other interpreters are freed.
294
+ */
295
+ static bool
296
+ has_shared_intern_dict (PyInterpreterState * interp )
297
+ {
298
+ PyInterpreterState * main_interp = _PyInterpreterState_Main ();
299
+ return interp != main_interp && interp -> feature_flags & Py_RTFLAGS_USE_MAIN_OBMALLOC ;
300
+ }
301
+
285
302
static int
286
303
init_interned_dict (PyInterpreterState * interp )
287
304
{
288
305
assert (get_interned_dict (interp ) == NULL );
289
- PyObject * interned = interned = PyDict_New ();
290
- if (interned == NULL ) {
291
- return -1 ;
306
+ PyObject * interned ;
307
+ if (has_shared_intern_dict (interp )) {
308
+ interned = get_interned_dict (_PyInterpreterState_Main ());
309
+ Py_INCREF (interned );
310
+ }
311
+ else {
312
+ interned = PyDict_New ();
313
+ if (interned == NULL ) {
314
+ return -1 ;
315
+ }
292
316
}
293
317
_Py_INTERP_CACHED_OBJECT (interp , interned_strings ) = interned ;
294
318
return 0 ;
@@ -299,7 +323,10 @@ clear_interned_dict(PyInterpreterState *interp)
299
323
{
300
324
PyObject * interned = get_interned_dict (interp );
301
325
if (interned != NULL ) {
302
- PyDict_Clear (interned );
326
+ if (!has_shared_intern_dict (interp )) {
327
+ // only clear if the dict belongs to this interpreter
328
+ PyDict_Clear (interned );
329
+ }
303
330
Py_DECREF (interned );
304
331
_Py_INTERP_CACHED_OBJECT (interp , interned_strings ) = NULL ;
305
332
}
@@ -15618,6 +15645,13 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp)
15618
15645
}
15619
15646
assert (PyDict_CheckExact (interned ));
15620
15647
15648
+ if (has_shared_intern_dict (interp )) {
15649
+ // the dict doesn't belong to this interpreter, skip the debug
15650
+ // checks on it and just clear the pointer to it
15651
+ clear_interned_dict (interp );
15652
+ return ;
15653
+ }
15654
+
15621
15655
#ifdef INTERNED_STATS
15622
15656
fprintf (stderr , "releasing %zd interned strings\n" ,
15623
15657
PyDict_GET_SIZE (interned ));
@@ -16126,8 +16160,10 @@ _PyUnicode_Fini(PyInterpreterState *interp)
16126
16160
{
16127
16161
struct _Py_unicode_state * state = & interp -> unicode ;
16128
16162
16129
- // _PyUnicode_ClearInterned() must be called before _PyUnicode_Fini()
16130
- assert (get_interned_dict (interp ) == NULL );
16163
+ if (!has_shared_intern_dict (interp )) {
16164
+ // _PyUnicode_ClearInterned() must be called before _PyUnicode_Fini()
16165
+ assert (get_interned_dict (interp ) == NULL );
16166
+ }
16131
16167
16132
16168
_PyUnicode_FiniEncodings (& state -> fs_codec );
16133
16169
0 commit comments