@@ -281,13 +281,37 @@ hashtable_unicode_compare(const void *key1, const void *key2)
281
281
}
282
282
}
283
283
284
+ /* Return true if this interpreter should share the main interpreter's
285
+ intern_dict. That's important for interpreters which load basic
286
+ single-phase init extension modules (m_size == -1). There could be interned
287
+ immortal strings that are shared between interpreters, due to the
288
+ PyDict_Update(mdict, m_copy) call in import_find_extension().
289
+
290
+ It's not safe to deallocate those strings until all interpreters that
291
+ potentially use them are freed. By storing them in the main interpreter, we
292
+ ensure they get freed after all other interpreters are freed.
293
+ */
294
+ static bool
295
+ has_shared_intern_dict (PyInterpreterState * interp )
296
+ {
297
+ PyInterpreterState * main_interp = _PyInterpreterState_Main ();
298
+ return interp != main_interp && interp -> feature_flags & Py_RTFLAGS_USE_MAIN_OBMALLOC ;
299
+ }
300
+
284
301
static int
285
302
init_interned_dict (PyInterpreterState * interp )
286
303
{
287
304
assert (get_interned_dict (interp ) == NULL );
288
- PyObject * interned = interned = PyDict_New ();
289
- if (interned == NULL ) {
290
- return -1 ;
305
+ PyObject * interned ;
306
+ if (has_shared_intern_dict (interp )) {
307
+ interned = get_interned_dict (_PyInterpreterState_Main ());
308
+ Py_INCREF (interned );
309
+ }
310
+ else {
311
+ interned = PyDict_New ();
312
+ if (interned == NULL ) {
313
+ return -1 ;
314
+ }
291
315
}
292
316
_Py_INTERP_CACHED_OBJECT (interp , interned_strings ) = interned ;
293
317
return 0 ;
@@ -298,7 +322,10 @@ clear_interned_dict(PyInterpreterState *interp)
298
322
{
299
323
PyObject * interned = get_interned_dict (interp );
300
324
if (interned != NULL ) {
301
- PyDict_Clear (interned );
325
+ if (!has_shared_intern_dict (interp )) {
326
+ // only clear if the dict belongs to this interpreter
327
+ PyDict_Clear (interned );
328
+ }
302
329
Py_DECREF (interned );
303
330
_Py_INTERP_CACHED_OBJECT (interp , interned_strings ) = NULL ;
304
331
}
@@ -15401,6 +15428,10 @@ _PyUnicode_InternStatic(PyInterpreterState *interp, PyObject **p)
15401
15428
assert (* p );
15402
15429
}
15403
15430
15431
+ #ifdef Py_TRACE_REFS
15432
+ extern void _Py_NormalizeImmortalReference (PyObject * );
15433
+ #endif
15434
+
15404
15435
static void
15405
15436
immortalize_interned (PyObject * s )
15406
15437
{
@@ -15416,6 +15447,10 @@ immortalize_interned(PyObject *s)
15416
15447
#endif
15417
15448
_PyUnicode_STATE (s ).interned = SSTATE_INTERNED_IMMORTAL ;
15418
15449
_Py_SetImmortal (s );
15450
+ #ifdef Py_TRACE_REFS
15451
+ /* Make sure the ref is associated with the right interpreter. */
15452
+ _Py_NormalizeImmortalReference (s );
15453
+ #endif
15419
15454
}
15420
15455
15421
15456
static /* non-null */ PyObject *
@@ -15609,6 +15644,13 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp)
15609
15644
}
15610
15645
assert (PyDict_CheckExact (interned ));
15611
15646
15647
+ if (has_shared_intern_dict (interp )) {
15648
+ // the dict doesn't belong to this interpreter, skip the debug
15649
+ // checks on it and just clear the pointer to it
15650
+ clear_interned_dict (interp );
15651
+ return ;
15652
+ }
15653
+
15612
15654
#ifdef INTERNED_STATS
15613
15655
fprintf (stderr , "releasing %zd interned strings\n" ,
15614
15656
PyDict_GET_SIZE (interned ));
@@ -16117,8 +16159,10 @@ _PyUnicode_Fini(PyInterpreterState *interp)
16117
16159
{
16118
16160
struct _Py_unicode_state * state = & interp -> unicode ;
16119
16161
16120
- // _PyUnicode_ClearInterned() must be called before _PyUnicode_Fini()
16121
- assert (get_interned_dict (interp ) == NULL );
16162
+ if (!has_shared_intern_dict (interp )) {
16163
+ // _PyUnicode_ClearInterned() must be called before _PyUnicode_Fini()
16164
+ assert (get_interned_dict (interp ) == NULL );
16165
+ }
16122
16166
16123
16167
_PyUnicode_FiniEncodings (& state -> fs_codec );
16124
16168
0 commit comments