diff options
author | Victor Stinner <vstinner@python.org> | 2022-04-21 21:04:01 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-04-21 21:04:01 (GMT) |
commit | 364ed9409269fb321dc4eafdea677c09a4bc0d8d (patch) | |
tree | f67c9f964a6641d5979c8991d11bfe365f499811 /Objects | |
parent | 8a4e519e7822d17ce062f55ba68e13bfeaf450de (diff) | |
download | cpython-364ed9409269fb321dc4eafdea677c09a4bc0d8d.zip cpython-364ed9409269fb321dc4eafdea677c09a4bc0d8d.tar.gz cpython-364ed9409269fb321dc4eafdea677c09a4bc0d8d.tar.bz2 |
gh-89373: _Py_Dealloc() checks tp_dealloc exception (#32357)
If Python is built in debug mode, _Py_Dealloc() now ensures that the
tp_dealloc function leaves the current exception unchanged.
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 } |