diff options
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/object.c | 36 |
1 files changed, 35 insertions, 1 deletions
diff --git a/Objects/object.c b/Objects/object.c index 29880f6..1144719 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -2354,11 +2354,45 @@ _PyObject_AssertFailed(PyObject *obj, const char *expr, const char *msg, void _Py_Dealloc(PyObject *op) { - destructor dealloc = Py_TYPE(op)->tp_dealloc; + PyTypeObject *type = Py_TYPE(op); + destructor dealloc = type->tp_dealloc; +#ifdef Py_DEBUG + PyThreadState *tstate = _PyThreadState_GET(); + PyObject *old_exc_type = tstate->curexc_type; + // Keep the old exception type alive to prevent undefined behavior + // on (tstate->curexc_type != old_exc_type) below + Py_XINCREF(old_exc_type); + // Make sure that type->tp_name remains valid + Py_INCREF(type); +#endif + #ifdef Py_TRACE_REFS _Py_ForgetReference(op); #endif (*dealloc)(op); + +#ifdef Py_DEBUG + // gh-89373: The tp_dealloc function must leave the current exception + // unchanged. + if (tstate->curexc_type != old_exc_type) { + const char *err; + if (old_exc_type == NULL) { + err = "Deallocator of type '%s' raised an exception"; + } + else if (tstate->curexc_type == NULL) { + err = "Deallocator of type '%s' cleared the current exception"; + } + else { + // It can happen if dealloc() normalized the current exception. + // A deallocator function must not change the current exception, + // not even normalize it. + err = "Deallocator of type '%s' overrode the current exception"; + } + _Py_FatalErrorFormat(__func__, err, type->tp_name); + } + Py_XDECREF(old_exc_type); + Py_DECREF(type); +#endif } |