Skip to content

Commit 959ea2f

Browse files
gh-101659: Avoid Allocation for Shared Exceptions in the _xxsubinterpreters Module (gh-102659)
#101659
1 parent 74885a0 commit 959ea2f

File tree

1 file changed

+49
-74
lines changed

1 file changed

+49
-74
lines changed

Diff for: Modules/_xxsubinterpretersmodule.c

+49-74
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,14 @@
1515
#define MODULE_NAME "_xxsubinterpreters"
1616

1717

18-
static char *
18+
static const char *
1919
_copy_raw_string(PyObject *strobj)
2020
{
2121
const char *str = PyUnicode_AsUTF8(strobj);
2222
if (str == NULL) {
2323
return NULL;
2424
}
25-
char *copied = PyMem_Malloc(strlen(str)+1);
25+
char *copied = PyMem_RawMalloc(strlen(str)+1);
2626
if (copied == NULL) {
2727
PyErr_NoMemory();
2828
return NULL;
@@ -128,7 +128,7 @@ clear_module_state(module_state *state)
128128
/* data-sharing-specific code ***********************************************/
129129

130130
struct _sharednsitem {
131-
char *name;
131+
const char *name;
132132
_PyCrossInterpreterData data;
133133
};
134134

@@ -152,7 +152,7 @@ static void
152152
_sharednsitem_clear(struct _sharednsitem *item)
153153
{
154154
if (item->name != NULL) {
155-
PyMem_Free(item->name);
155+
PyMem_RawFree((void *)item->name);
156156
item->name = NULL;
157157
}
158158
(void)_release_xid_data(&item->data, 1);
@@ -258,96 +258,74 @@ _sharedns_apply(_sharedns *shared, PyObject *ns)
258258
// of the exception in the calling interpreter.
259259

260260
typedef struct _sharedexception {
261-
char *name;
262-
char *msg;
261+
const char *name;
262+
const char *msg;
263263
} _sharedexception;
264264

265-
static _sharedexception *
266-
_sharedexception_new(void)
267-
{
268-
_sharedexception *err = PyMem_NEW(_sharedexception, 1);
269-
if (err == NULL) {
270-
PyErr_NoMemory();
271-
return NULL;
272-
}
273-
err->name = NULL;
274-
err->msg = NULL;
275-
return err;
276-
}
265+
static const struct _sharedexception no_exception = {
266+
.name = NULL,
267+
.msg = NULL,
268+
};
277269

278270
static void
279271
_sharedexception_clear(_sharedexception *exc)
280272
{
281273
if (exc->name != NULL) {
282-
PyMem_Free(exc->name);
274+
PyMem_RawFree((void *)exc->name);
283275
}
284276
if (exc->msg != NULL) {
285-
PyMem_Free(exc->msg);
277+
PyMem_RawFree((void *)exc->msg);
286278
}
287279
}
288280

289-
static void
290-
_sharedexception_free(_sharedexception *exc)
291-
{
292-
_sharedexception_clear(exc);
293-
PyMem_Free(exc);
294-
}
295-
296-
static _sharedexception *
297-
_sharedexception_bind(PyObject *exc)
281+
static const char *
282+
_sharedexception_bind(PyObject *exc, _sharedexception *sharedexc)
298283
{
299284
assert(exc != NULL);
300-
char *failure = NULL;
301-
302-
_sharedexception *err = _sharedexception_new();
303-
if (err == NULL) {
304-
goto finally;
305-
}
285+
const char *failure = NULL;
306286

307-
PyObject *name = PyUnicode_FromFormat("%S", Py_TYPE(exc));
308-
if (name == NULL) {
287+
PyObject *nameobj = PyUnicode_FromFormat("%S", Py_TYPE(exc));
288+
if (nameobj == NULL) {
309289
failure = "unable to format exception type name";
310-
goto finally;
290+
goto error;
311291
}
312-
err->name = _copy_raw_string(name);
313-
Py_DECREF(name);
314-
if (err->name == NULL) {
292+
sharedexc->name = _copy_raw_string(nameobj);
293+
Py_DECREF(nameobj);
294+
if (sharedexc->name == NULL) {
315295
if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
316296
failure = "out of memory copying exception type name";
317297
} else {
318298
failure = "unable to encode and copy exception type name";
319299
}
320-
goto finally;
300+
goto error;
321301
}
322302

323303
if (exc != NULL) {
324-
PyObject *msg = PyUnicode_FromFormat("%S", exc);
325-
if (msg == NULL) {
304+
PyObject *msgobj = PyUnicode_FromFormat("%S", exc);
305+
if (msgobj == NULL) {
326306
failure = "unable to format exception message";
327-
goto finally;
307+
goto error;
328308
}
329-
err->msg = _copy_raw_string(msg);
330-
Py_DECREF(msg);
331-
if (err->msg == NULL) {
309+
sharedexc->msg = _copy_raw_string(msgobj);
310+
Py_DECREF(msgobj);
311+
if (sharedexc->msg == NULL) {
332312
if (PyErr_ExceptionMatches(PyExc_MemoryError)) {
333313
failure = "out of memory copying exception message";
334314
} else {
335315
failure = "unable to encode and copy exception message";
336316
}
337-
goto finally;
317+
goto error;
338318
}
339319
}
340320

341-
finally:
342-
if (failure != NULL) {
343-
PyErr_Clear();
344-
if (err->name != NULL) {
345-
PyMem_Free(err->name);
346-
err->name = NULL;
347-
}
348-
err->msg = failure;
349-
}
350-
return err;
321+
return NULL;
322+
323+
error:
324+
assert(failure != NULL);
325+
PyErr_Clear();
326+
_sharedexception_clear(sharedexc);
327+
*sharedexc = no_exception;
328+
return failure;
351329
}
352330

353331
static void
@@ -430,7 +408,7 @@ _ensure_not_running(PyInterpreterState *interp)
430408

431409
static int
432410
_run_script(PyInterpreterState *interp, const char *codestr,
433-
_sharedns *shared, _sharedexception **exc)
411+
_sharedns *shared, _sharedexception *sharedexc)
434412
{
435413
PyObject *excval = NULL;
436414
PyObject *main_mod = _PyInterpreterState_GetMainModule(interp);
@@ -462,22 +440,20 @@ _run_script(PyInterpreterState *interp, const char *codestr,
462440
Py_DECREF(result); // We throw away the result.
463441
}
464442

465-
*exc = NULL;
443+
*sharedexc = no_exception;
466444
return 0;
467445

468446
error:
469447
excval = PyErr_GetRaisedException();
470-
_sharedexception *sharedexc = _sharedexception_bind(excval);
471-
Py_XDECREF(excval);
472-
if (sharedexc == NULL) {
473-
fprintf(stderr, "RunFailedError: script raised an uncaught exception");
448+
const char *failure = _sharedexception_bind(excval, sharedexc);
449+
if (failure != NULL) {
450+
fprintf(stderr,
451+
"RunFailedError: script raised an uncaught exception (%s)",
452+
failure);
474453
PyErr_Clear();
475-
sharedexc = NULL;
476-
}
477-
else {
478-
assert(!PyErr_Occurred());
479454
}
480-
*exc = sharedexc;
455+
Py_XDECREF(excval);
456+
assert(!PyErr_Occurred());
481457
return -1;
482458
}
483459

@@ -505,7 +481,7 @@ _run_script_in_interpreter(PyObject *mod, PyInterpreterState *interp,
505481
}
506482

507483
// Run the script.
508-
_sharedexception *exc = NULL;
484+
_sharedexception exc;
509485
int result = _run_script(interp, codestr, shared, &exc);
510486

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

516492
// Propagate any exception out to the caller.
517-
if (exc != NULL) {
493+
if (exc.name != NULL) {
518494
assert(state != NULL);
519-
_sharedexception_apply(exc, state->RunFailedError);
520-
_sharedexception_free(exc);
495+
_sharedexception_apply(&exc, state->RunFailedError);
521496
}
522497
else if (result != 0) {
523498
// We were unable to allocate a shared exception.

0 commit comments

Comments
 (0)