mirror of
https://github.com/python/cpython.git
synced 2025-11-18 01:57:37 +00:00
gh-101659: Avoid Allocation for Shared Exceptions in the _xxsubinterpreters Module (gh-102659)
https://github.com/python/cpython/issues/101659
This commit is contained in:
parent
74885a08db
commit
959ea2f9e9
1 changed files with 49 additions and 74 deletions
|
|
@ -15,14 +15,14 @@
|
||||||
#define MODULE_NAME "_xxsubinterpreters"
|
#define MODULE_NAME "_xxsubinterpreters"
|
||||||
|
|
||||||
|
|
||||||
static char *
|
static const char *
|
||||||
_copy_raw_string(PyObject *strobj)
|
_copy_raw_string(PyObject *strobj)
|
||||||
{
|
{
|
||||||
const char *str = PyUnicode_AsUTF8(strobj);
|
const char *str = PyUnicode_AsUTF8(strobj);
|
||||||
if (str == NULL) {
|
if (str == NULL) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
char *copied = PyMem_Malloc(strlen(str)+1);
|
char *copied = PyMem_RawMalloc(strlen(str)+1);
|
||||||
if (copied == NULL) {
|
if (copied == NULL) {
|
||||||
PyErr_NoMemory();
|
PyErr_NoMemory();
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
@ -128,7 +128,7 @@ clear_module_state(module_state *state)
|
||||||
/* data-sharing-specific code ***********************************************/
|
/* data-sharing-specific code ***********************************************/
|
||||||
|
|
||||||
struct _sharednsitem {
|
struct _sharednsitem {
|
||||||
char *name;
|
const char *name;
|
||||||
_PyCrossInterpreterData data;
|
_PyCrossInterpreterData data;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -152,7 +152,7 @@ static void
|
||||||
_sharednsitem_clear(struct _sharednsitem *item)
|
_sharednsitem_clear(struct _sharednsitem *item)
|
||||||
{
|
{
|
||||||
if (item->name != NULL) {
|
if (item->name != NULL) {
|
||||||
PyMem_Free(item->name);
|
PyMem_RawFree((void *)item->name);
|
||||||
item->name = NULL;
|
item->name = NULL;
|
||||||
}
|
}
|
||||||
(void)_release_xid_data(&item->data, 1);
|
(void)_release_xid_data(&item->data, 1);
|
||||||
|
|
@ -258,96 +258,74 @@ _sharedns_apply(_sharedns *shared, PyObject *ns)
|
||||||
// of the exception in the calling interpreter.
|
// of the exception in the calling interpreter.
|
||||||
|
|
||||||
typedef struct _sharedexception {
|
typedef struct _sharedexception {
|
||||||
char *name;
|
const char *name;
|
||||||
char *msg;
|
const char *msg;
|
||||||
} _sharedexception;
|
} _sharedexception;
|
||||||
|
|
||||||
static _sharedexception *
|
static const struct _sharedexception no_exception = {
|
||||||
_sharedexception_new(void)
|
.name = NULL,
|
||||||
{
|
.msg = NULL,
|
||||||
_sharedexception *err = PyMem_NEW(_sharedexception, 1);
|
};
|
||||||
if (err == NULL) {
|
|
||||||
PyErr_NoMemory();
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
err->name = NULL;
|
|
||||||
err->msg = NULL;
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
_sharedexception_clear(_sharedexception *exc)
|
_sharedexception_clear(_sharedexception *exc)
|
||||||
{
|
{
|
||||||
if (exc->name != NULL) {
|
if (exc->name != NULL) {
|
||||||
PyMem_Free(exc->name);
|
PyMem_RawFree((void *)exc->name);
|
||||||
}
|
}
|
||||||
if (exc->msg != NULL) {
|
if (exc->msg != NULL) {
|
||||||
PyMem_Free(exc->msg);
|
PyMem_RawFree((void *)exc->msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static const char *
|
||||||
_sharedexception_free(_sharedexception *exc)
|
_sharedexception_bind(PyObject *exc, _sharedexception *sharedexc)
|
||||||
{
|
|
||||||
_sharedexception_clear(exc);
|
|
||||||
PyMem_Free(exc);
|
|
||||||
}
|
|
||||||
|
|
||||||
static _sharedexception *
|
|
||||||
_sharedexception_bind(PyObject *exc)
|
|
||||||
{
|
{
|
||||||
assert(exc != NULL);
|
assert(exc != NULL);
|
||||||
char *failure = NULL;
|
const char *failure = NULL;
|
||||||
|
|
||||||
_sharedexception *err = _sharedexception_new();
|
PyObject *nameobj = PyUnicode_FromFormat("%S", Py_TYPE(exc));
|
||||||
if (err == NULL) {
|
if (nameobj == NULL) {
|
||||||
goto finally;
|
|
||||||
}
|
|
||||||
|
|
||||||
PyObject *name = PyUnicode_FromFormat("%S", Py_TYPE(exc));
|
|
||||||
if (name == NULL) {
|
|
||||||
failure = "unable to format exception type name";
|
failure = "unable to format exception type name";
|
||||||
goto finally;
|
goto error;
|
||||||
}
|
}
|
||||||
err->name = _copy_raw_string(name);
|
sharedexc->name = _copy_raw_string(nameobj);
|
||||||
Py_DECREF(name);
|
Py_DECREF(nameobj);
|
||||||
if (err->name == NULL) {
|
if (sharedexc->name == NULL) {
|
||||||
if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
|
if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
|
||||||
failure = "out of memory copying exception type name";
|
failure = "out of memory copying exception type name";
|
||||||
} else {
|
} else {
|
||||||
failure = "unable to encode and copy exception type name";
|
failure = "unable to encode and copy exception type name";
|
||||||
}
|
}
|
||||||
goto finally;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (exc != NULL) {
|
if (exc != NULL) {
|
||||||
PyObject *msg = PyUnicode_FromFormat("%S", exc);
|
PyObject *msgobj = PyUnicode_FromFormat("%S", exc);
|
||||||
if (msg == NULL) {
|
if (msgobj == NULL) {
|
||||||
failure = "unable to format exception message";
|
failure = "unable to format exception message";
|
||||||
goto finally;
|
goto error;
|
||||||
}
|
}
|
||||||
err->msg = _copy_raw_string(msg);
|
sharedexc->msg = _copy_raw_string(msgobj);
|
||||||
Py_DECREF(msg);
|
Py_DECREF(msgobj);
|
||||||
if (err->msg == NULL) {
|
if (sharedexc->msg == NULL) {
|
||||||
if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
|
if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
|
||||||
failure = "out of memory copying exception message";
|
failure = "out of memory copying exception message";
|
||||||
} else {
|
} else {
|
||||||
failure = "unable to encode and copy exception message";
|
failure = "unable to encode and copy exception message";
|
||||||
}
|
}
|
||||||
goto finally;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
finally:
|
return NULL;
|
||||||
if (failure != NULL) {
|
|
||||||
PyErr_Clear();
|
error:
|
||||||
if (err->name != NULL) {
|
assert(failure != NULL);
|
||||||
PyMem_Free(err->name);
|
PyErr_Clear();
|
||||||
err->name = NULL;
|
_sharedexception_clear(sharedexc);
|
||||||
}
|
*sharedexc = no_exception;
|
||||||
err->msg = failure;
|
return failure;
|
||||||
}
|
|
||||||
return err;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
|
@ -430,7 +408,7 @@ _ensure_not_running(PyInterpreterState *interp)
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_run_script(PyInterpreterState *interp, const char *codestr,
|
_run_script(PyInterpreterState *interp, const char *codestr,
|
||||||
_sharedns *shared, _sharedexception **exc)
|
_sharedns *shared, _sharedexception *sharedexc)
|
||||||
{
|
{
|
||||||
PyObject *excval = NULL;
|
PyObject *excval = NULL;
|
||||||
PyObject *main_mod = _PyInterpreterState_GetMainModule(interp);
|
PyObject *main_mod = _PyInterpreterState_GetMainModule(interp);
|
||||||
|
|
@ -462,22 +440,20 @@ _run_script(PyInterpreterState *interp, const char *codestr,
|
||||||
Py_DECREF(result); // We throw away the result.
|
Py_DECREF(result); // We throw away the result.
|
||||||
}
|
}
|
||||||
|
|
||||||
*exc = NULL;
|
*sharedexc = no_exception;
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
excval = PyErr_GetRaisedException();
|
excval = PyErr_GetRaisedException();
|
||||||
_sharedexception *sharedexc = _sharedexception_bind(excval);
|
const char *failure = _sharedexception_bind(excval, sharedexc);
|
||||||
Py_XDECREF(excval);
|
if (failure != NULL) {
|
||||||
if (sharedexc == NULL) {
|
fprintf(stderr,
|
||||||
fprintf(stderr, "RunFailedError: script raised an uncaught exception");
|
"RunFailedError: script raised an uncaught exception (%s)",
|
||||||
|
failure);
|
||||||
PyErr_Clear();
|
PyErr_Clear();
|
||||||
sharedexc = NULL;
|
|
||||||
}
|
}
|
||||||
else {
|
Py_XDECREF(excval);
|
||||||
assert(!PyErr_Occurred());
|
assert(!PyErr_Occurred());
|
||||||
}
|
|
||||||
*exc = sharedexc;
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -505,7 +481,7 @@ _run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the script.
|
// Run the script.
|
||||||
_sharedexception *exc = NULL;
|
_sharedexception exc;
|
||||||
int result = _run_script(interp, codestr, shared, &exc);
|
int result = _run_script(interp, codestr, shared, &exc);
|
||||||
|
|
||||||
// Switch back.
|
// Switch back.
|
||||||
|
|
@ -514,10 +490,9 @@ _run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Propagate any exception out to the caller.
|
// Propagate any exception out to the caller.
|
||||||
if (exc != NULL) {
|
if (exc.name != NULL) {
|
||||||
assert(state != NULL);
|
assert(state != NULL);
|
||||||
_sharedexception_apply(exc, state->RunFailedError);
|
_sharedexception_apply(&exc, state->RunFailedError);
|
||||||
_sharedexception_free(exc);
|
|
||||||
}
|
}
|
||||||
else if (result != 0) {
|
else if (result != 0) {
|
||||||
// We were unable to allocate a shared exception.
|
// We were unable to allocate a shared exception.
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue