From 21d563c8594fd218e071c0b22a932b3a3f944595 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Wed, 18 Mar 2020 22:47:58 +0100 Subject: [PATCH] bpo-38865: Py_FinalizeEx() cannot be called in a subinterpreter Py_FinalizeEx() cannot be called in a subinterpreter anymore. Fix test_embed.test_audit_subinterpreter(): end subinterpreters. --- Doc/c-api/init.rst | 5 ++++ Doc/whatsnew/3.9.rst | 3 ++ .../2020-03-18-22-52-27.bpo-38865.KeRYAu.rst | 1 + Programs/_testembed.c | 29 ++++++++++++++----- Python/pylifecycle.c | 4 +++ 5 files changed, 34 insertions(+), 8 deletions(-) create mode 100644 Misc/NEWS.d/next/C API/2020-03-18-22-52-27.bpo-38865.KeRYAu.rst diff --git a/Doc/c-api/init.rst b/Doc/c-api/init.rst index f309ad0c03cce9..b98ee1190504e2 100644 --- a/Doc/c-api/init.rst +++ b/Doc/c-api/init.rst @@ -290,6 +290,8 @@ Initializing and finalizing the interpreter developer might want to free all memory allocated by Python before exiting from the application. + This function cannot be called in a subinterpreter. + **Bugs and caveats:** The destruction of modules and objects in modules is done in random order; this may cause destructors (:meth:`__del__` methods) to fail when they depend on other objects (even functions) or modules. Dynamically @@ -305,6 +307,9 @@ Initializing and finalizing the interpreter .. versionadded:: 3.6 + .. versionchanged:: 3.9 + This function cannot be called in a subinterpreter anymore. + .. c:function:: void Py_Finalize() This is a backwards-compatible version of :c:func:`Py_FinalizeEx` that diff --git a/Doc/whatsnew/3.9.rst b/Doc/whatsnew/3.9.rst index 6a6d1ee38c7b60..338cd889fe88a2 100644 --- a/Doc/whatsnew/3.9.rst +++ b/Doc/whatsnew/3.9.rst @@ -514,6 +514,9 @@ Build and C API Changes Extension modules without module state (``m_size <= 0``) are not affected. +* :c:func:`Py_FinalizeEx` cannot be called in a subinterpreter anymore. + (Contributed by Victor Stinner in :issue:`38865`.) + Deprecated ========== diff --git a/Misc/NEWS.d/next/C API/2020-03-18-22-52-27.bpo-38865.KeRYAu.rst b/Misc/NEWS.d/next/C API/2020-03-18-22-52-27.bpo-38865.KeRYAu.rst new file mode 100644 index 00000000000000..00152f83f18cde --- /dev/null +++ b/Misc/NEWS.d/next/C API/2020-03-18-22-52-27.bpo-38865.KeRYAu.rst @@ -0,0 +1 @@ +:c:func:`Py_FinalizeEx` cannot be called in a subinterpreter anymore. diff --git a/Programs/_testembed.c b/Programs/_testembed.c index 900a4b1d427a6b..110e2d8ae99867 100644 --- a/Programs/_testembed.c +++ b/Programs/_testembed.c @@ -1165,7 +1165,7 @@ static volatile int _audit_subinterpreter_interpreter_count = 0; static int _audit_subinterpreter_hook(const char *event, PyObject *args, void *userdata) { - printf("%s\n", event); + fprintf(stderr, "audit event: %s\n", event); if (strcmp(event, "cpython.PyInterpreterState_New") == 0) { _audit_subinterpreter_interpreter_count += 1; } @@ -1178,17 +1178,30 @@ static int test_audit_subinterpreter(void) PySys_AddAuditHook(_audit_subinterpreter_hook, NULL); _testembed_Py_Initialize(); - Py_NewInterpreter(); - Py_NewInterpreter(); - Py_NewInterpreter(); + PyThreadState *mainstate = PyThreadState_Get(); + + for (int i=0; i<3; i++) { + PyThreadState *substate = Py_NewInterpreter(); + if (substate == NULL) { + fprintf(stderr, "Py_NewInterpreter() failed\n"); + return 1; + } + Py_EndInterpreter(substate); + + /* Restore tstate after each Py_EndInterpreter() call. Otherwise the + current Python thread state is NULL and so PySys_Audit() does + nothing. */ + PyThreadState_Swap(mainstate); + } Py_Finalize(); - switch (_audit_subinterpreter_interpreter_count) { - case 3: return 0; - case 0: return -1; - default: return _audit_subinterpreter_interpreter_count; + printf("audit subinterpreter count: %i\n", + _audit_subinterpreter_interpreter_count); + if (_audit_subinterpreter_interpreter_count != 3) { + return 2; } + return 0; } typedef struct { diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index da2bb37af518c3..be4bccc8b97e7e 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1340,6 +1340,10 @@ Py_FinalizeEx(void) PyThreadState *tstate = _PyRuntimeState_GetThreadState(runtime); PyInterpreterState *interp = tstate->interp; + if (!_Py_IsMainInterpreter(tstate)) { + Py_FatalError("Py_FinalizeEx cannot be called in a subinterpreter"); + } + // Wrap up existing "threading"-module-created, non-daemon threads. wait_for_thread_shutdown(tstate);