diff options
author | Tim Peters <tim.peters@gmail.com> | 2003-04-05 17:35:54 (GMT) |
---|---|---|
committer | Tim Peters <tim.peters@gmail.com> | 2003-04-05 17:35:54 (GMT) |
commit | 86b993b6cfffa6fee144054d30fd94d02a3717cb (patch) | |
tree | 73d09eae152995dede57ef56aa4eb84e830a440c /Modules/gcmodule.c | |
parent | 93ad66dea9814b6ad59710171227d84c78bbb4b9 (diff) | |
download | cpython-86b993b6cfffa6fee144054d30fd94d02a3717cb.zip cpython-86b993b6cfffa6fee144054d30fd94d02a3717cb.tar.gz cpython-86b993b6cfffa6fee144054d30fd94d02a3717cb.tar.bz2 |
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.
Diffstat (limited to 'Modules/gcmodule.c')
-rw-r--r-- | Modules/gcmodule.c | 27 |
1 files changed, 21 insertions, 6 deletions
diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c index 10a90b1..729e9d5 100644 --- a/Modules/gcmodule.c +++ b/Modules/gcmodule.c @@ -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 has_finalizer(PyObject *op) { - return PyInstance_Check(op) ? PyObject_HasAttr(op, delstr) : - PyType_HasFeature(op->ob_type, Py_TPFLAGS_HEAPTYPE) ? - op->ob_type->tp_del != NULL : 0; + if (PyInstance_Check(op)) { + /* This is the dangerous path: hasattr can invoke + * 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. @@ -586,8 +599,10 @@ collect(int generation) * instance objects with __del__ methods. * * Move each object into the collectable set or the finalizers set. - * It's possible that a classic class with a getattr() hook will - * be revived or deallocated in this step. + * Because we need to check for __del__ methods on instances of + * 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(&finalizers); |