@@ -665,11 +665,13 @@ visit_reachable(PyObject *op, void *arg)
665665 * So we can not gc_list_* functions for unreachable until we remove the flag.
666666 */
667667static void
668- move_unreachable (PyGC_Head * young , PyGC_Head * unreachable )
668+ move_unreachable (PyGC_Head * young , PyGC_Head * unreachable , PyGC_Head * unreachable_types )
669669{
670670 // previous elem in the young list, used for restore gc_prev.
671671 PyGC_Head * prev = young ;
672672 PyGC_Head * gc = GC_NEXT (young );
673+ PyGC_Head * to ;
674+ PyObject * op ;
673675
674676 /* Invariants: all objects "to the left" of us in young are reachable
675677 * (directly or indirectly) from outside the young list as it was at entry.
@@ -720,18 +722,26 @@ move_unreachable(PyGC_Head *young, PyGC_Head *unreachable)
720722 // No need to gc->next->prev = prev because it is single linked.
721723 prev -> _gc_next = gc -> _gc_next ;
722724
725+ op = FROM_GC (gc );
726+ if (unreachable_types != NULL && PyType_Check (op )) {
727+ to = unreachable_types ;
728+ }
729+ else {
730+ to = unreachable ;
731+ }
732+
723733 // We can't use gc_list_append() here because we use
724734 // NEXT_MASK_UNREACHABLE here.
725- PyGC_Head * last = GC_PREV (unreachable );
735+ PyGC_Head * last = GC_PREV (to );
726736 // NOTE: Since all objects in unreachable set has
727737 // NEXT_MASK_UNREACHABLE flag, we set it unconditionally.
728738 // But this may pollute the unreachable list head's 'next' pointer
729739 // too. That's semantically senseless but expedient here - the
730740 // damage is repaired when this function ends.
731741 last -> _gc_next = flags | (uintptr_t )gc ;
732742 _PyGCHead_SET_PREV (gc , last );
733- gc -> _gc_next = flags | (uintptr_t )unreachable ;
734- unreachable -> _gc_prev = (uintptr_t )gc ;
743+ gc -> _gc_next = flags | (uintptr_t )to ;
744+ to -> _gc_prev = (uintptr_t )gc ;
735745 }
736746 gc = _PyGCHead_NEXT (prev );
737747 }
@@ -740,6 +750,9 @@ move_unreachable(PyGC_Head *young, PyGC_Head *unreachable)
740750 young -> _gc_next &= _PyGC_PREV_MASK ;
741751 // don't let the pollution of the list head's next pointer leak
742752 unreachable -> _gc_next &= _PyGC_PREV_MASK ;
753+ if (unreachable_types != NULL ) {
754+ unreachable_types -> _gc_next &= _PyGC_PREV_MASK ;
755+ }
743756}
744757
745758/* In theory, all tuples should be younger than the
@@ -858,21 +871,6 @@ move_legacy_finalizer_reachable(PyGC_Head *finalizers)
858871 }
859872}
860873
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-
876874/* Clear all weakrefs to unreachable objects, and if such a weakref has a
877875 * callback, invoke it if necessary. Note that it's possible for such
878876 * weakrefs to be outside the unreachable set -- indeed, those are precisely
@@ -1184,6 +1182,8 @@ delete_garbage(PyThreadState *tstate, GCState *gcstate,
11841182 them to the "unreachable" list. This step also needs to move back to "base" all
11851183 objects that were initially marked as unreachable but are referred transitively
11861184 by the reachable objects (the ones with strictly positive reference count).
1185+ 4. Split unreachable objects and unreachable types to prevent clearing types
1186+ before instances.
11871187
11881188Contracts:
11891189
@@ -1198,7 +1198,8 @@ flag is cleared (for example, by using 'clear_unreachable_mask' function or
11981198by a call to 'move_legacy_finalizers'), the 'unreachable' list is not a normal
11991199list and we can not use most gc_list_* functions for it. */
12001200static inline void
1201- deduce_unreachable (PyGC_Head * base , PyGC_Head * unreachable ) {
1201+ deduce_unreachable (PyGC_Head * base , PyGC_Head * unreachable ,
1202+ PyGC_Head * unreachable_types ) {
12021203 validate_list (base , collecting_clear_unreachable_clear );
12031204 /* Using ob_refcnt and gc_refs, calculate which objects in the
12041205 * container set are reachable from outside the set (i.e., have a
@@ -1242,10 +1243,19 @@ deduce_unreachable(PyGC_Head *base, PyGC_Head *unreachable) {
12421243 * objects will remain unreachable, so it would be more efficient to move
12431244 * the reachable objects instead. But this is a one-time cost, probably not
12441245 * worth complicating the code to speed just a little.
1246+ *
1247+ * Note on types: All types in the unreachable set should be handled after
1248+ * the instances of those types are finalized. Otherwise, when we clear
1249+ * the weak references, the subclasses list will also be cleared, and
1250+ * the type's cache will not be properly invalidated from
1251+ * within the __del__ method.
12451252 */
1246- move_unreachable (base , unreachable ); // gc_prev is pointer again
1253+ move_unreachable (base , unreachable , unreachable_types ); // gc_prev is pointer again
12471254 validate_list (base , collecting_clear_unreachable_clear );
12481255 validate_list (unreachable , collecting_set_unreachable_set );
1256+ if (unreachable_types != NULL ) {
1257+ validate_list (unreachable_types , collecting_set_unreachable_set );
1258+ }
12491259}
12501260
12511261/* Handle objects that may have resurrected after a call to 'finalize_garbage', moving
@@ -1273,7 +1283,7 @@ handle_resurrected_objects(PyGC_Head *unreachable, PyGC_Head* still_unreachable,
12731283 // have the PREV_MARK_COLLECTING set, but the objects are going to be
12741284 // removed so we can skip the expense of clearing the flag.
12751285 PyGC_Head * resurrected = unreachable ;
1276- deduce_unreachable (resurrected , still_unreachable );
1286+ deduce_unreachable (resurrected , still_unreachable , NULL );
12771287 clear_unreachable_mask (still_unreachable );
12781288
12791289 // Move the resurrected objects to the old generation for future collection.
@@ -1713,15 +1723,16 @@ gc_collect_region(PyThreadState *tstate,
17131723{
17141724 PyGC_Head unreachable ; /* non-problematic unreachable trash */
17151725 PyGC_Head finalizers ; /* objects with, & reachable from, __del__ */
1716- PyGC_Head types ; /* unreachable types */
1726+ PyGC_Head unreachable_types ; /* unreachable types */
17171727 PyGC_Head * gc ; /* initialize to prevent a compiler warning */
17181728 GCState * gcstate = & tstate -> interp -> gc ;
17191729
17201730 assert (gcstate -> garbage != NULL );
17211731 assert (!_PyErr_Occurred (tstate ));
17221732
17231733 gc_list_init (& unreachable );
1724- deduce_unreachable (from , & unreachable );
1734+ gc_list_init (& unreachable_types );
1735+ deduce_unreachable (from , & unreachable , & unreachable_types );
17251736 validate_consistent_old_space (from );
17261737 untrack_tuples (from );
17271738 validate_consistent_old_space (to );
@@ -1738,29 +1749,26 @@ gc_collect_region(PyThreadState *tstate,
17381749 // NEXT_MASK_UNREACHABLE is cleared here.
17391750 // After move_legacy_finalizers(), unreachable is normal list.
17401751 move_legacy_finalizers (& unreachable , & finalizers );
1752+ move_legacy_finalizers (& unreachable_types , & finalizers );
17411753 /* finalizers contains the unreachable objects with a legacy finalizer;
17421754 * unreachable objects reachable *from* those are also uncollectable,
17431755 * and we move those into the finalizers list too.
17441756 */
17451757 move_legacy_finalizer_reachable (& finalizers );
17461758 validate_list (& finalizers , collecting_clear_unreachable_clear );
17471759 validate_list (& unreachable , collecting_set_unreachable_clear );
1760+ validate_list (& unreachable_types , collecting_set_unreachable_clear );
17481761 /* Print debugging information. */
17491762 if (gcstate -> debug & _PyGC_DEBUG_COLLECTABLE ) {
17501763 for (gc = GC_NEXT (& unreachable ); gc != & unreachable ; gc = GC_NEXT (gc )) {
17511764 debug_cycle ("collectable" , FROM_GC (gc ));
17521765 }
1766+ gc = GC_NEXT (& unreachable_types );
1767+ for (; gc != & unreachable_types ; gc = GC_NEXT (gc )) {
1768+ debug_cycle ("collectable" , FROM_GC (gc ));
1769+ }
17531770 }
17541771
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-
17641772 /* Clear weakrefs and invoke callbacks as necessary. */
17651773 stats -> collected += handle_weakrefs (& unreachable , to );
17661774 gc_list_validate_space (to , gcstate -> visited_space );
@@ -1771,17 +1779,18 @@ gc_collect_region(PyThreadState *tstate,
17711779 finalize_garbage (tstate , & unreachable );
17721780
17731781 /* Clear weakrefs to types and invoke callbacks as necessary. */
1774- stats -> collected += handle_weakrefs (& types , to );
1782+ stats -> collected += handle_weakrefs (& unreachable_types , to );
17751783 gc_list_validate_space (to , gcstate -> visited_space );
17761784 validate_list (to , collecting_clear_unreachable_clear );
1785+ validate_list (& unreachable_types , collecting_set_unreachable_clear );
17771786
17781787 /* Call tp_finalize on types. */
1779- finalize_garbage (tstate , & types );
1788+ finalize_garbage (tstate , & unreachable_types );
17801789
17811790 /* Merge types back to unreachable to properly process resurected
17821791 * objects and so on.
17831792 */
1784- gc_list_merge (& types , & unreachable );
1793+ gc_list_merge (& unreachable_types , & unreachable );
17851794
17861795 /* Handle any objects that may have resurrected after the call
17871796 * to 'finalize_garbage' and continue the collection with the
0 commit comments