Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] bpo-38865: Py_FinalizeEx() cannot be called in a subinterpreter #19063

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Doc/c-api/init.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down
3 changes: 3 additions & 0 deletions Doc/whatsnew/3.9.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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
==========
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
:c:func:`Py_FinalizeEx` cannot be called in a subinterpreter anymore.
29 changes: 21 additions & 8 deletions Programs/_testembed.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand All @@ -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 {
Expand Down
4 changes: 4 additions & 0 deletions Python/pylifecycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down