Skip to content

Commit 3aa5e2a

Browse files
committed
pythongh-116510: Fix crash due to shared immortal interned strings.
Fix a crash caused by immortal interned strings being shared between sub-interpreters that use basic single-phase init. In that case, the string can be used by an interpreter that outlives the interpeter that created and interned it. For interpreters that share obmalloc state, also share the interned dict with the main interpreter.
1 parent 13565f1 commit 3aa5e2a

File tree

2 files changed

+42
-5
lines changed

2 files changed

+42
-5
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Fix a crash caused by immortal interned strings being shared between
2+
sub-interpreters that use basic single-phase init. In that case, the string
3+
can be used by an interpreter that outlives the interpeter that created and
4+
interned it. For interpreters that share obmalloc state, also share the
5+
interned dict with the main interpreter.

Objects/unicodeobject.c

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,23 @@ hashtable_unicode_compare(const void *key1, const void *key2)
266266
}
267267
}
268268

269+
/* Return true if this interpreter should share the main interpreter's
270+
intern_dict. That's important for interpreters which load basic
271+
single-phase init extension modules (m_size == -1). There could be interned
272+
immortal strings that are shared between interpreters, due to the
273+
PyDict_Update(mdict, m_copy) call in import_find_extension().
274+
275+
It's not safe to deallocate those strings until all interpreters that
276+
potentially use them are freed. By storing them in the main interpreter, we
277+
ensure they get freed after all other interpreters are freed.
278+
*/
279+
static bool
280+
has_shared_intern_dict(PyInterpreterState *interp)
281+
{
282+
PyInterpreterState *main_interp = _PyInterpreterState_Main();
283+
return interp != main_interp && interp->feature_flags & Py_RTFLAGS_USE_MAIN_OBMALLOC;
284+
}
285+
269286
static int
270287
init_interned_dict(PyInterpreterState *interp)
271288
{
@@ -284,9 +301,16 @@ init_interned_dict(PyInterpreterState *interp)
284301
}
285302
}
286303
assert(get_interned_dict(interp) == NULL);
287-
PyObject *interned = interned = PyDict_New();
288-
if (interned == NULL) {
289-
return -1;
304+
PyObject *interned;
305+
if (has_shared_intern_dict(interp)) {
306+
interned = get_interned_dict(_PyInterpreterState_Main());
307+
Py_INCREF(interned);
308+
}
309+
else {
310+
interned = PyDict_New();
311+
if (interned == NULL) {
312+
return -1;
313+
}
290314
}
291315
_Py_INTERP_CACHED_OBJECT(interp, interned_strings) = interned;
292316
return 0;
@@ -295,6 +319,9 @@ init_interned_dict(PyInterpreterState *interp)
295319
static void
296320
clear_interned_dict(PyInterpreterState *interp)
297321
{
322+
if (has_shared_intern_dict(interp)) {
323+
return; // the dict doesn't belong to this interpreter
324+
}
298325
PyObject *interned = get_interned_dict(interp);
299326
if (interned != NULL) {
300327
PyDict_Clear(interned);
@@ -14855,6 +14882,9 @@ PyUnicode_InternFromString(const char *cp)
1485514882
void
1485614883
_PyUnicode_ClearInterned(PyInterpreterState *interp)
1485714884
{
14885+
if (has_shared_intern_dict(interp)) {
14886+
return; // the dict doesn't belong to this interpreter
14887+
}
1485814888
PyObject *interned = get_interned_dict(interp);
1485914889
if (interned == NULL) {
1486014890
return;
@@ -15364,8 +15394,10 @@ _PyUnicode_Fini(PyInterpreterState *interp)
1536415394
{
1536515395
struct _Py_unicode_state *state = &interp->unicode;
1536615396

15367-
// _PyUnicode_ClearInterned() must be called before _PyUnicode_Fini()
15368-
assert(get_interned_dict(interp) == NULL);
15397+
if (!has_shared_intern_dict(interp)) {
15398+
// _PyUnicode_ClearInterned() must be called before _PyUnicode_Fini()
15399+
assert(get_interned_dict(interp) == NULL);
15400+
}
1536915401

1537015402
_PyUnicode_FiniEncodings(&state->fs_codec);
1537115403

0 commit comments

Comments
 (0)