@@ -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