@@ -775,10 +775,13 @@ has_legacy_finalizer(PyObject *op)
775775 * 
776776 * This function also removes NEXT_MASK_UNREACHABLE flag 
777777 * from _gc_next in unreachable. 
778+  * 
779+  * Returns the number of items remaining in the `unreachable` list. 
778780 */ 
779- static  void 
781+ static  Py_ssize_t 
780782move_legacy_finalizers (PyGC_Head  * unreachable , PyGC_Head  * finalizers )
781783{
784+     Py_ssize_t  count  =  0 ;
782785    PyGC_Head  * gc , * next ;
783786    _PyObject_ASSERT (
784787        FROM_GC (unreachable ),
@@ -797,8 +800,11 @@ move_legacy_finalizers(PyGC_Head *unreachable, PyGC_Head *finalizers)
797800        if  (has_legacy_finalizer (op )) {
798801            gc_clear_collecting (gc );
799802            gc_list_move (gc , finalizers );
803+         } else  {
804+             ++ count ;
800805        }
801806    }
807+     return  count ;
802808}
803809
804810static  inline  void 
@@ -1072,7 +1078,7 @@ handle_legacy_finalizers(PyThreadState *tstate,
10721078
10731079/* Run first-time finalizers (if any) on all the objects in collectable. 
10741080 * Note that this may remove some (or even all) of the objects from the 
1075-  * list, due to refcounts falling to 0. 
1081+  * list, due to refcounts falling to 0. Return the number of finalizers run.  
10761082 */ 
10771083static  int 
10781084finalize_garbage (PyThreadState  * tstate , PyGC_Head  * collectable )
@@ -1717,7 +1723,8 @@ gc_collect_region(PyThreadState *tstate,
17171723    gc_list_init (& finalizers );
17181724    // NEXT_MASK_UNREACHABLE is cleared here. 
17191725    // After move_legacy_finalizers(), unreachable is normal list. 
1720-     move_legacy_finalizers (& unreachable , & finalizers );
1726+     Py_ssize_t  unreachable_count  =  move_legacy_finalizers (& unreachable , & finalizers );
1727+ 
17211728    /* finalizers contains the unreachable objects with a legacy finalizer; 
17221729     * unreachable objects reachable *from* those are also uncollectable, 
17231730     * and we move those into the finalizers list too. 
@@ -1734,6 +1741,7 @@ gc_collect_region(PyThreadState *tstate,
17341741
17351742    /* Clear weakrefs and invoke callbacks as necessary. */ 
17361743    stats -> collected  +=  handle_weakrefs (& unreachable , to );
1744+ 
17371745    gc_list_validate_space (to , gcstate -> visited_space );
17381746    validate_list (to , collecting_clear_unreachable_clear );
17391747    validate_list (& unreachable , collecting_set_unreachable_clear );
@@ -1750,15 +1758,17 @@ gc_collect_region(PyThreadState *tstate,
17501758    gc_list_init (& final_unreachable );
17511759    if  (check_resurrected ) {
17521760        handle_resurrected_objects (& unreachable , & final_unreachable , to );
1761+         unreachable_count  =  gc_list_size (& final_unreachable );
17531762    } else  {
17541763        gc_list_merge (& unreachable , & final_unreachable );
1764+         assert (unreachable_count  ==  gc_list_size (& final_unreachable ));
17551765    }
17561766
17571767    /* Call tp_clear on objects in the final_unreachable set.  This will cause 
17581768    * the reference cycles to be broken.  It may also cause some objects 
17591769    * in finalizers to be freed. 
17601770    */ 
1761-     stats -> collected  +=  gc_list_size ( & final_unreachable ) ;
1771+     stats -> collected  +=  unreachable_count ;
17621772    delete_garbage (tstate , gcstate , & final_unreachable , to );
17631773
17641774    /* Collect statistics on uncollectable objects found and print 
0 commit comments