GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — [3.12] gh-116510: Fix a crash due to shared immortal interned strings… · python/cpython@5dd07eb

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
  • Misc/NEWS.d/next/Core_and_Builtins
    • 2024-09-25-12-37-58.gh-issue-116510.WeBAx1.rst
  • Objects
    • unicodeobject.c
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎Misc/NEWS.d/next/Core_and_Builtins/2024-09-25-12-37-58.gh-issue-116510.WeBAx1.rst‎

Copy file name to clipboard
+5Lines changed: 5 additions & 0 deletions
  • Display the source diff
  • Display the rich diff
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.
Collapse file

‎Objects/unicodeobject.c‎

Copy file name to clipboardExpand all lines: Objects/unicodeobject.c
+42-6Lines changed: 42 additions & 6 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;
@@ -297,7 +321,10 @@ clear_interned_dict(PyInterpreterState *interp)
297321
{
298322
PyObject *interned = get_interned_dict(interp);
299323
if (interned != NULL) {
300-
PyDict_Clear(interned);
324+
if (!has_shared_intern_dict(interp)) {
325+
// only clear if the dict belongs to this interpreter
326+
PyDict_Clear(interned);
327+
}
301328
Py_DECREF(interned);
302329
_Py_INTERP_CACHED_OBJECT(interp, interned_strings) = NULL;
303330
}
@@ -14861,6 +14888,13 @@ _PyUnicode_ClearInterned(PyInterpreterState *interp)
1486114888
}
1486214889
assert(PyDict_CheckExact(interned));
1486314890

14891+
if (has_shared_intern_dict(interp)) {
14892+
// the dict doesn't belong to this interpreter, skip the debug
14893+
// checks on it and just clear the pointer to it
14894+
clear_interned_dict(interp);
14895+
return;
14896+
}
14897+
1486414898
/* TODO:
1486514899
* Currently, the runtime is not able to guarantee that it can exit without
1486614900
* allocations that carry over to a future initialization of Python within
@@ -15364,8 +15398,10 @@ _PyUnicode_Fini(PyInterpreterState *interp)
1536415398
{
1536515399
struct _Py_unicode_state *state = &interp->unicode;
1536615400

15367-
// _PyUnicode_ClearInterned() must be called before _PyUnicode_Fini()
15368-
assert(get_interned_dict(interp) == NULL);
15401+
if (!has_shared_intern_dict(interp)) {
15402+
// _PyUnicode_ClearInterned() must be called before _PyUnicode_Fini()
15403+
assert(get_interned_dict(interp) == NULL);
15404+
}
1536915405

1537015406
_PyUnicode_FiniEncodings(&state->fs_codec);
1537115407

0 commit comments

Comments
0 (0)
You are visitor 01402520 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.