Skip to content

Commit 0e649ab

Browse files
Do not clear weakrefs to types before finalization of instances
1 parent bb21510 commit 0e649ab

1 file changed

Lines changed: 39 additions & 0 deletions

File tree

Python/gc.c

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -858,6 +858,21 @@ move_legacy_finalizer_reachable(PyGC_Head *finalizers)
858858
}
859859
}
860860

861+
/* Move types from unreachable set to prevent clearing of type's subclasses */
862+
static void
863+
move_types_from_unreachable(PyGC_Head *unreachable, PyGC_Head *to)
864+
{
865+
PyGC_Head *gc, *next;
866+
for(gc = GC_NEXT(unreachable); gc != unreachable; gc = next) {
867+
PyObject *op = FROM_GC(gc);
868+
next = GC_NEXT(gc);
869+
870+
if (PyType_Check(op)) {
871+
gc_list_move(gc, to);
872+
}
873+
}
874+
}
875+
861876
/* Clear all weakrefs to unreachable objects, and if such a weakref has a
862877
* callback, invoke it if necessary. Note that it's possible for such
863878
* weakrefs to be outside the unreachable set -- indeed, those are precisely
@@ -1698,6 +1713,7 @@ gc_collect_region(PyThreadState *tstate,
16981713
{
16991714
PyGC_Head unreachable; /* non-problematic unreachable trash */
17001715
PyGC_Head finalizers; /* objects with, & reachable from, __del__ */
1716+
PyGC_Head types; /* unreachable types */
17011717
PyGC_Head *gc; /* initialize to prevent a compiler warning */
17021718
GCState *gcstate = &tstate->interp->gc;
17031719

@@ -1736,6 +1752,15 @@ gc_collect_region(PyThreadState *tstate,
17361752
}
17371753
}
17381754

1755+
/* All types in the unreachable set should be handled after the
1756+
* instances of those types are finalized. Otherwise, when we clear
1757+
* the weak references, the subclasses list will also be cleared, and
1758+
* the type's cache will not be properly invalidated from
1759+
* within the __del__ method.
1760+
*/
1761+
gc_list_init(&types);
1762+
move_types_from_unreachable(&unreachable, &types);
1763+
17391764
/* Clear weakrefs and invoke callbacks as necessary. */
17401765
stats->collected += handle_weakrefs(&unreachable, to);
17411766
gc_list_validate_space(to, gcstate->visited_space);
@@ -1744,6 +1769,20 @@ gc_collect_region(PyThreadState *tstate,
17441769

17451770
/* Call tp_finalize on objects which have one. */
17461771
finalize_garbage(tstate, &unreachable);
1772+
1773+
/* Clear weakrefs to types and invoke callbacks as necessary. */
1774+
stats->collected += handle_weakrefs(&types, to);
1775+
gc_list_validate_space(to, gcstate->visited_space);
1776+
validate_list(to, collecting_clear_unreachable_clear);
1777+
1778+
/* Call tp_finalize on types. */
1779+
finalize_garbage(tstate, &types);
1780+
1781+
/* Merge types back to unreachable to properly process resurected
1782+
* objects and so on.
1783+
*/
1784+
gc_list_merge(&types, &unreachable);
1785+
17471786
/* Handle any objects that may have resurrected after the call
17481787
* to 'finalize_garbage' and continue the collection with the
17491788
* objects that are still unreachable */

0 commit comments

Comments
 (0)