summaryrefslogtreecommitdiffstats
path: root/Objects/exceptions.c
diff options
context:
space:
mode:
authorMark Shannon <mark@hotpy.org>2023-02-08 09:31:12 (GMT)
committerGitHub <noreply@github.com>2023-02-08 09:31:12 (GMT)
commitfeec49c40736fc05626a183a8d14c4ebbea5ae28 (patch)
tree5af6110eca8c2a21a9f699b40a87e7567c603e98 /Objects/exceptions.c
parent027adf42cd85db41fee05b0a40d89ef822876c97 (diff)
downloadcpython-feec49c40736fc05626a183a8d14c4ebbea5ae28.zip
cpython-feec49c40736fc05626a183a8d14c4ebbea5ae28.tar.gz
cpython-feec49c40736fc05626a183a8d14c4ebbea5ae28.tar.bz2
GH-101578: Normalize the current exception (GH-101607)
* Make sure that the current exception is always normalized. * Remove redundant type and traceback fields for the current exception. * Add new API functions: PyErr_GetRaisedException, PyErr_SetRaisedException * Add new API functions: PyException_GetArgs, PyException_SetArgs
Diffstat (limited to 'Objects/exceptions.c')
-rw-r--r--Objects/exceptions.c75
1 files changed, 63 insertions, 12 deletions
diff --git a/Objects/exceptions.c b/Objects/exceptions.c
index db6f7d5..976f84d 100644
--- a/Objects/exceptions.c
+++ b/Objects/exceptions.c
@@ -8,6 +8,7 @@
#include <Python.h>
#include <stdbool.h>
#include "pycore_ceval.h" // _Py_EnterRecursiveCall
+#include "pycore_pyerrors.h" // struct _PyErr_SetRaisedException
#include "pycore_exceptions.h" // struct _Py_exc_state
#include "pycore_initconfig.h"
#include "pycore_object.h"
@@ -288,13 +289,17 @@ BaseException_set_tb(PyBaseExceptionObject *self, PyObject *tb, void *Py_UNUSED(
PyErr_SetString(PyExc_TypeError, "__traceback__ may not be deleted");
return -1;
}
- else if (!(tb == Py_None || PyTraceBack_Check(tb))) {
+ if (PyTraceBack_Check(tb)) {
+ Py_XSETREF(self->traceback, Py_NewRef(tb));
+ }
+ else if (tb == Py_None) {
+ Py_CLEAR(self->traceback);
+ }
+ else {
PyErr_SetString(PyExc_TypeError,
"__traceback__ must be a traceback or None");
return -1;
}
-
- Py_XSETREF(self->traceback, Py_NewRef(tb));
return 0;
}
@@ -413,6 +418,20 @@ PyException_SetContext(PyObject *self, PyObject *context)
Py_XSETREF(_PyBaseExceptionObject_cast(self)->context, context);
}
+PyObject *
+PyException_GetArgs(PyObject *self)
+{
+ PyObject *args = _PyBaseExceptionObject_cast(self)->args;
+ return Py_NewRef(args);
+}
+
+void
+PyException_SetArgs(PyObject *self, PyObject *args)
+{
+ Py_INCREF(args);
+ Py_XSETREF(_PyBaseExceptionObject_cast(self)->args, args);
+}
+
const char *
PyExceptionClass_Name(PyObject *ob)
{
@@ -3188,20 +3207,19 @@ SimpleExtendsException(PyExc_Exception, ReferenceError,
#define MEMERRORS_SAVE 16
+static PyBaseExceptionObject last_resort_memory_error;
+
static PyObject *
-MemoryError_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+get_memory_error(int allow_allocation, PyObject *args, PyObject *kwds)
{
PyBaseExceptionObject *self;
-
- /* If this is a subclass of MemoryError, don't use the freelist
- * and just return a fresh object */
- if (type != (PyTypeObject *) PyExc_MemoryError) {
- return BaseException_new(type, args, kwds);
- }
-
struct _Py_exc_state *state = get_exc_state();
if (state->memerrors_freelist == NULL) {
- return BaseException_new(type, args, kwds);
+ if (!allow_allocation) {
+ return Py_NewRef(&last_resort_memory_error);
+ }
+ PyObject *result = BaseException_new((PyTypeObject *)PyExc_MemoryError, args, kwds);
+ return result;
}
/* Fetch object from freelist and revive it */
@@ -3221,6 +3239,35 @@ MemoryError_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return (PyObject *)self;
}
+static PyBaseExceptionObject last_resort_memory_error;
+
+static PyObject *
+MemoryError_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
+{
+ /* If this is a subclass of MemoryError, don't use the freelist
+ * and just return a fresh object */
+ if (type != (PyTypeObject *) PyExc_MemoryError) {
+ return BaseException_new(type, args, kwds);
+ }
+ return get_memory_error(1, args, kwds);
+}
+
+PyObject *
+_PyErr_NoMemory(PyThreadState *tstate)
+{
+ if (Py_IS_TYPE(PyExc_MemoryError, NULL)) {
+ /* PyErr_NoMemory() has been called before PyExc_MemoryError has been
+ initialized by _PyExc_Init() */
+ Py_FatalError("Out of memory and PyExc_MemoryError is not "
+ "initialized yet");
+ }
+ PyObject *err = get_memory_error(0, NULL, NULL);
+ if (err != NULL) {
+ _PyErr_SetRaisedException(tstate, err);
+ }
+ return NULL;
+}
+
static void
MemoryError_dealloc(PyBaseExceptionObject *self)
{
@@ -3252,6 +3299,7 @@ preallocate_memerrors(void)
/* We create enough MemoryErrors and then decref them, which will fill
up the freelist. */
int i;
+
PyObject *errors[MEMERRORS_SAVE];
for (i = 0; i < MEMERRORS_SAVE; i++) {
errors[i] = MemoryError_new((PyTypeObject *) PyExc_MemoryError,
@@ -3291,6 +3339,9 @@ static PyTypeObject _PyExc_MemoryError = {
};
PyObject *PyExc_MemoryError = (PyObject *) &_PyExc_MemoryError;
+static PyBaseExceptionObject last_resort_memory_error = {
+ _PyObject_IMMORTAL_INIT(&_PyExc_MemoryError)
+};
/*
* BufferError extends Exception