summaryrefslogtreecommitdiffstats
path: root/Python/crossinterp.c
diff options
context:
space:
mode:
authorEric Snow <ericsnowcurrently@gmail.com>2023-12-13 00:31:30 (GMT)
committerGitHub <noreply@github.com>2023-12-13 00:31:30 (GMT)
commitc6e614fd81d7dca436fe640d63a307c7dc9f6f3b (patch)
treec433141c74720a09c4e93722891d111a57ecd32a /Python/crossinterp.c
parent7e2d93f30b157e414924c32232bb748c8f66c828 (diff)
downloadcpython-c6e614fd81d7dca436fe640d63a307c7dc9f6f3b.zip
cpython-c6e614fd81d7dca436fe640d63a307c7dc9f6f3b.tar.gz
cpython-c6e614fd81d7dca436fe640d63a307c7dc9f6f3b.tar.bz2
gh-76785: Avoid Pickled TracebackException for Propagated Subinterpreter Exceptions (gh-113036)
We need the TracebackException of uncaught exceptions for a single purpose: the error display. Thus we only need to pass the formatted error display between interpreters. Passing a pickled TracebackException is overkill.
Diffstat (limited to 'Python/crossinterp.c')
-rw-r--r--Python/crossinterp.c239
1 files changed, 88 insertions, 151 deletions
diff --git a/Python/crossinterp.c b/Python/crossinterp.c
index edd61cf..c6ed7da 100644
--- a/Python/crossinterp.c
+++ b/Python/crossinterp.c
@@ -945,113 +945,105 @@ _xidregistry_fini(struct _xidregistry *registry)
/*************************/
static const char *
-_copy_raw_string(const char *str, Py_ssize_t len)
+_copy_string_obj_raw(PyObject *strobj, Py_ssize_t *p_size)
{
- size_t size = len + 1;
- if (len <= 0) {
- size = strlen(str) + 1;
- }
- char *copied = PyMem_RawMalloc(size);
- if (copied == NULL) {
- return NULL;
- }
- if (len <= 0) {
- strcpy(copied, str);
- }
- else {
- memcpy(copied, str, size);
- }
- return copied;
-}
-
-static const char *
-_copy_string_obj_raw(PyObject *strobj)
-{
- const char *str = PyUnicode_AsUTF8(strobj);
+ Py_ssize_t size = -1;
+ const char *str = PyUnicode_AsUTF8AndSize(strobj, &size);
if (str == NULL) {
return NULL;
}
- char *copied = PyMem_RawMalloc(strlen(str)+1);
+ char *copied = PyMem_RawMalloc(size+1);
if (copied == NULL) {
PyErr_NoMemory();
return NULL;
}
strcpy(copied, str);
+ if (p_size != NULL) {
+ *p_size = size;
+ }
return copied;
}
static int
-_pickle_object(PyObject *obj, const char **p_pickled, Py_ssize_t *p_len)
+_convert_exc_to_TracebackException(PyObject *exc, PyObject **p_tbexc)
{
- assert(!PyErr_Occurred());
- PyObject *picklemod = PyImport_ImportModule("_pickle");
- if (picklemod == NULL) {
- PyErr_Clear();
- picklemod = PyImport_ImportModule("pickle");
- if (picklemod == NULL) {
- return -1;
- }
+ PyObject *args = NULL;
+ PyObject *kwargs = NULL;
+ PyObject *create = NULL;
+
+ // This is inspired by _PyErr_Display().
+ PyObject *tbmod = PyImport_ImportModule("traceback");
+ if (tbmod == NULL) {
+ return -1;
}
- PyObject *dumps = PyObject_GetAttrString(picklemod, "dumps");
- Py_DECREF(picklemod);
- if (dumps == NULL) {
+ PyObject *tbexc_type = PyObject_GetAttrString(tbmod, "TracebackException");
+ Py_DECREF(tbmod);
+ if (tbexc_type == NULL) {
return -1;
}
- PyObject *pickledobj = PyObject_CallOneArg(dumps, obj);
- Py_DECREF(dumps);
- if (pickledobj == NULL) {
+ create = PyObject_GetAttrString(tbexc_type, "from_exception");
+ Py_DECREF(tbexc_type);
+ if (create == NULL) {
return -1;
}
- char *pickled = NULL;
- Py_ssize_t len = 0;
- if (PyBytes_AsStringAndSize(pickledobj, &pickled, &len) < 0) {
- Py_DECREF(pickledobj);
- return -1;
+ args = PyTuple_Pack(1, exc);
+ if (args == NULL) {
+ goto error;
}
- const char *copied = _copy_raw_string(pickled, len);
- Py_DECREF(pickledobj);
- if (copied == NULL) {
- return -1;
+
+ kwargs = PyDict_New();
+ if (kwargs == NULL) {
+ goto error;
+ }
+ if (PyDict_SetItemString(kwargs, "save_exc_type", Py_False) < 0) {
+ goto error;
+ }
+ if (PyDict_SetItemString(kwargs, "lookup_lines", Py_False) < 0) {
+ goto error;
+ }
+
+ PyObject *tbexc = PyObject_Call(create, args, kwargs);
+ Py_DECREF(args);
+ Py_DECREF(kwargs);
+ Py_DECREF(create);
+ if (tbexc == NULL) {
+ goto error;
}
- *p_pickled = copied;
- *p_len = len;
+ *p_tbexc = tbexc;
return 0;
+
+error:
+ Py_XDECREF(args);
+ Py_XDECREF(kwargs);
+ Py_XDECREF(create);
+ return -1;
}
-static int
-_unpickle_object(const char *pickled, Py_ssize_t size, PyObject **p_obj)
+
+static const char *
+_format_TracebackException(PyObject *tbexc)
{
- assert(!PyErr_Occurred());
- PyObject *picklemod = PyImport_ImportModule("_pickle");
- if (picklemod == NULL) {
- PyErr_Clear();
- picklemod = PyImport_ImportModule("pickle");
- if (picklemod == NULL) {
- return -1;
- }
- }
- PyObject *loads = PyObject_GetAttrString(picklemod, "loads");
- Py_DECREF(picklemod);
- if (loads == NULL) {
- return -1;
- }
- PyObject *pickledobj = PyBytes_FromStringAndSize(pickled, size);
- if (pickledobj == NULL) {
- Py_DECREF(loads);
- return -1;
+ PyObject *lines = PyObject_CallMethod(tbexc, "format", NULL);
+ if (lines == NULL) {
+ return NULL;
}
- PyObject *obj = PyObject_CallOneArg(loads, pickledobj);
- Py_DECREF(loads);
- Py_DECREF(pickledobj);
- if (obj == NULL) {
- return -1;
+ PyObject *formatted_obj = PyUnicode_Join(&_Py_STR(empty), lines);
+ Py_DECREF(lines);
+ if (formatted_obj == NULL) {
+ return NULL;
}
- *p_obj = obj;
- return 0;
+
+ Py_ssize_t size = -1;
+ const char *formatted = _copy_string_obj_raw(formatted_obj, &size);
+ Py_DECREF(formatted_obj);
+ // We remove trailing the newline added by TracebackException.format().
+ assert(formatted[size-1] == '\n');
+ ((char *)formatted)[size-1] = '\0';
+ return formatted;
}
@@ -1101,7 +1093,7 @@ _excinfo_init_type(struct _excinfo_type *info, PyObject *exc)
if (strobj == NULL) {
return -1;
}
- info->name = _copy_string_obj_raw(strobj);
+ info->name = _copy_string_obj_raw(strobj, NULL);
Py_DECREF(strobj);
if (info->name == NULL) {
return -1;
@@ -1112,7 +1104,7 @@ _excinfo_init_type(struct _excinfo_type *info, PyObject *exc)
if (strobj == NULL) {
return -1;
}
- info->qualname = _copy_string_obj_raw(strobj);
+ info->qualname = _copy_string_obj_raw(strobj, NULL);
Py_DECREF(strobj);
if (info->name == NULL) {
return -1;
@@ -1123,7 +1115,7 @@ _excinfo_init_type(struct _excinfo_type *info, PyObject *exc)
if (strobj == NULL) {
return -1;
}
- info->module = _copy_string_obj_raw(strobj);
+ info->module = _copy_string_obj_raw(strobj, NULL);
Py_DECREF(strobj);
if (info->name == NULL) {
return -1;
@@ -1188,8 +1180,8 @@ _PyXI_excinfo_Clear(_PyXI_excinfo *info)
if (info->msg != NULL) {
PyMem_RawFree((void *)info->msg);
}
- if (info->pickled != NULL) {
- PyMem_RawFree((void *)info->pickled);
+ if (info->errdisplay != NULL) {
+ PyMem_RawFree((void *)info->errdisplay);
}
*info = (_PyXI_excinfo){{NULL}};
}
@@ -1226,63 +1218,6 @@ _PyXI_excinfo_format(_PyXI_excinfo *info)
}
}
-static int
-_convert_exc_to_TracebackException(PyObject *exc, PyObject **p_tbexc)
-{
- PyObject *args = NULL;
- PyObject *kwargs = NULL;
- PyObject *create = NULL;
-
- // This is inspired by _PyErr_Display().
- PyObject *tbmod = PyImport_ImportModule("traceback");
- if (tbmod == NULL) {
- return -1;
- }
- PyObject *tbexc_type = PyObject_GetAttrString(tbmod, "TracebackException");
- Py_DECREF(tbmod);
- if (tbexc_type == NULL) {
- return -1;
- }
- create = PyObject_GetAttrString(tbexc_type, "from_exception");
- Py_DECREF(tbexc_type);
- if (create == NULL) {
- return -1;
- }
-
- args = PyTuple_Pack(1, exc);
- if (args == NULL) {
- goto error;
- }
-
- kwargs = PyDict_New();
- if (kwargs == NULL) {
- goto error;
- }
- if (PyDict_SetItemString(kwargs, "save_exc_type", Py_False) < 0) {
- goto error;
- }
- if (PyDict_SetItemString(kwargs, "lookup_lines", Py_False) < 0) {
- goto error;
- }
-
- PyObject *tbexc = PyObject_Call(create, args, kwargs);
- Py_DECREF(args);
- Py_DECREF(kwargs);
- Py_DECREF(create);
- if (tbexc == NULL) {
- goto error;
- }
-
- *p_tbexc = tbexc;
- return 0;
-
-error:
- Py_XDECREF(args);
- Py_XDECREF(kwargs);
- Py_XDECREF(create);
- return -1;
-}
-
static const char *
_PyXI_excinfo_InitFromException(_PyXI_excinfo *info, PyObject *exc)
{
@@ -1305,7 +1240,7 @@ _PyXI_excinfo_InitFromException(_PyXI_excinfo *info, PyObject *exc)
failure = "error while formatting exception";
goto error;
}
- info->msg = _copy_string_obj_raw(msgobj);
+ info->msg = _copy_string_obj_raw(msgobj, NULL);
Py_DECREF(msgobj);
if (info->msg == NULL) {
failure = "error while copying exception message";
@@ -1321,13 +1256,14 @@ _PyXI_excinfo_InitFromException(_PyXI_excinfo *info, PyObject *exc)
PyErr_Clear();
}
else {
- if (_pickle_object(tbexc, &info->pickled, &info->pickled_len) < 0) {
+ info->errdisplay = _format_TracebackException(tbexc);
+ Py_DECREF(tbexc);
+ if (info->errdisplay == NULL) {
#ifdef Py_DEBUG
- PyErr_FormatUnraisable("Exception ignored while pickling TracebackException");
+ PyErr_FormatUnraisable("Exception ignored while formating TracebackException");
#endif
PyErr_Clear();
}
- Py_DECREF(tbexc);
}
return NULL;
@@ -1342,8 +1278,9 @@ static void
_PyXI_excinfo_Apply(_PyXI_excinfo *info, PyObject *exctype)
{
PyObject *tbexc = NULL;
- if (info->pickled != NULL) {
- if (_unpickle_object(info->pickled, info->pickled_len, &tbexc) < 0) {
+ if (info->errdisplay != NULL) {
+ tbexc = PyUnicode_FromString(info->errdisplay);
+ if (tbexc == NULL) {
PyErr_Clear();
}
}
@@ -1354,9 +1291,9 @@ _PyXI_excinfo_Apply(_PyXI_excinfo *info, PyObject *exctype)
if (tbexc != NULL) {
PyObject *exc = PyErr_GetRaisedException();
- if (PyObject_SetAttrString(exc, "_tbexc", tbexc) < 0) {
+ if (PyObject_SetAttrString(exc, "_errdisplay", tbexc) < 0) {
#ifdef Py_DEBUG
- PyErr_FormatUnraisable("Exception ignored when setting _tbexc");
+ PyErr_FormatUnraisable("Exception ignored when setting _errdisplay");
#endif
PyErr_Clear();
}
@@ -1468,13 +1405,13 @@ _PyXI_excinfo_AsObject(_PyXI_excinfo *info)
goto error;
}
- if (info->pickled != NULL) {
- PyObject *tbexc = NULL;
- if (_unpickle_object(info->pickled, info->pickled_len, &tbexc) < 0) {
+ if (info->errdisplay != NULL) {
+ PyObject *tbexc = PyUnicode_FromString(info->errdisplay);
+ if (tbexc == NULL) {
PyErr_Clear();
}
else {
- res = PyObject_SetAttrString(ns, "tbexc", tbexc);
+ res = PyObject_SetAttrString(ns, "errdisplay", tbexc);
Py_DECREF(tbexc);
if (res < 0) {
goto error;
@@ -1646,7 +1583,7 @@ _sharednsitem_is_initialized(_PyXI_namespace_item *item)
static int
_sharednsitem_init(_PyXI_namespace_item *item, PyObject *key)
{
- item->name = _copy_string_obj_raw(key);
+ item->name = _copy_string_obj_raw(key, NULL);
if (item->name == NULL) {
assert(!_sharednsitem_is_initialized(item));
return -1;