]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-98608: Stop Treating All Errors from _Py_NewInterpreterFromConfig() as Fatal ...
authorEric Snow <ericsnowcurrently@gmail.com>
Tue, 21 Mar 2023 16:49:12 +0000 (10:49 -0600)
committerGitHub <noreply@github.com>
Tue, 21 Mar 2023 16:49:12 +0000 (10:49 -0600)
Prior to this change, errors in _Py_NewInterpreterFromConfig() were always fatal.  Instead, callers should be able to handle such errors and keep going.  That's what this change supports.  (This was an oversight in the original implementation of _Py_NewInterpreterFromConfig().)  Note that the existing [fatal] behavior of the public Py_NewInterpreter() is preserved.

https://github.com/python/cpython/issues/98608

Include/cpython/initconfig.h
Include/cpython/pylifecycle.h
Include/internal/pycore_initconfig.h
Modules/_testcapimodule.c
Modules/_xxsubinterpretersmodule.c
Python/pylifecycle.c

index a070fa9ff3a038aeeaa3a0ca2044b0f1f957eb97..8bc681b1a93f5c410e6d3c2761fb470ee2e85a05 100644 (file)
@@ -25,6 +25,7 @@ PyAPI_FUNC(PyStatus) PyStatus_Exit(int exitcode);
 PyAPI_FUNC(int) PyStatus_IsError(PyStatus err);
 PyAPI_FUNC(int) PyStatus_IsExit(PyStatus err);
 PyAPI_FUNC(int) PyStatus_Exception(PyStatus err);
+PyAPI_FUNC(PyObject *) _PyErr_SetFromPyStatus(PyStatus status);
 
 /* --- PyWideStringList ------------------------------------------------ */
 
index e1f83acbffc360293c58818c9a3a8dd9e1ebe1bb..821b169d7a1759dd83ea3ee5d50c82e005856c84 100644 (file)
@@ -62,5 +62,6 @@ PyAPI_FUNC(int) _Py_CoerceLegacyLocale(int warn);
 PyAPI_FUNC(int) _Py_LegacyLocaleDetected(int warn);
 PyAPI_FUNC(char *) _Py_SetLocaleFromEnv(int category);
 
-PyAPI_FUNC(PyThreadState *) _Py_NewInterpreterFromConfig(
-    const _PyInterpreterConfig *);
+PyAPI_FUNC(PyStatus) _Py_NewInterpreterFromConfig(
+    PyThreadState **tstate_p,
+    const _PyInterpreterConfig *config);
index 69f88d7d1d46b8e4df48e5ad9ca412cce8b68773..4cbd14a61d4545eeb1fbf46462f0636ee98ee279 100644 (file)
@@ -44,8 +44,6 @@ struct pyruntimestate;
 #define _PyStatus_UPDATE_FUNC(err) \
     do { (err).func = _PyStatus_GET_FUNC(); } while (0)
 
-PyObject* _PyErr_SetFromPyStatus(PyStatus status);
-
 /* --- PyWideStringList ------------------------------------------------ */
 
 #define _PyWideStringList_INIT (PyWideStringList){.length = 0, .items = NULL}
index f45d0312e94411933c0a092a7c8356a5f3d7ae87..e2ebab5c5b48497c7c0bbb2afeffbfcf9be11918 100644 (file)
@@ -1538,15 +1538,19 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs)
         .allow_daemon_threads = allow_daemon_threads,
         .check_multi_interp_extensions = check_multi_interp_extensions,
     };
-    substate = _Py_NewInterpreterFromConfig(&config);
-    if (substate == NULL) {
+    PyStatus status = _Py_NewInterpreterFromConfig(&substate, &config);
+    if (PyStatus_Exception(status)) {
         /* Since no new thread state was created, there is no exception to
            propagate; raise a fresh one after swapping in the old thread
            state. */
         PyThreadState_Swap(mainstate);
+        _PyErr_SetFromPyStatus(status);
+        PyObject *exc = PyErr_GetRaisedException();
         PyErr_SetString(PyExc_RuntimeError, "sub-interpreter creation failed");
+        _PyErr_ChainExceptions1(exc);
         return NULL;
     }
+    assert(substate != NULL);
     r = PyRun_SimpleStringFlags(code, &cflags);
     Py_EndInterpreter(substate);
 
index 76fb87fa3a34e1f6af780f158ae5db806e0c1987..9648f080cd756ca8ab73c69be8e3f14d054c034e 100644 (file)
@@ -526,15 +526,20 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds)
         ? (_PyInterpreterConfig)_PyInterpreterConfig_INIT
         : (_PyInterpreterConfig)_PyInterpreterConfig_LEGACY_INIT;
     // XXX Possible GILState issues?
-    PyThreadState *tstate = _Py_NewInterpreterFromConfig(&config);
+    PyThreadState *tstate = NULL;
+    PyStatus status = _Py_NewInterpreterFromConfig(&tstate, &config);
     PyThreadState_Swap(save_tstate);
-    if (tstate == NULL) {
+    if (PyStatus_Exception(status)) {
         /* Since no new thread state was created, there is no exception to
            propagate; raise a fresh one after swapping in the old thread
            state. */
+        _PyErr_SetFromPyStatus(status);
+        PyObject *exc = PyErr_GetRaisedException();
         PyErr_SetString(PyExc_RuntimeError, "interpreter creation failed");
+        _PyErr_ChainExceptions1(exc);
         return NULL;
     }
+    assert(tstate != NULL);
     PyInterpreterState *interp = PyThreadState_GetInterpreter(tstate);
     PyObject *idobj = _PyInterpreterState_GetIDObject(interp);
     if (idobj == NULL) {
index 731f340001b4e03c569d2dda7a09cd9c1c342d0f..8b58a14c693f22f96f025667106378fc14b505e3 100644 (file)
@@ -2065,22 +2065,23 @@ error:
     return status;
 }
 
-PyThreadState *
-_Py_NewInterpreterFromConfig(const _PyInterpreterConfig *config)
+PyStatus
+_Py_NewInterpreterFromConfig(PyThreadState **tstate_p,
+                             const _PyInterpreterConfig *config)
 {
-    PyThreadState *tstate = NULL;
-    PyStatus status = new_interpreter(&tstate, config);
-    if (_PyStatus_EXCEPTION(status)) {
-        Py_ExitStatusException(status);
-    }
-    return tstate;
+    return new_interpreter(tstate_p, config);
 }
 
 PyThreadState *
 Py_NewInterpreter(void)
 {
+    PyThreadState *tstate = NULL;
     const _PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT;
-    return _Py_NewInterpreterFromConfig(&config);
+    PyStatus status = _Py_NewInterpreterFromConfig(&tstate, &config);
+    if (_PyStatus_EXCEPTION(status)) {
+        Py_ExitStatusException(status);
+    }
+    return tstate;
 }
 
 /* Delete an interpreter and its last thread.  This requires that the