mirror of
https://github.com/python/cpython.git
synced 2025-11-13 23:46:24 +00:00
Clear weakrefs in garbage found by the GC (#16495)
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.
This commit is contained in:
parent
c9a413ede4
commit
bcda460baf
2 changed files with 20 additions and 0 deletions
|
|
@ -0,0 +1,3 @@
|
||||||
|
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.
|
||||||
|
|
@ -678,6 +678,21 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old)
|
||||||
op = FROM_GC(gc);
|
op = FROM_GC(gc);
|
||||||
next = GC_NEXT(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)))
|
if (! PyType_SUPPORTS_WEAKREFS(Py_TYPE(op)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
|
@ -733,6 +748,8 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old)
|
||||||
* is moved to wrcb_to_call in this case.
|
* is moved to wrcb_to_call in this case.
|
||||||
*/
|
*/
|
||||||
if (gc_is_collecting(AS_GC(wr))) {
|
if (gc_is_collecting(AS_GC(wr))) {
|
||||||
|
/* it should already have been cleared above */
|
||||||
|
assert(wr->wr_object == Py_None);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue