gh-102381: don't call watcher callback with dead object (#102382)

Co-authored-by: T. Wouters <thomas@python.org>
This commit is contained in:
Carl Meyer 2023-03-07 17:10:58 -07:00 committed by GitHub
parent a33ca2ad1f
commit 1e703a4733
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 243 additions and 38 deletions

View file

@ -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();