else:
self.fail("exception not properly restored")
+ def test_sf_bug_840829(self):
+ # "weakref callbacks and gc corrupt memory"
+ # subtype_dealloc erroneously exposed a new-style instance
+ # already in the process of getting deallocated to gc,
+ # causing double-deallocation if the instance had a weakref
+ # callback that triggered gc.
+ # If the bug exists, there probably won't be an obvious symptom
+ # in a release build. In a debug build, a segfault will occur
+ # when the second attempt to remove the instance from the "list
+ # of all objects" occurs.
+
+ import gc
+
+ class C(object):
+ pass
+
+ c = C()
+ wr = weakref.ref(c, lambda ignore: gc.collect())
+ del c
+
class Object:
def __init__(self, arg):
Core and builtins
-----------------
+- Critical bugfix, for SF bug 840829: if cyclic garbage collection
+ happened to occur during a weakref callback for a new-style class
+ instance, subtle memory corruption was the result (in a release build;
+ in a debug build, a segfault occurred reliably very soon after).
+ This has been repaired.
+
- Added a reversed() builtin function that returns a reverse iterator
over a sequence.
++_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;
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) {