summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTim Peters <tim.peters@gmail.com>2003-11-14 00:01:17 (GMT)
committerTim Peters <tim.peters@gmail.com>2003-11-14 00:01:17 (GMT)
commit780c497972f367df86cf0f6f3b7c2aecf1e078d6 (patch)
tree8c28622f4e96b83d10ef2a4a5421e9c743c10007
parent0bd743cee17ab8a96122ca0cc692419232a3d3bb (diff)
downloadcpython-780c497972f367df86cf0f6f3b7c2aecf1e078d6.zip
cpython-780c497972f367df86cf0f6f3b7c2aecf1e078d6.tar.gz
cpython-780c497972f367df86cf0f6f3b7c2aecf1e078d6.tar.bz2
update_refs(): assert that incoming refcounts aren't 0. The comment
for this function has always claimed that was true, but it wasn't verified before. For the latest batch of "double deallocation" bugs (stemming from weakref callbacks invoked by way of subtype_dealloc), this assert would have triggered (instead of waiting for _Py_ForgetReference to die with a segfault later).
-rw-r--r--Modules/gcmodule.c19
1 files changed, 19 insertions, 0 deletions
diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c
index 6442fe5..e6aabe4 100644
--- a/Modules/gcmodule.c
+++ b/Modules/gcmodule.c
@@ -214,6 +214,25 @@ update_refs(PyGC_Head *containers)
for (; gc != containers; gc = gc->gc.gc_next) {
assert(gc->gc.gc_refs == GC_REACHABLE);
gc->gc.gc_refs = FROM_GC(gc)->ob_refcnt;
+ /* Python's cyclic gc should never see an incoming refcount
+ * of 0: if something decref'ed to 0, it should have been
+ * deallocated immediately at that time.
+ * Possible cause (if the assert triggers): a tp_dealloc
+ * routine left a gc-aware object tracked during its teardown
+ * phase, and did something-- or allowed something to happen --
+ * that called back into Python. gc can trigger then, and may
+ * see the still-tracked dying object. Before this assert
+ * was added, such mistakes went on to allow gc to try to
+ * delete the object again. In a debug build, that caused
+ * a mysterious segfault, when _Py_ForgetReference tried
+ * to remove the object from the doubly-linked list of all
+ * objects a second time. In a release build, an actual
+ * double deallocation occurred, which leads to corruption
+ * of the allocator's internal bookkeeping pointers. That's
+ * so serious that maybe this should be a release-build
+ * check instead of an assert?
+ */
+ assert(gc->gc.gc_refs != 0);
}
}