mirror of
https://github.com/python/cpython.git
synced 2025-09-27 02:39:58 +00:00
New comments. Rewrote has_finalizer() as a sequence of ifs instead of
squashed-together conditional operators; makes it much easier to step thru in the debugger, and to set a breakpoint on the only dangerous path.
This commit is contained in:
parent
93ad66dea9
commit
86b993b6cf
1 changed files with 21 additions and 6 deletions
|
@ -339,13 +339,26 @@ move_unreachable(PyGC_Head *young, PyGC_Head *unreachable)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* return true if object has a finalization method */
|
/* Return true if object has a finalization method.
|
||||||
|
* CAUTION: An instance of an old-style class has to be checked for a
|
||||||
|
*__del__ method, and that can cause arbitrary Python code to get executed
|
||||||
|
* via the class's __getattr__ hook (if any). This function can therefore
|
||||||
|
* mutate the object graph, and that's been the source of subtle bugs.
|
||||||
|
*/
|
||||||
static int
|
static int
|
||||||
has_finalizer(PyObject *op)
|
has_finalizer(PyObject *op)
|
||||||
{
|
{
|
||||||
return PyInstance_Check(op) ? PyObject_HasAttr(op, delstr) :
|
if (PyInstance_Check(op)) {
|
||||||
PyType_HasFeature(op->ob_type, Py_TPFLAGS_HEAPTYPE) ?
|
/* This is the dangerous path: hasattr can invoke
|
||||||
op->ob_type->tp_del != NULL : 0;
|
* the class __getattr__(), and that can do anything.
|
||||||
|
*/
|
||||||
|
assert(delstr != NULL);
|
||||||
|
return PyObject_HasAttr(op, delstr);
|
||||||
|
}
|
||||||
|
else if (PyType_HasFeature(op->ob_type, Py_TPFLAGS_HEAPTYPE))
|
||||||
|
return op->ob_type->tp_del != NULL;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move all objects out of unreachable and into collectable or finalizers.
|
/* Move all objects out of unreachable and into collectable or finalizers.
|
||||||
|
@ -586,8 +599,10 @@ collect(int generation)
|
||||||
* instance objects with __del__ methods.
|
* instance objects with __del__ methods.
|
||||||
*
|
*
|
||||||
* Move each object into the collectable set or the finalizers set.
|
* Move each object into the collectable set or the finalizers set.
|
||||||
* It's possible that a classic class with a getattr() hook will
|
* Because we need to check for __del__ methods on instances of
|
||||||
* be revived or deallocated in this step.
|
* classic classes, arbitrary Python code may get executed by
|
||||||
|
* getattr hooks: that may resurrect or deallocate (via refcount
|
||||||
|
* falling to 0) unreachable objects, so this is very delicate.
|
||||||
*/
|
*/
|
||||||
gc_list_init(&collectable);
|
gc_list_init(&collectable);
|
||||||
gc_list_init(&finalizers);
|
gc_list_init(&finalizers);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue