summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>2019-09-30 17:27:46 (GMT)
committerƁukasz Langa <lukasz@langa.pl>2019-09-30 17:27:46 (GMT)
commit92ca515ee1efbdc51678e12d105ad642c9b9cc13 (patch)
treef4488b73b4fe285dfcbdcdb01b48418ced310940 /Modules
parent18c4ba9f33868761e374a725d497902863d59ea9 (diff)
downloadcpython-92ca515ee1efbdc51678e12d105ad642c9b9cc13.zip
cpython-92ca515ee1efbdc51678e12d105ad642c9b9cc13.tar.gz
cpython-92ca515ee1efbdc51678e12d105ad642c9b9cc13.tar.bz2
Clear weakrefs in garbage found by the GC (GH-16495) (#16499)
Fix a bug due to the interaction of weakrefs and the cyclic garbage collector. We must clear any weakrefs in garbage in order to prevent their callbacks from executing and causing a crash. (cherry picked from commit bcda460baf25062ab68622b3f043f52b9db4d21d) Co-authored-by: Neil Schemenauer <nas-github@arctrix.com>
Diffstat (limited to 'Modules')
-rw-r--r--Modules/gcmodule.c17
1 files changed, 17 insertions, 0 deletions
diff --git a/Modules/gcmodule.c b/Modules/gcmodule.c
index b2ee566..8bdbafe 100644
--- a/Modules/gcmodule.c
+++ b/Modules/gcmodule.c
@@ -678,6 +678,21 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old)
op = FROM_GC(gc);
next = GC_NEXT(gc);
+ if (PyWeakref_Check(op)) {
+ /* A weakref inside the unreachable set must be cleared. If we
+ * allow its callback to execute inside delete_garbage(), it
+ * could expose objects that have tp_clear already called on
+ * them. Or, it could resurrect unreachable objects. One way
+ * this can happen is if some container objects do not implement
+ * tp_traverse. Then, wr_object can be outside the unreachable
+ * set but can be deallocated as a result of breaking the
+ * reference cycle. If we don't clear the weakref, the callback
+ * will run and potentially cause a crash. See bpo-38006 for
+ * one example.
+ */
+ _PyWeakref_ClearRef((PyWeakReference *)op);
+ }
+
if (! PyType_SUPPORTS_WEAKREFS(Py_TYPE(op)))
continue;
@@ -733,6 +748,8 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old)
* is moved to wrcb_to_call in this case.
*/
if (gc_is_collecting(AS_GC(wr))) {
+ /* it should already have been cleared above */
+ assert(wr->wr_object == Py_None);
continue;
}