Skip to content

Commit 34cac1e

Browse files
ericsnowcurrentlymiss-islington
authored andcommitted
pythongh-105699: Fix an Interned Strings Crasher (pythongh-106930)
A static (process-global) str object must only have its "interned" state cleared when no longer interned in any interpreters. They are the only ones that can be shared by interpreters so we don't have to worry about any other str objects. We trigger clearing the state with the main interpreter, since no other interpreters may exist at that point and _PyUnicode_ClearInterned() is only called during interpreter finalization. We do not address here the fact that a string will only be interned in the first interpreter that interns it. In any subsequent interpreters str.state.interned is already set so _PyUnicode_InternInPlace() will skip it. That needs to be addressed separately from fixing the crasher. (cherry picked from commit 87e7cb0) Co-authored-by: Eric Snow <[email protected]>
1 parent ffc7678 commit 34cac1e

File tree

2 files changed

+15
-1
lines changed

2 files changed

+15
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Python no longer crashes due an infrequent race when initialzing
2+
per-interpreter interned strings. The crash would manifest when the
3+
interpreter was finalized.

Objects/unicodeobject.c

+12-1
Original file line numberDiff line numberDiff line change
@@ -14817,6 +14817,7 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp)
1481714817
PyObject *s, *ignored_value;
1481814818
while (PyDict_Next(interned, &pos, &s, &ignored_value)) {
1481914819
assert(PyUnicode_IS_READY(s));
14820+
int shared = 0;
1482014821
switch (PyUnicode_CHECK_INTERNED(s)) {
1482114822
case SSTATE_INTERNED_IMMORTAL:
1482214823
// Skip the Immortal Instance check and restore
@@ -14828,6 +14829,14 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp)
1482814829
#endif
1482914830
break;
1483014831
case SSTATE_INTERNED_IMMORTAL_STATIC:
14832+
/* It is shared between interpreters, so we should unmark it
14833+
only when this is the last interpreter in which it's
14834+
interned. We immortalize all the statically initialized
14835+
strings during startup, so we can rely on the
14836+
main interpreter to be the last one. */
14837+
if (!_Py_IsMainInterpreter(interp)) {
14838+
shared = 1;
14839+
}
1483114840
break;
1483214841
case SSTATE_INTERNED_MORTAL:
1483314842
/* fall through */
@@ -14836,7 +14845,9 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp)
1483614845
default:
1483714846
Py_UNREACHABLE();
1483814847
}
14839-
_PyUnicode_STATE(s).interned = SSTATE_NOT_INTERNED;
14848+
if (!shared) {
14849+
_PyUnicode_STATE(s).interned = SSTATE_NOT_INTERNED;
14850+
}
1484014851
}
1484114852
#ifdef INTERNED_STATS
1484214853
fprintf(stderr,

0 commit comments

Comments
 (0)