diff --git a/Include/internal/pycore_crossinterp.h b/Include/internal/pycore_crossinterp.h index e91e911feb3..a7e71efc5da 100644 --- a/Include/internal/pycore_crossinterp.h +++ b/Include/internal/pycore_crossinterp.h @@ -11,6 +11,7 @@ extern "C" { #include "pycore_lock.h" // PyMutex #include "pycore_pyerrors.h" + /**************/ /* exceptions */ /**************/ @@ -163,8 +164,13 @@ struct _xi_state { // heap types _PyXIData_lookup_t data_lookup; - // heap types - PyObject *PyExc_NotShareableError; + struct xi_exceptions { + // static types + PyObject *PyExc_InterpreterError; + PyObject *PyExc_InterpreterNotFoundError; + // heap types + PyObject *PyExc_NotShareableError; + } exceptions; }; extern PyStatus _PyXI_Init(PyInterpreterState *interp); diff --git a/Modules/_interpretersmodule.c b/Modules/_interpretersmodule.c index a9a966e79e0..eb4ac9847dc 100644 --- a/Modules/_interpretersmodule.c +++ b/Modules/_interpretersmodule.c @@ -1507,7 +1507,7 @@ module_exec(PyObject *mod) goto error; } PyObject *PyExc_NotShareableError = \ - _PyInterpreterState_GetXIState(interp)->PyExc_NotShareableError; + _PyInterpreterState_GetXIState(interp)->exceptions.PyExc_NotShareableError; if (PyModule_AddType(mod, (PyTypeObject *)PyExc_NotShareableError) < 0) { goto error; } diff --git a/Python/crossinterp.c b/Python/crossinterp.c index 2daba99988c..b7aa8da8ac5 100644 --- a/Python/crossinterp.c +++ b/Python/crossinterp.c @@ -17,11 +17,11 @@ /* exceptions */ /**************/ -static int init_exceptions(PyInterpreterState *); -static void fini_exceptions(PyInterpreterState *); -static int _init_not_shareable_error_type(PyInterpreterState *); -static void _fini_not_shareable_error_type(PyInterpreterState *); -static PyObject * _get_not_shareable_error_type(PyInterpreterState *); +typedef struct xi_exceptions exceptions_t; +static int init_static_exctypes(exceptions_t *, PyInterpreterState *); +static void fini_static_exctypes(exceptions_t *, PyInterpreterState *); +static int init_heap_exctypes(exceptions_t *); +static void fini_heap_exctypes(exceptions_t *); #include "crossinterp_exceptions.h" @@ -205,7 +205,8 @@ static inline void _set_xid_lookup_failure(PyInterpreterState *interp, PyObject *obj, const char *msg) { - PyObject *exctype = _get_not_shareable_error_type(interp); + exceptions_t *state = &_PyInterpreterState_GetXIState(interp)->exceptions; + PyObject *exctype = state->PyExc_NotShareableError; assert(exctype != NULL); if (msg != NULL) { assert(obj == NULL); @@ -1605,7 +1606,9 @@ _propagate_not_shareable_error(_PyXI_session *session) return; } PyInterpreterState *interp = PyInterpreterState_Get(); - if (PyErr_ExceptionMatches(_get_not_shareable_error_type(interp))) { + exceptions_t *state = &_PyInterpreterState_GetXIState(interp)->exceptions; + assert(state->PyExc_NotShareableError != NULL); + if (PyErr_ExceptionMatches(state->PyExc_NotShareableError)) { // We want to propagate the exception directly. session->_error_override = _PyXI_ERR_NOT_SHAREABLE; session->error_override = &session->_error_override; @@ -1782,9 +1785,11 @@ _PyXI_Init(PyInterpreterState *interp) } xid_lookup_init(&_PyXI_GET_STATE(interp)->data_lookup); - // Initialize exceptions (heap types). - if (_init_not_shareable_error_type(interp) < 0) { - return _PyStatus_ERR("failed to initialize NotShareableError"); + // Initialize exceptions.(heap types). + // See _PyXI_InitTypes() for the static types. + if (init_heap_exctypes(&_PyXI_GET_STATE(interp)->exceptions) < 0) { + PyErr_PrintEx(0); + return _PyStatus_ERR("failed to initialize exceptions"); } return _PyStatus_OK(); @@ -1797,7 +1802,8 @@ void _PyXI_Fini(PyInterpreterState *interp) { // Finalize exceptions (heap types). - _fini_not_shareable_error_type(interp); + // See _PyXI_FiniTypes() for the static types. + fini_heap_exctypes(&_PyXI_GET_STATE(interp)->exceptions); // Finalize the XID lookup state (e.g. registry). xid_lookup_fini(&_PyXI_GET_STATE(interp)->data_lookup); @@ -1809,17 +1815,21 @@ _PyXI_Fini(PyInterpreterState *interp) PyStatus _PyXI_InitTypes(PyInterpreterState *interp) { - if (init_exceptions(interp) < 0) { + if (init_static_exctypes(&_PyXI_GET_STATE(interp)->exceptions, interp) < 0) { PyErr_PrintEx(0); return _PyStatus_ERR("failed to initialize an exception type"); } + // We would initialize heap types here too but that leads to ref leaks. + // Instead, we intialize them in _PyXI_Init(). return _PyStatus_OK(); } void _PyXI_FiniTypes(PyInterpreterState *interp) { - fini_exceptions(interp); + // We would finalize heap types here too but that leads to ref leaks. + // Instead, we finalize them in _PyXI_Fini(). + fini_static_exctypes(&_PyXI_GET_STATE(interp)->exceptions, interp); } diff --git a/Python/crossinterp_exceptions.h b/Python/crossinterp_exceptions.h index 278511da615..3cb45d20677 100644 --- a/Python/crossinterp_exceptions.h +++ b/Python/crossinterp_exceptions.h @@ -25,71 +25,78 @@ static PyTypeObject _PyExc_InterpreterNotFoundError = { }; PyObject *PyExc_InterpreterNotFoundError = (PyObject *)&_PyExc_InterpreterNotFoundError; -/* NotShareableError extends ValueError */ - -static int -_init_not_shareable_error_type(PyInterpreterState *interp) -{ - const char *name = "interpreters.NotShareableError"; - PyObject *base = PyExc_ValueError; - PyObject *ns = NULL; - PyObject *exctype = PyErr_NewException(name, base, ns); - if (exctype == NULL) { - return -1; - } - - _PyInterpreterState_GetXIState(interp)->PyExc_NotShareableError = exctype; - return 0; -} - -static void -_fini_not_shareable_error_type(PyInterpreterState *interp) -{ - Py_CLEAR(_PyInterpreterState_GetXIState(interp)->PyExc_NotShareableError); -} - -static PyObject * -_get_not_shareable_error_type(PyInterpreterState *interp) -{ - assert(_PyInterpreterState_GetXIState(interp)->PyExc_NotShareableError != NULL); - return _PyInterpreterState_GetXIState(interp)->PyExc_NotShareableError; -} - /* lifecycle */ static int -init_exceptions(PyInterpreterState *interp) +init_static_exctypes(exceptions_t *state, PyInterpreterState *interp) { + assert(state == &_PyXI_GET_STATE(interp)->exceptions); PyTypeObject *base = (PyTypeObject *)PyExc_Exception; - // builtin static types - + // PyExc_InterpreterError _PyExc_InterpreterError.tp_base = base; _PyExc_InterpreterError.tp_traverse = base->tp_traverse; _PyExc_InterpreterError.tp_clear = base->tp_clear; if (_PyStaticType_InitBuiltin(interp, &_PyExc_InterpreterError) < 0) { - return -1; + goto error; } + state->PyExc_InterpreterError = (PyObject *)&_PyExc_InterpreterError; + // PyExc_InterpreterNotFoundError _PyExc_InterpreterNotFoundError.tp_traverse = base->tp_traverse; _PyExc_InterpreterNotFoundError.tp_clear = base->tp_clear; if (_PyStaticType_InitBuiltin(interp, &_PyExc_InterpreterNotFoundError) < 0) { - return -1; + goto error; } - - // heap types - - // We would call _init_not_shareable_error_type() here too, - // but that leads to ref leaks + state->PyExc_InterpreterNotFoundError = + (PyObject *)&_PyExc_InterpreterNotFoundError; return 0; + +error: + fini_static_exctypes(state, interp); + return -1; } static void -fini_exceptions(PyInterpreterState *interp) +fini_static_exctypes(exceptions_t *state, PyInterpreterState *interp) { - // Likewise with _fini_not_shareable_error_type(). - _PyStaticType_FiniBuiltin(interp, &_PyExc_InterpreterNotFoundError); - _PyStaticType_FiniBuiltin(interp, &_PyExc_InterpreterError); + assert(state == &_PyXI_GET_STATE(interp)->exceptions); + if (state->PyExc_InterpreterNotFoundError != NULL) { + state->PyExc_InterpreterNotFoundError = NULL; + _PyStaticType_FiniBuiltin(interp, &_PyExc_InterpreterNotFoundError); + } + if (state->PyExc_InterpreterError != NULL) { + state->PyExc_InterpreterError = NULL; + _PyStaticType_FiniBuiltin(interp, &_PyExc_InterpreterError); + } +} + +static int +init_heap_exctypes(exceptions_t *state) +{ + PyObject *exctype; + + /* NotShareableError extends ValueError */ + const char *name = "interpreters.NotShareableError"; + PyObject *base = PyExc_ValueError; + PyObject *ns = NULL; + exctype = PyErr_NewException(name, base, ns); + if (exctype == NULL) { + goto error; + } + state->PyExc_NotShareableError = exctype; + + return 0; + +error: + fini_heap_exctypes(state); + return -1; +} + +static void +fini_heap_exctypes(exceptions_t *state) +{ + Py_CLEAR(state->PyExc_NotShareableError); }