From 444b39bb64aa894d3f1831210a8ce40042a5a532 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 20 Nov 2019 01:18:11 +0100 Subject: [PATCH] bpo-38631: Avoid Py_FatalError() in handle_legacy_finalizers() (GH-17266) * Rename _PyGC_Initialize() to _PyGC_InitializeRuntime() * Add _PyGC_Init(): initialize _PyRuntime.gc.garbage list * Call _PyGC_Init() before _PyTypes_Init() --- Include/internal/pycore_pylifecycle.h | 1 + Include/internal/pycore_pymem.h | 2 +- Modules/gcmodule.c | 24 ++++++++++++++++++------ Python/pylifecycle.c | 15 +++++++++++---- Python/pystate.c | 2 +- 5 files changed, 32 insertions(+), 12 deletions(-) diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h index d89dbeacb24..16baf10061b 100644 --- a/Include/internal/pycore_pylifecycle.h +++ b/Include/internal/pycore_pylifecycle.h @@ -57,6 +57,7 @@ extern PyStatus _Py_HashRandomization_Init(const PyConfig *); extern PyStatus _PyTypes_Init(void); extern PyStatus _PyImportZip_Init(PyThreadState *tstate); +extern PyStatus _PyGC_Init(struct pyruntimestate *runtime); /* Various internal finalizers */ diff --git a/Include/internal/pycore_pymem.h b/Include/internal/pycore_pymem.h index 535f99e8cc5..97d8fd99904 100644 --- a/Include/internal/pycore_pymem.h +++ b/Include/internal/pycore_pymem.h @@ -144,7 +144,7 @@ struct _gc_runtime_state { Py_ssize_t long_lived_pending; }; -PyAPI_FUNC(void) _PyGC_Initialize(struct _gc_runtime_state *); +PyAPI_FUNC(void) _PyGC_InitializeRuntime(struct _gc_runtime_state *); /* Set the memory allocator of the specified domain to the default. diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index cb7a3de57a3..d2e39371b9e 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -25,6 +25,7 @@ #include "Python.h" #include "pycore_context.h" +#include "pycore_initconfig.h" #include "pycore_object.h" #include "pycore_pymem.h" #include "pycore_pystate.h" @@ -129,7 +130,7 @@ static PyObject *gc_str = NULL; #define GEN_HEAD(state, n) (&(state)->generations[n].head) void -_PyGC_Initialize(struct _gc_runtime_state *state) +_PyGC_InitializeRuntime(struct _gc_runtime_state *state) { state->enabled = 1; /* automatic collection enabled? */ @@ -151,6 +152,21 @@ _PyGC_Initialize(struct _gc_runtime_state *state) state->permanent_generation = permanent_generation; } + +PyStatus +_PyGC_Init(_PyRuntimeState *runtime) +{ + struct _gc_runtime_state *state = &runtime->gc; + if (state->garbage == NULL) { + state->garbage = PyList_New(0); + if (state->garbage == NULL) { + return _PyStatus_NO_MEMORY(); + } + } + return _PyStatus_OK(); +} + + /* _gc_prev values --------------- @@ -905,13 +921,9 @@ handle_legacy_finalizers(struct _gc_runtime_state *state, PyGC_Head *finalizers, PyGC_Head *old) { assert(!PyErr_Occurred()); + assert(state->garbage != NULL); PyGC_Head *gc = GC_NEXT(finalizers); - if (state->garbage == NULL) { - state->garbage = PyList_New(0); - if (state->garbage == NULL) - Py_FatalError("gc couldn't create gc.garbage list"); - } for (; gc != finalizers; gc = GC_NEXT(gc)) { PyObject *op = FROM_GC(gc); diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 1bfc7c16dc6..9739bb15418 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -558,9 +558,16 @@ pycore_create_interpreter(_PyRuntimeState *runtime, static PyStatus -pycore_init_types(void) +pycore_init_types(_PyRuntimeState *runtime) { - PyStatus status = _PyTypes_Init(); + PyStatus status; + + status = _PyGC_Init(runtime); + if (_PyStatus_EXCEPTION(status)) { + return status; + } + + status = _PyTypes_Init(); if (_PyStatus_EXCEPTION(status)) { return status; } @@ -683,7 +690,7 @@ pyinit_config(_PyRuntimeState *runtime, config = &tstate->interp->config; *tstate_p = tstate; - status = pycore_init_types(); + status = pycore_init_types(runtime); if (_PyStatus_EXCEPTION(status)) { return status; } @@ -1447,7 +1454,7 @@ new_interpreter(PyThreadState **tstate_p) } config = &interp->config; - status = pycore_init_types(); + status = pycore_init_types(runtime); /* XXX The following is lax in error checking */ PyObject *modules = PyDict_New(); diff --git a/Python/pystate.c b/Python/pystate.c index b4b12472286..06cc9a8fb44 100644 --- a/Python/pystate.c +++ b/Python/pystate.c @@ -58,7 +58,7 @@ _PyRuntimeState_Init_impl(_PyRuntimeState *runtime) runtime->open_code_userdata = open_code_userdata; runtime->audit_hook_head = audit_hook_head; - _PyGC_Initialize(&runtime->gc); + _PyGC_InitializeRuntime(&runtime->gc); _PyEval_Initialize(&runtime->ceval); PyPreConfig_InitPythonConfig(&runtime->preconfig);