From 64ce00359ab462153750e59ab97a688452461e90 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 12 Jan 2022 23:09:43 +0100 Subject: [PATCH 1/2] bpo-46070: Revert "bpo-36854: Move _PyRuntimeState.gc to PyInterpreterState (GH-17287)" This reverts commit 7247407c35330f3f6292f1d40606b7ba6afd5700. Fix a random crash involving subinterpreters on Windows. Revert the change which made the gc module state per interpreter: the gc module state is shared again by all interpreters. --- Include/internal/pycore_gc.h | 2 +- Include/internal/pycore_interp.h | 2 - Include/internal/pycore_object.h | 4 +- Include/internal/pycore_pylifecycle.h | 6 +- Include/internal/pycore_runtime.h | 2 + .../2022-01-12-23-13-39.bpo-46070.cQp0eC.rst | 3 + Modules/gcmodule.c | 58 +++++++++---------- Objects/object.c | 8 +-- Python/pylifecycle.c | 12 ++-- Python/pystate.c | 6 +- Python/traceback.c | 4 +- 11 files changed, 57 insertions(+), 50 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2022-01-12-23-13-39.bpo-46070.cQp0eC.rst diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index 9db4a4716fa588..496ad8e41ed373 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -161,7 +161,7 @@ struct _gc_runtime_state { Py_ssize_t long_lived_pending; }; -extern void _PyGC_InitState(struct _gc_runtime_state *); +extern void _PyGC_InitializeRuntime(struct _gc_runtime_state *); extern Py_ssize_t _PyGC_CollectNoFail(PyThreadState *tstate); diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 4307b61ca36aaf..3d93f73954ddd8 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -11,7 +11,6 @@ extern "C" { #include "pycore_atomic.h" // _Py_atomic_address #include "pycore_ast_state.h" // struct ast_state #include "pycore_gil.h" // struct _gil_runtime_state -#include "pycore_gc.h" // struct _gc_runtime_state #include "pycore_warnings.h" // struct _warnings_runtime_state struct _pending_calls { @@ -229,7 +228,6 @@ struct _is { int finalizing; struct _ceval_state ceval; - struct _gc_runtime_state gc; // sys.modules dictionary PyObject *modules; diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index 90d98134b8919b..ba3199767bb687 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -87,8 +87,8 @@ static inline void _PyObject_GC_TRACK( "object is in generation which is garbage collected", filename, lineno, __func__); - PyInterpreterState *interp = _PyInterpreterState_GET(); - PyGC_Head *generation0 = interp->gc.generation0; + _PyRuntimeState *runtime = &_PyRuntime; + PyGC_Head *generation0 = runtime->gc.generation0; PyGC_Head *last = (PyGC_Head*)(generation0->_gc_prev); _PyGCHead_SET_NEXT(last, gc); _PyGCHead_SET_PREV(gc, last); diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h index 524be9d4cbb940..e230b5f4f3afe6 100644 --- a/Include/internal/pycore_pylifecycle.h +++ b/Include/internal/pycore_pylifecycle.h @@ -75,7 +75,7 @@ extern PyStatus _Py_HashRandomization_Init(const PyConfig *); extern PyStatus _PyTypes_Init(void); extern PyStatus _PyTypes_InitSlotDefs(void); extern PyStatus _PyImportZip_Init(PyThreadState *tstate); -extern PyStatus _PyGC_Init(PyInterpreterState *interp); +extern PyStatus _PyGC_Init(void); extern PyStatus _PyAtExit_Init(PyInterpreterState *interp); @@ -96,7 +96,7 @@ extern void _PySignal_Fini(void); extern void _PyExc_Fini(PyInterpreterState *interp); extern void _PyImport_Fini(void); extern void _PyImport_Fini2(void); -extern void _PyGC_Fini(PyInterpreterState *interp); +extern void _PyGC_Fini(void); extern void _PyType_Fini(PyInterpreterState *interp); extern void _Py_HashRandomization_Fini(void); extern void _PyUnicode_Fini(PyInterpreterState *interp); @@ -113,7 +113,7 @@ extern PyStatus _PyGILState_Init(_PyRuntimeState *runtime); extern PyStatus _PyGILState_SetTstate(PyThreadState *tstate); extern void _PyGILState_Fini(PyInterpreterState *interp); -PyAPI_FUNC(void) _PyGC_DumpShutdownStats(PyInterpreterState *interp); +PyAPI_FUNC(void) _PyGC_DumpShutdownStats(void); PyAPI_FUNC(PyStatus) _Py_PreInitializeFromPyArgv( const PyPreConfig *src_config, diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index bcd710c4496bd7..7a654b0c9e589f 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -9,6 +9,7 @@ extern "C" { #endif #include "pycore_atomic.h" /* _Py_atomic_address */ +#include "pycore_gc.h" // struct _gc_runtime_state #include "pycore_gil.h" // struct _gil_runtime_state /* ceval state */ @@ -104,6 +105,7 @@ typedef struct pyruntimestate { void (*exitfuncs[NEXITFUNCS])(void); int nexitfuncs; + struct _gc_runtime_state gc; struct _ceval_runtime_state ceval; struct _gilstate_runtime_state gilstate; diff --git a/Misc/NEWS.d/next/Core and Builtins/2022-01-12-23-13-39.bpo-46070.cQp0eC.rst b/Misc/NEWS.d/next/Core and Builtins/2022-01-12-23-13-39.bpo-46070.cQp0eC.rst new file mode 100644 index 00000000000000..c55578ff87f5d8 --- /dev/null +++ b/Misc/NEWS.d/next/Core and Builtins/2022-01-12-23-13-39.bpo-46070.cQp0eC.rst @@ -0,0 +1,3 @@ +Fix a random crash involving subinterpreters on Windows. Revert the change +which made the gc module state per interpreter: the gc module state is +shared again by all interpreters. Patch by Victor Stinner. diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index e5e5aa3287b0d6..479ddd6f976930 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -131,13 +131,13 @@ gc_decref(PyGC_Head *g) static GCState * get_gc_state(void) { - PyInterpreterState *interp = _PyInterpreterState_GET(); - return &interp->gc; + _PyRuntimeState *runtime = &_PyRuntime; + return &runtime->gc; } void -_PyGC_InitState(GCState *gcstate) +_PyGC_InitializeRuntime(GCState *gcstate) { gcstate->enabled = 1; /* automatic collection enabled? */ @@ -161,9 +161,9 @@ _PyGC_InitState(GCState *gcstate) PyStatus -_PyGC_Init(PyInterpreterState *interp) +_PyGC_Init(void) { - GCState *gcstate = &interp->gc; + GCState *gcstate = get_gc_state(); gcstate->garbage = PyList_New(0); if (gcstate->garbage == NULL) { @@ -1193,7 +1193,7 @@ gc_collect_main(PyThreadState *tstate, int generation, PyGC_Head finalizers; /* objects with, & reachable from, __del__ */ PyGC_Head *gc; _PyTime_t t1 = 0; /* initialize to prevent a compiler warning */ - GCState *gcstate = &tstate->interp->gc; + GCState *gcstate = get_gc_state(); // gc_collect_main() must not be called before _PyGC_Init // or after _PyGC_Fini() @@ -1367,7 +1367,7 @@ invoke_gc_callback(PyThreadState *tstate, const char *phase, assert(!_PyErr_Occurred(tstate)); /* we may get called very early */ - GCState *gcstate = &tstate->interp->gc; + GCState *gcstate = get_gc_state(); if (gcstate->callbacks == NULL) { return; } @@ -1419,7 +1419,7 @@ gc_collect_with_callback(PyThreadState *tstate, int generation) static Py_ssize_t gc_collect_generations(PyThreadState *tstate) { - GCState *gcstate = &tstate->interp->gc; + GCState *gcstate = get_gc_state(); /* Find the oldest generation (highest numbered) where the count * exceeds the threshold. Objects in the that generation and * generations younger than it will be collected. */ @@ -1540,7 +1540,7 @@ gc_collect_impl(PyObject *module, int generation) return -1; } - GCState *gcstate = &tstate->interp->gc; + GCState *gcstate = get_gc_state(); Py_ssize_t n; if (gcstate->collecting) { /* already collecting, don't do anything */ @@ -1761,10 +1761,9 @@ static PyObject * gc_get_objects_impl(PyObject *module, Py_ssize_t generation) /*[clinic end generated code: output=48b35fea4ba6cb0e input=ef7da9df9806754c]*/ { - PyThreadState *tstate = _PyThreadState_GET(); int i; PyObject* result; - GCState *gcstate = &tstate->interp->gc; + GCState *gcstate = get_gc_state(); if (PySys_Audit("gc.get_objects", "n", generation) < 0) { return NULL; @@ -1778,16 +1777,16 @@ gc_get_objects_impl(PyObject *module, Py_ssize_t generation) /* If generation is passed, we extract only that generation */ if (generation != -1) { if (generation >= NUM_GENERATIONS) { - _PyErr_Format(tstate, PyExc_ValueError, - "generation parameter must be less than the number of " - "available generations (%i)", - NUM_GENERATIONS); + PyErr_Format(PyExc_ValueError, + "generation parameter must be less than the number of " + "available generations (%i)", + NUM_GENERATIONS); goto error; } if (generation < 0) { - _PyErr_SetString(tstate, PyExc_ValueError, - "generation parameter cannot be negative"); + PyErr_SetString(PyExc_ValueError, + "generation parameter cannot be negative"); goto error; } @@ -2080,9 +2079,7 @@ PyGC_IsEnabled(void) Py_ssize_t PyGC_Collect(void) { - PyThreadState *tstate = _PyThreadState_GET(); - GCState *gcstate = &tstate->interp->gc; - + GCState *gcstate = get_gc_state(); if (!gcstate->enabled) { return 0; } @@ -2095,6 +2092,7 @@ PyGC_Collect(void) else { PyObject *exc, *value, *tb; gcstate->collecting = 1; + PyThreadState *tstate = _PyThreadState_GET(); _PyErr_Fetch(tstate, &exc, &value, &tb); n = gc_collect_with_callback(tstate, NUM_GENERATIONS - 1); _PyErr_Restore(tstate, exc, value, tb); @@ -2113,7 +2111,7 @@ _PyGC_CollectNoFail(PyThreadState *tstate) during interpreter shutdown (and then never finish it). See http://bugs.python.org/issue8713#msg195178 for an example. */ - GCState *gcstate = &tstate->interp->gc; + GCState *gcstate = get_gc_state(); if (gcstate->collecting) { return 0; } @@ -2126,9 +2124,9 @@ _PyGC_CollectNoFail(PyThreadState *tstate) } void -_PyGC_DumpShutdownStats(PyInterpreterState *interp) +_PyGC_DumpShutdownStats(void) { - GCState *gcstate = &interp->gc; + GCState *gcstate = get_gc_state(); if (!(gcstate->debug & DEBUG_SAVEALL) && gcstate->garbage != NULL && PyList_GET_SIZE(gcstate->garbage) > 0) { const char *message; @@ -2163,9 +2161,9 @@ _PyGC_DumpShutdownStats(PyInterpreterState *interp) } void -_PyGC_Fini(PyInterpreterState *interp) +_PyGC_Fini(void) { - GCState *gcstate = &interp->gc; + GCState *gcstate = get_gc_state(); Py_CLEAR(gcstate->garbage); Py_CLEAR(gcstate->callbacks); } @@ -2235,10 +2233,9 @@ PyObject_IS_GC(PyObject *obj) static PyObject * _PyObject_GC_Alloc(int use_calloc, size_t basicsize) { - PyThreadState *tstate = _PyThreadState_GET(); - GCState *gcstate = &tstate->interp->gc; + GCState *gcstate = get_gc_state(); if (basicsize > PY_SSIZE_T_MAX - sizeof(PyGC_Head)) { - return _PyErr_NoMemory(tstate); + return PyErr_NoMemory(); } size_t size = sizeof(PyGC_Head) + basicsize; @@ -2250,7 +2247,7 @@ _PyObject_GC_Alloc(int use_calloc, size_t basicsize) g = (PyGC_Head *)PyObject_Malloc(size); } if (g == NULL) { - return _PyErr_NoMemory(tstate); + return PyErr_NoMemory(); } assert(((uintptr_t)g & 3) == 0); // g must be aligned 4bytes boundary @@ -2261,9 +2258,10 @@ _PyObject_GC_Alloc(int use_calloc, size_t basicsize) gcstate->enabled && gcstate->generations[0].threshold && !gcstate->collecting && - !_PyErr_Occurred(tstate)) + !PyErr_Occurred()) { gcstate->collecting = 1; + PyThreadState *tstate = _PyThreadState_GET(); gc_collect_generations(tstate); gcstate->collecting = 0; } diff --git a/Objects/object.c b/Objects/object.c index ff816cd5b9a605..fdb41d60e22d6f 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2099,8 +2099,8 @@ Py_ReprLeave(PyObject *obj) void _PyTrash_deposit_object(PyObject *op) { - PyInterpreterState *interp = _PyInterpreterState_GET(); - struct _gc_runtime_state *gcstate = &interp->gc; + _PyRuntimeState *runtime = &_PyRuntime; + struct _gc_runtime_state *gcstate = &runtime->gc; _PyObject_ASSERT(op, _PyObject_IS_GC(op)); _PyObject_ASSERT(op, !_PyObject_GC_IS_TRACKED(op)); @@ -2127,8 +2127,8 @@ _PyTrash_thread_deposit_object(PyObject *op) void _PyTrash_destroy_chain(void) { - PyInterpreterState *interp = _PyInterpreterState_GET(); - struct _gc_runtime_state *gcstate = &interp->gc; + _PyRuntimeState *runtime = &_PyRuntime; + struct _gc_runtime_state *gcstate = &runtime->gc; while (gcstate->trash_delete_later) { PyObject *op = gcstate->trash_delete_later; diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index eeaf20b4617a20..225a581766289d 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -801,10 +801,12 @@ pycore_interp_init(PyThreadState *tstate) return status; } - // The GC must be initialized before the first GC collection. - status = _PyGC_Init(interp); - if (_PyStatus_EXCEPTION(status)) { - return status; + if (_Py_IsMainInterpreter(interp)) { + // The GC must be initialized before the first GC collection. + status = _PyGC_Init(); + if (_PyStatus_EXCEPTION(status)) { + return status; + } } status = pycore_init_types(interp); @@ -1526,7 +1528,7 @@ finalize_modules(PyThreadState *tstate) // Dump GC stats before it's too late, since it uses the warnings // machinery. - _PyGC_DumpShutdownStats(interp); + _PyGC_DumpShutdownStats(); if (weaklist != NULL) { // Now, if there are any modules left alive, clear their globals to diff --git a/Python/pystate.c b/Python/pystate.c index df98eb11bb0a49..7afc6bc46ab1f1 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -65,6 +65,7 @@ _PyRuntimeState_Init_impl(_PyRuntimeState *runtime) runtime->audit_hook_head = audit_hook_head; _PyEval_InitRuntimeState(&runtime->ceval); + _PyGC_InitializeRuntime(&runtime->gc); PyPreConfig_InitPythonConfig(&runtime->preconfig); @@ -228,7 +229,6 @@ PyInterpreterState_New(void) goto out_of_memory; } - _PyGC_InitState(&interp->gc); PyConfig_InitPythonConfig(&interp->config); _PyType_InitCache(interp); @@ -327,7 +327,9 @@ interpreter_clear(PyInterpreterState *interp, PyThreadState *tstate) /* Last garbage collection on this interpreter */ _PyGC_CollectNoFail(tstate); - _PyGC_Fini(interp); + if (_Py_IsMainInterpreter(interp)) { + _PyGC_Fini(); + } /* We don't clear sysdict and builtins until the end of this function. Because clearing other attributes can execute arbitrary Python code diff --git a/Python/traceback.c b/Python/traceback.c index 7d6f7f435a6ba6..bf1778ea4df324 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -5,6 +5,7 @@ #include "code.h" #include "pycore_interp.h" // PyInterpreterState.gc +#include "pycore_runtime.h" // _PyRuntime #include "frameobject.h" // PyFrame_GetBack() #include "structmember.h" // PyMemberDef #include "osdefs.h" // SEP @@ -925,6 +926,7 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp, return "unable to get the thread head state"; /* Dump the traceback of each thread */ + _PyRuntimeState *runtime = &_PyRuntime; tstate = PyInterpreterState_ThreadHead(interp); nthreads = 0; _Py_BEGIN_SUPPRESS_IPH @@ -937,7 +939,7 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp, break; } write_thread_id(fd, tstate, tstate == current_tstate); - if (tstate == current_tstate && tstate->interp->gc.collecting) { + if (tstate == current_tstate && runtime->gc.collecting) { PUTS(fd, " Garbage-collecting\n"); } dump_traceback(fd, tstate, 0); From 01c415597102f94edc07cee47c99577fed53241e Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Thu, 13 Jan 2022 00:45:09 +0100 Subject: [PATCH 2/2] Fix the ABI --- Include/internal/pycore_gc.h | 2 +- Include/internal/pycore_interp.h | 4 ++++ Include/internal/pycore_object.h | 14 ++++++++++++-- Include/internal/pycore_runtime.h | 2 -- Modules/gcmodule.c | 5 ++--- Objects/object.c | 6 ++---- Python/pystate.c | 2 +- Python/traceback.c | 6 +++--- 8 files changed, 25 insertions(+), 16 deletions(-) diff --git a/Include/internal/pycore_gc.h b/Include/internal/pycore_gc.h index 496ad8e41ed373..9db4a4716fa588 100644 --- a/Include/internal/pycore_gc.h +++ b/Include/internal/pycore_gc.h @@ -161,7 +161,7 @@ struct _gc_runtime_state { Py_ssize_t long_lived_pending; }; -extern void _PyGC_InitializeRuntime(struct _gc_runtime_state *); +extern void _PyGC_InitState(struct _gc_runtime_state *); extern Py_ssize_t _PyGC_CollectNoFail(PyThreadState *tstate); diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 3d93f73954ddd8..1df5f413e06c99 100644 --- a/Include/internal/pycore_interp.h +++ b/Include/internal/pycore_interp.h @@ -11,6 +11,7 @@ extern "C" { #include "pycore_atomic.h" // _Py_atomic_address #include "pycore_ast_state.h" // struct ast_state #include "pycore_gil.h" // struct _gil_runtime_state +#include "pycore_gc.h" // struct _gc_runtime_state #include "pycore_warnings.h" // struct _warnings_runtime_state struct _pending_calls { @@ -228,6 +229,9 @@ struct _is { int finalizing; struct _ceval_state ceval; + // bpo-46070: Even if each PyInterpreterState has a GC state, + // _PyGC_GetState() only uses the state of the main interpreter. + struct _gc_runtime_state gc; // sys.modules dictionary PyObject *modules; diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h index ba3199767bb687..100db494f2fab9 100644 --- a/Include/internal/pycore_object.h +++ b/Include/internal/pycore_object.h @@ -57,6 +57,16 @@ _PyObject_InitVar(PyVarObject *op, PyTypeObject *typeobj, Py_ssize_t size) } +static inline struct _gc_runtime_state* +_PyGC_GetState(void) +{ + // bpo-46070: Even if each PyInterpreterState has a GC state, + // _PyGC_GetState() only uses the state of the main interpreter. + PyInterpreterState *interp = _PyRuntime.interpreters.main; + return &interp->gc; +} + + /* Tell the GC to track this object. * * The object must not be tracked by the GC. @@ -87,8 +97,8 @@ static inline void _PyObject_GC_TRACK( "object is in generation which is garbage collected", filename, lineno, __func__); - _PyRuntimeState *runtime = &_PyRuntime; - PyGC_Head *generation0 = runtime->gc.generation0; + struct _gc_runtime_state *state = _PyGC_GetState(); + PyGC_Head *generation0 = state->generation0; PyGC_Head *last = (PyGC_Head*)(generation0->_gc_prev); _PyGCHead_SET_NEXT(last, gc); _PyGCHead_SET_PREV(gc, last); diff --git a/Include/internal/pycore_runtime.h b/Include/internal/pycore_runtime.h index 7a654b0c9e589f..bcd710c4496bd7 100644 --- a/Include/internal/pycore_runtime.h +++ b/Include/internal/pycore_runtime.h @@ -9,7 +9,6 @@ extern "C" { #endif #include "pycore_atomic.h" /* _Py_atomic_address */ -#include "pycore_gc.h" // struct _gc_runtime_state #include "pycore_gil.h" // struct _gil_runtime_state /* ceval state */ @@ -105,7 +104,6 @@ typedef struct pyruntimestate { void (*exitfuncs[NEXITFUNCS])(void); int nexitfuncs; - struct _gc_runtime_state gc; struct _ceval_runtime_state ceval; struct _gilstate_runtime_state gilstate; diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 479ddd6f976930..38c71277724d35 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -131,13 +131,12 @@ gc_decref(PyGC_Head *g) static GCState * get_gc_state(void) { - _PyRuntimeState *runtime = &_PyRuntime; - return &runtime->gc; + return _PyGC_GetState(); } void -_PyGC_InitializeRuntime(GCState *gcstate) +_PyGC_InitState(GCState *gcstate) { gcstate->enabled = 1; /* automatic collection enabled? */ diff --git a/Objects/object.c b/Objects/object.c index fdb41d60e22d6f..84e1d77c42315f 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2099,8 +2099,7 @@ Py_ReprLeave(PyObject *obj) void _PyTrash_deposit_object(PyObject *op) { - _PyRuntimeState *runtime = &_PyRuntime; - struct _gc_runtime_state *gcstate = &runtime->gc; + struct _gc_runtime_state *gcstate = _PyGC_GetState(); _PyObject_ASSERT(op, _PyObject_IS_GC(op)); _PyObject_ASSERT(op, !_PyObject_GC_IS_TRACKED(op)); @@ -2127,8 +2126,7 @@ _PyTrash_thread_deposit_object(PyObject *op) void _PyTrash_destroy_chain(void) { - _PyRuntimeState *runtime = &_PyRuntime; - struct _gc_runtime_state *gcstate = &runtime->gc; + struct _gc_runtime_state *gcstate = _PyGC_GetState(); while (gcstate->trash_delete_later) { PyObject *op = gcstate->trash_delete_later; diff --git a/Python/pystate.c b/Python/pystate.c index 7afc6bc46ab1f1..4141cbb73c069c 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -65,7 +65,6 @@ _PyRuntimeState_Init_impl(_PyRuntimeState *runtime) runtime->audit_hook_head = audit_hook_head; _PyEval_InitRuntimeState(&runtime->ceval); - _PyGC_InitializeRuntime(&runtime->gc); PyPreConfig_InitPythonConfig(&runtime->preconfig); @@ -229,6 +228,7 @@ PyInterpreterState_New(void) goto out_of_memory; } + _PyGC_InitState(&interp->gc); PyConfig_InitPythonConfig(&interp->config); _PyType_InitCache(interp); diff --git a/Python/traceback.c b/Python/traceback.c index bf1778ea4df324..bf52602ed0dc4e 100644 --- a/Python/traceback.c +++ b/Python/traceback.c @@ -5,7 +5,7 @@ #include "code.h" #include "pycore_interp.h" // PyInterpreterState.gc -#include "pycore_runtime.h" // _PyRuntime +#include "pycore_object.h" // _PyGC_GetState() #include "frameobject.h" // PyFrame_GetBack() #include "structmember.h" // PyMemberDef #include "osdefs.h" // SEP @@ -926,7 +926,7 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp, return "unable to get the thread head state"; /* Dump the traceback of each thread */ - _PyRuntimeState *runtime = &_PyRuntime; + struct _gc_runtime_state *gcstate = _PyGC_GetState(); tstate = PyInterpreterState_ThreadHead(interp); nthreads = 0; _Py_BEGIN_SUPPRESS_IPH @@ -939,7 +939,7 @@ _Py_DumpTracebackThreads(int fd, PyInterpreterState *interp, break; } write_thread_id(fd, tstate, tstate == current_tstate); - if (tstate == current_tstate && runtime->gc.collecting) { + if (tstate == current_tstate && gcstate->collecting) { PUTS(fd, " Garbage-collecting\n"); } dump_traceback(fd, tstate, 0);