summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2003-11-12 20:43:28 (GMT)
committerTim Peters <tim.peters@gmail.com>2003-11-12 20:43:28 (GMT)
commitadd09b4149b17afa30aa042dbb718b9d9ec741c3 (patch)
treee3d9f2501d6143ff2d27a50a7d93674c99dde7cd /Objects
parent045f1de57ed524d5dbaab92fea8eabc59b33d6f2 (diff)
downloadcpython-add09b4149b17afa30aa042dbb718b9d9ec741c3.zip
cpython-add09b4149b17afa30aa042dbb718b9d9ec741c3.tar.gz
cpython-add09b4149b17afa30aa042dbb718b9d9ec741c3.tar.bz2
SF bug 840829: weakref callbacks and gc corrupt memory.
subtype_dealloc(): This left the dying object exposed to gc, so that if cyclic gc triggered during the weakref callback, gc tried to delete the dying object a second time. That's a disaster. subtype_dealloc() had a (I hope!) unique problem here, as every normal dealloc routine untracks the object (from gc) before fiddling with weakrefs etc. But subtype_dealloc has obscure technical reasons for re-registering the dying object with gc (already explained in a large comment block at the bottom of the function). The fix amounts to simply refraining from reregistering the dying object with gc until after the weakref callback (if any) has been called. This is a critical bug (hard to predict, and causes seemingly random memory corruption when it occurs). I'll backport it to 2.3 later.
Diffstat (limited to 'Objects')
-rw-r--r--Objects/typeobject.c7
1 files changed, 6 insertions, 1 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index b1c822f..bdbabf4 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -639,7 +639,11 @@ subtype_dealloc(PyObject *self)
++_PyTrash_delete_nesting;
Py_TRASHCAN_SAFE_BEGIN(self);
--_PyTrash_delete_nesting;
- _PyObject_GC_TRACK(self); /* We'll untrack for real later */
+ /* DO NOT restore GC tracking at this point. The weakref callback
+ * (if any) may trigger GC, and if self is tracked at that point,
+ * it will look like trash to GC and GC will try to delete it
+ * again. Double-deallocation is a subtle disaster.
+ */
/* Find the nearest base with a different tp_dealloc */
base = type;
@@ -654,6 +658,7 @@ subtype_dealloc(PyObject *self)
if (type->tp_weaklistoffset && !base->tp_weaklistoffset)
PyObject_ClearWeakRefs(self);
+ _PyObject_GC_TRACK(self); /* We'll untrack for real later */
/* Maybe call finalizer; exit early if resurrected */
if (type->tp_del) {