gh-98608: Stop Treating All Errors from _Py_NewInterpreterFromConfig() as Fatal (gh-102657)

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
This commit is contained in:
Eric Snow 2023-03-21 10:49:12 -06:00 committed by GitHub
parent 910a64e301
commit 3bb475662b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 27 additions and 17 deletions

View file

@ -25,6 +25,7 @@ PyAPI_FUNC(PyStatus) PyStatus_Exit(int exitcode);
PyAPI_FUNC(int) PyStatus_IsError(PyStatus err); PyAPI_FUNC(int) PyStatus_IsError(PyStatus err);
PyAPI_FUNC(int) PyStatus_IsExit(PyStatus err); PyAPI_FUNC(int) PyStatus_IsExit(PyStatus err);
PyAPI_FUNC(int) PyStatus_Exception(PyStatus err); PyAPI_FUNC(int) PyStatus_Exception(PyStatus err);
PyAPI_FUNC(PyObject *) _PyErr_SetFromPyStatus(PyStatus status);
/* --- PyWideStringList ------------------------------------------------ */ /* --- PyWideStringList ------------------------------------------------ */

View file

@ -62,5 +62,6 @@ PyAPI_FUNC(int) _Py_CoerceLegacyLocale(int warn);
PyAPI_FUNC(int) _Py_LegacyLocaleDetected(int warn); PyAPI_FUNC(int) _Py_LegacyLocaleDetected(int warn);
PyAPI_FUNC(char *) _Py_SetLocaleFromEnv(int category); PyAPI_FUNC(char *) _Py_SetLocaleFromEnv(int category);
PyAPI_FUNC(PyThreadState *) _Py_NewInterpreterFromConfig( PyAPI_FUNC(PyStatus) _Py_NewInterpreterFromConfig(
const _PyInterpreterConfig *); PyThreadState **tstate_p,
const _PyInterpreterConfig *config);

View file

@ -44,8 +44,6 @@ struct pyruntimestate;
#define _PyStatus_UPDATE_FUNC(err) \ #define _PyStatus_UPDATE_FUNC(err) \
do { (err).func = _PyStatus_GET_FUNC(); } while (0) do { (err).func = _PyStatus_GET_FUNC(); } while (0)
PyObject* _PyErr_SetFromPyStatus(PyStatus status);
/* --- PyWideStringList ------------------------------------------------ */ /* --- PyWideStringList ------------------------------------------------ */
#define _PyWideStringList_INIT (PyWideStringList){.length = 0, .items = NULL} #define _PyWideStringList_INIT (PyWideStringList){.length = 0, .items = NULL}

View file

@ -1538,15 +1538,19 @@ run_in_subinterp_with_config(PyObject *self, PyObject *args, PyObject *kwargs)
.allow_daemon_threads = allow_daemon_threads, .allow_daemon_threads = allow_daemon_threads,
.check_multi_interp_extensions = check_multi_interp_extensions, .check_multi_interp_extensions = check_multi_interp_extensions,
}; };
substate = _Py_NewInterpreterFromConfig(&config); PyStatus status = _Py_NewInterpreterFromConfig(&substate, &config);
if (substate == NULL) { if (PyStatus_Exception(status)) {
/* Since no new thread state was created, there is no exception to /* Since no new thread state was created, there is no exception to
propagate; raise a fresh one after swapping in the old thread propagate; raise a fresh one after swapping in the old thread
state. */ state. */
PyThreadState_Swap(mainstate); PyThreadState_Swap(mainstate);
_PyErr_SetFromPyStatus(status);
PyObject *exc = PyErr_GetRaisedException();
PyErr_SetString(PyExc_RuntimeError, "sub-interpreter creation failed"); PyErr_SetString(PyExc_RuntimeError, "sub-interpreter creation failed");
_PyErr_ChainExceptions1(exc);
return NULL; return NULL;
} }
assert(substate != NULL);
r = PyRun_SimpleStringFlags(code, &cflags); r = PyRun_SimpleStringFlags(code, &cflags);
Py_EndInterpreter(substate); Py_EndInterpreter(substate);

View file

@ -526,15 +526,20 @@ interp_create(PyObject *self, PyObject *args, PyObject *kwds)
? (_PyInterpreterConfig)_PyInterpreterConfig_INIT ? (_PyInterpreterConfig)_PyInterpreterConfig_INIT
: (_PyInterpreterConfig)_PyInterpreterConfig_LEGACY_INIT; : (_PyInterpreterConfig)_PyInterpreterConfig_LEGACY_INIT;
// XXX Possible GILState issues? // XXX Possible GILState issues?
PyThreadState *tstate = _Py_NewInterpreterFromConfig(&config); PyThreadState *tstate = NULL;
PyStatus status = _Py_NewInterpreterFromConfig(&tstate, &config);
PyThreadState_Swap(save_tstate); PyThreadState_Swap(save_tstate);
if (tstate == NULL) { if (PyStatus_Exception(status)) {
/* Since no new thread state was created, there is no exception to /* Since no new thread state was created, there is no exception to
propagate; raise a fresh one after swapping in the old thread propagate; raise a fresh one after swapping in the old thread
state. */ state. */
_PyErr_SetFromPyStatus(status);
PyObject *exc = PyErr_GetRaisedException();
PyErr_SetString(PyExc_RuntimeError, "interpreter creation failed"); PyErr_SetString(PyExc_RuntimeError, "interpreter creation failed");
_PyErr_ChainExceptions1(exc);
return NULL; return NULL;
} }
assert(tstate != NULL);
PyInterpreterState *interp = PyThreadState_GetInterpreter(tstate); PyInterpreterState *interp = PyThreadState_GetInterpreter(tstate);
PyObject *idobj = _PyInterpreterState_GetIDObject(interp); PyObject *idobj = _PyInterpreterState_GetIDObject(interp);
if (idobj == NULL) { if (idobj == NULL) {

View file

@ -2065,22 +2065,23 @@ error:
return status; return status;
} }
PyThreadState * PyStatus
_Py_NewInterpreterFromConfig(const _PyInterpreterConfig *config) _Py_NewInterpreterFromConfig(PyThreadState **tstate_p,
const _PyInterpreterConfig *config)
{ {
PyThreadState *tstate = NULL; return new_interpreter(tstate_p, config);
PyStatus status = new_interpreter(&tstate, config);
if (_PyStatus_EXCEPTION(status)) {
Py_ExitStatusException(status);
}
return tstate;
} }
PyThreadState * PyThreadState *
Py_NewInterpreter(void) Py_NewInterpreter(void)
{ {
PyThreadState *tstate = NULL;
const _PyInterpreterConfig config = _PyInterpreterConfig_LEGACY_INIT; 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 /* Delete an interpreter and its last thread. This requires that the