Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

gh-101659: Avoid Allocation for Shared Exceptions in the _xxsubinterpreters Module #102659

Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
123 changes: 49 additions & 74 deletions Modules/_xxsubinterpretersmodule.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,14 @@
#define MODULE_NAME "_xxsubinterpreters"


static char *
static const char *
_copy_raw_string(PyObject *strobj)
{
const char *str = PyUnicode_AsUTF8(strobj);
if (str == NULL) {
return NULL;
}
char *copied = PyMem_Malloc(strlen(str)+1);
char *copied = PyMem_RawMalloc(strlen(str)+1);
if (copied == NULL) {
PyErr_NoMemory();
return NULL;
Expand Down Expand Up @@ -128,7 +128,7 @@ clear_module_state(module_state *state)
/* data-sharing-specific code ***********************************************/

struct _sharednsitem {
char *name;
const char *name;
_PyCrossInterpreterData data;
};

Expand All @@ -152,7 +152,7 @@ static void
_sharednsitem_clear(struct _sharednsitem *item)
{
if (item->name != NULL) {
PyMem_Free(item->name);
PyMem_RawFree((void *)item->name);
item->name = NULL;
}
(void)_release_xid_data(&item->data, 1);
Expand Down Expand Up @@ -258,96 +258,74 @@ _sharedns_apply(_sharedns *shared, PyObject *ns)
// of the exception in the calling interpreter.

typedef struct _sharedexception {
char *name;
char *msg;
const char *name;
const char *msg;
} _sharedexception;

static _sharedexception *
_sharedexception_new(void)
{
_sharedexception *err = PyMem_NEW(_sharedexception, 1);
if (err == NULL) {
PyErr_NoMemory();
return NULL;
}
err->name = NULL;
err->msg = NULL;
return err;
}
static const struct _sharedexception no_exception = {
.name = NULL,
.msg = NULL,
};

static void
_sharedexception_clear(_sharedexception *exc)
{
if (exc->name != NULL) {
PyMem_Free(exc->name);
PyMem_RawFree((void *)exc->name);
}
if (exc->msg != NULL) {
PyMem_Free(exc->msg);
PyMem_RawFree((void *)exc->msg);
}
}

static void
_sharedexception_free(_sharedexception *exc)
{
_sharedexception_clear(exc);
PyMem_Free(exc);
}

static _sharedexception *
_sharedexception_bind(PyObject *exc)
static const char *
_sharedexception_bind(PyObject *exc, _sharedexception *sharedexc)
{
assert(exc != NULL);
char *failure = NULL;

_sharedexception *err = _sharedexception_new();
if (err == NULL) {
goto finally;
}
const char *failure = NULL;

PyObject *name = PyUnicode_FromFormat("%S", Py_TYPE(exc));
if (name == NULL) {
PyObject *nameobj = PyUnicode_FromFormat("%S", Py_TYPE(exc));
if (nameobj == NULL) {
failure = "unable to format exception type name";
goto finally;
goto error;
}
err->name = _copy_raw_string(name);
Py_DECREF(name);
if (err->name == NULL) {
sharedexc->name = _copy_raw_string(nameobj);
Py_DECREF(nameobj);
if (sharedexc->name == NULL) {
if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
failure = "out of memory copying exception type name";
} else {
failure = "unable to encode and copy exception type name";
}
goto finally;
goto error;
}

if (exc != NULL) {
PyObject *msg = PyUnicode_FromFormat("%S", exc);
if (msg == NULL) {
PyObject *msgobj = PyUnicode_FromFormat("%S", exc);
if (msgobj == NULL) {
failure = "unable to format exception message";
goto finally;
goto error;
}
err->msg = _copy_raw_string(msg);
Py_DECREF(msg);
if (err->msg == NULL) {
sharedexc->msg = _copy_raw_string(msgobj);
Py_DECREF(msgobj);
if (sharedexc->msg == NULL) {
if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
failure = "out of memory copying exception message";
} else {
failure = "unable to encode and copy exception message";
}
goto finally;
goto error;
}
}

finally:
if (failure != NULL) {
PyErr_Clear();
if (err->name != NULL) {
PyMem_Free(err->name);
err->name = NULL;
}
err->msg = failure;
}
return err;
return NULL;

error:
assert(failure != NULL);
PyErr_Clear();
_sharedexception_clear(sharedexc);
*sharedexc = no_exception;
return failure;
}

static void
Expand Down Expand Up @@ -430,7 +408,7 @@ _ensure_not_running(PyInterpreterState *interp)

static int
_run_script(PyInterpreterState *interp, const char *codestr,
_sharedns *shared, _sharedexception **exc)
_sharedns *shared, _sharedexception *sharedexc)
{
PyObject *excval = NULL;
PyObject *main_mod = _PyInterpreterState_GetMainModule(interp);
Expand Down Expand Up @@ -462,22 +440,20 @@ _run_script(PyInterpreterState *interp, const char *codestr,
Py_DECREF(result); // We throw away the result.
}

*exc = NULL;
*sharedexc = no_exception;
return 0;

error:
excval = PyErr_GetRaisedException();
_sharedexception *sharedexc = _sharedexception_bind(excval);
Py_XDECREF(excval);
if (sharedexc == NULL) {
fprintf(stderr, "RunFailedError: script raised an uncaught exception");
const char *failure = _sharedexception_bind(excval, sharedexc);
if (failure != NULL) {
fprintf(stderr,
"RunFailedError: script raised an uncaught exception (%s)",
failure);
PyErr_Clear();
sharedexc = NULL;
}
else {
assert(!PyErr_Occurred());
}
*exc = sharedexc;
Py_XDECREF(excval);
assert(!PyErr_Occurred());
return -1;
}

Expand Down Expand Up @@ -505,7 +481,7 @@ _run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp,
}

// Run the script.
_sharedexception *exc = NULL;
_sharedexception exc;
int result = _run_script(interp, codestr, shared, &exc);

// Switch back.
Expand All @@ -514,10 +490,9 @@ _run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp,
}

// Propagate any exception out to the caller.
if (exc != NULL) {
if (exc.name != NULL) {
assert(state != NULL);
_sharedexception_apply(exc, state->RunFailedError);
_sharedexception_free(exc);
_sharedexception_apply(&exc, state->RunFailedError);
}
else if (result != 0) {
// We were unable to allocate a shared exception.
Expand Down