mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
gh-102381: don't call watcher callback with dead object (#102382)
Co-authored-by: T. Wouters <thomas@python.org>
This commit is contained in:
parent
a33ca2ad1f
commit
1e703a4733
12 changed files with 243 additions and 38 deletions
|
@ -8,6 +8,20 @@
|
|||
#include "pycore_pyerrors.h" // _PyErr_Occurred()
|
||||
#include "structmember.h" // PyMemberDef
|
||||
|
||||
static PyObject* func_repr(PyFunctionObject *op);
|
||||
|
||||
static const char *
|
||||
func_event_name(PyFunction_WatchEvent event) {
|
||||
switch (event) {
|
||||
#define CASE(op) \
|
||||
case PyFunction_EVENT_##op: \
|
||||
return "PyFunction_EVENT_" #op;
|
||||
PY_FOREACH_FUNC_EVENT(CASE)
|
||||
#undef CASE
|
||||
}
|
||||
Py_UNREACHABLE();
|
||||
}
|
||||
|
||||
static void
|
||||
notify_func_watchers(PyInterpreterState *interp, PyFunction_WatchEvent event,
|
||||
PyFunctionObject *func, PyObject *new_value)
|
||||
|
@ -21,7 +35,21 @@ notify_func_watchers(PyInterpreterState *interp, PyFunction_WatchEvent event,
|
|||
// callback must be non-null if the watcher bit is set
|
||||
assert(cb != NULL);
|
||||
if (cb(event, func, new_value) < 0) {
|
||||
PyErr_WriteUnraisable((PyObject *) func);
|
||||
// Don't risk resurrecting the func if an unraisablehook keeps a
|
||||
// reference; pass a string as context.
|
||||
PyObject *context = NULL;
|
||||
PyObject *repr = func_repr(func);
|
||||
if (repr != NULL) {
|
||||
context = PyUnicode_FromFormat(
|
||||
"%s watcher callback for %U",
|
||||
func_event_name(event), repr);
|
||||
Py_DECREF(repr);
|
||||
}
|
||||
if (context == NULL) {
|
||||
context = Py_NewRef(Py_None);
|
||||
}
|
||||
PyErr_WriteUnraisable(context);
|
||||
Py_DECREF(context);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
|
@ -33,6 +61,7 @@ static inline void
|
|||
handle_func_event(PyFunction_WatchEvent event, PyFunctionObject *func,
|
||||
PyObject *new_value)
|
||||
{
|
||||
assert(Py_REFCNT(func) > 0);
|
||||
PyInterpreterState *interp = _PyInterpreterState_GET();
|
||||
assert(interp->_initialized);
|
||||
if (interp->active_func_watchers) {
|
||||
|
@ -766,7 +795,14 @@ func_clear(PyFunctionObject *op)
|
|||
static void
|
||||
func_dealloc(PyFunctionObject *op)
|
||||
{
|
||||
assert(Py_REFCNT(op) == 0);
|
||||
Py_SET_REFCNT(op, 1);
|
||||
handle_func_event(PyFunction_EVENT_DESTROY, op, NULL);
|
||||
if (Py_REFCNT(op) > 1) {
|
||||
Py_SET_REFCNT(op, Py_REFCNT(op) - 1);
|
||||
return;
|
||||
}
|
||||
Py_SET_REFCNT(op, 0);
|
||||
_PyObject_GC_UNTRACK(op);
|
||||
if (op->func_weakreflist != NULL) {
|
||||
PyObject_ClearWeakRefs((PyObject *) op);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue