diff options
Diffstat (limited to 'Objects/codeobject.c')
-rw-r--r-- | Objects/codeobject.c | 38 |
1 files changed, 37 insertions, 1 deletions
diff --git a/Objects/codeobject.c b/Objects/codeobject.c index 175bd57..65b1d25 100644 --- a/Objects/codeobject.c +++ b/Objects/codeobject.c @@ -11,9 +11,24 @@ #include "pycore_tuple.h" // _PyTuple_ITEMS() #include "clinic/codeobject.c.h" +static PyObject* code_repr(PyCodeObject *co); + +static const char * +code_event_name(PyCodeEvent event) { + switch (event) { + #define CASE(op) \ + case PY_CODE_EVENT_##op: \ + return "PY_CODE_EVENT_" #op; + PY_FOREACH_CODE_EVENT(CASE) + #undef CASE + } + Py_UNREACHABLE(); +} + static void notify_code_watchers(PyCodeEvent event, PyCodeObject *co) { + assert(Py_REFCNT(co) > 0); PyInterpreterState *interp = _PyInterpreterState_GET(); assert(interp->_initialized); uint8_t bits = interp->active_code_watchers; @@ -25,7 +40,21 @@ notify_code_watchers(PyCodeEvent event, PyCodeObject *co) // callback must be non-null if the watcher bit is set assert(cb != NULL); if (cb(event, co) < 0) { - PyErr_WriteUnraisable((PyObject *) co); + // Don't risk resurrecting the object if an unraisablehook keeps + // a reference; pass a string as context. + PyObject *context = NULL; + PyObject *repr = code_repr(co); + if (repr) { + context = PyUnicode_FromFormat( + "%s watcher callback for %U", + code_event_name(event), repr); + Py_DECREF(repr); + } + if (context == NULL) { + context = Py_NewRef(Py_None); + } + PyErr_WriteUnraisable(context); + Py_DECREF(context); } } i++; @@ -1667,7 +1696,14 @@ code_new_impl(PyTypeObject *type, int argcount, int posonlyargcount, static void code_dealloc(PyCodeObject *co) { + assert(Py_REFCNT(co) == 0); + Py_SET_REFCNT(co, 1); notify_code_watchers(PY_CODE_EVENT_DESTROY, co); + if (Py_REFCNT(co) > 1) { + Py_SET_REFCNT(co, Py_REFCNT(co) - 1); + return; + } + Py_SET_REFCNT(co, 0); if (co->co_extra != NULL) { PyInterpreterState *interp = _PyInterpreterState_GET(); |