mirror of
https://github.com/python/cpython.git
synced 2025-08-31 05:58:33 +00:00
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:
parent
910a64e301
commit
3bb475662b
6 changed files with 27 additions and 17 deletions
|
@ -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 ------------------------------------------------ */
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue