@@ -51,13 +51,13 @@ PyGC_Head *_PyGC_generation0 = GEN_HEAD(0);
5151static int enabled = 1 ; /* automatic collection enabled? */
5252
5353/* true if we are currently running the collector */
54- static int collecting ;
54+ static int collecting = 0 ;
5555
5656/* list of uncollectable objects */
57- static PyObject * garbage ;
57+ static PyObject * garbage = NULL ;
5858
5959/* Python string to use if unhandled exception occurs */
60- static PyObject * gc_str ;
60+ static PyObject * gc_str = NULL ;
6161
6262/* Python string used to look for __del__ attribute. */
6363static PyObject * delstr = NULL ;
@@ -412,19 +412,20 @@ visit_move(PyObject *op, PyGC_Head *tolist)
412412}
413413
414414/* Move objects that are reachable from finalizers, from the unreachable set
415- * into the finalizers set.
415+ * into the reachable_from_finalizers set.
416416 */
417417static void
418- move_finalizer_reachable (PyGC_Head * finalizers )
418+ move_finalizer_reachable (PyGC_Head * finalizers ,
419+ PyGC_Head * reachable_from_finalizers )
419420{
420421 traverseproc traverse ;
421422 PyGC_Head * gc = finalizers -> gc .gc_next ;
422- for (; gc != finalizers ; gc = gc -> gc .gc_next ) {
423- /* careful, finalizers list is growing here */
423+ for (; gc != finalizers ; gc = gc -> gc .gc_next ) {
424+ /* Note that the finalizers list may grow during this. */
424425 traverse = FROM_GC (gc )-> ob_type -> tp_traverse ;
425426 (void ) traverse (FROM_GC (gc ),
426- (visitproc )visit_move ,
427- (void * )finalizers );
427+ (visitproc )visit_move ,
428+ (void * )reachable_from_finalizers );
428429 }
429430}
430431
@@ -454,28 +455,32 @@ debug_cycle(char *msg, PyObject *op)
454455 }
455456}
456457
457- /* Handle uncollectable garbage (cycles with finalizers). */
458+ /* Handle uncollectable garbage (cycles with finalizers, and stuff reachable
459+ * only from such cycles).
460+ */
458461static void
459- handle_finalizers (PyGC_Head * finalizers , PyGC_Head * old )
462+ handle_finalizers (PyGC_Head * finalizers , PyGC_Head * old , int hasfinalizer )
460463{
461464 PyGC_Head * gc ;
462465 if (garbage == NULL ) {
463466 garbage = PyList_New (0 );
467+ if (garbage == NULL )
468+ Py_FatalError ("gc couldn't create gc.garbage list" );
464469 }
465- for (gc = finalizers -> gc .gc_next ; gc != finalizers ;
466- gc = finalizers -> gc .gc_next ) {
470+ for (gc = finalizers -> gc .gc_next ;
471+ gc != finalizers ;
472+ gc = finalizers -> gc .gc_next ) {
467473 PyObject * op = FROM_GC (gc );
468- /* XXX has_finalizer() is not safe here. */
469- if ((debug & DEBUG_SAVEALL ) || has_finalizer (op )) {
474+
475+ assert (IS_REACHABLE (op ));
476+ if ((debug & DEBUG_SAVEALL ) || hasfinalizer ) {
470477 /* If SAVEALL is not set then just append objects with
471478 * finalizers to the list of garbage. All objects in
472479 * the finalizers list are reachable from those
473480 * objects.
474481 */
475482 PyList_Append (garbage , op );
476483 }
477- /* object is now reachable again */
478- assert (IS_REACHABLE (op ));
479484 gc_list_remove (gc );
480485 gc_list_append (gc , old );
481486 }
@@ -527,6 +532,7 @@ collect(int generation)
527532 PyGC_Head unreachable ;
528533 PyGC_Head collectable ;
529534 PyGC_Head finalizers ;
535+ PyGC_Head reachable_from_finalizers ;
530536 PyGC_Head * gc ;
531537
532538 if (delstr == NULL ) {
@@ -589,16 +595,27 @@ collect(int generation)
589595 * care not to create such things. For Python, finalizers means
590596 * instance objects with __del__ methods.
591597 *
592- * Move each object into the collectable set or the finalizers set.
593- * Because we need to check for __del__ methods on instances of
594- * classic classes, arbitrary Python code may get executed by
595- * getattr hooks: that may resurrect or deallocate (via refcount
596- * falling to 0) unreachable objects, so this is very delicate.
598+ * Move each unreachable object into the collectable set or the
599+ * finalizers set. Because we need to check for __del__ methods on
600+ * instances of classic classes, arbitrary Python code may get
601+ * executed by getattr hooks: that may resurrect or deallocate (via
602+ * refcount falling to 0) unreachable objects, so this is very
603+ * delicate.
597604 */
598605 gc_list_init (& collectable );
599606 gc_list_init (& finalizers );
600607 move_finalizers (& unreachable , & collectable , & finalizers );
601- move_finalizer_reachable (& finalizers );
608+ /* finalizers contains the unreachable objects with a finalizer;
609+ * unreachable objects reachable only *from* those are also
610+ * uncollectable; we move those into a separate list
611+ * (reachable_from_finalizers) so we don't have to do the dangerous
612+ * has_finalizer() test again later.
613+ */
614+ gc_list_init (& reachable_from_finalizers );
615+ move_finalizer_reachable (& finalizers , & reachable_from_finalizers );
616+ /* And move everything only reachable from the reachable stuff. */
617+ move_finalizer_reachable (& reachable_from_finalizers ,
618+ & reachable_from_finalizers );
602619
603620 /* Collect statistics on collectable objects found and print
604621 * debugging information. */
@@ -610,18 +627,25 @@ collect(int generation)
610627 }
611628 }
612629 /* Call tp_clear on objects in the collectable set. This will cause
613- * the reference cycles to be broken. It may also cause some objects in
614- * finalizers to be freed */
630+ * the reference cycles to be broken. It may also cause some objects
631+ * in finalizers and/or reachable_from_finalizers to be freed */
615632 delete_garbage (& collectable , old );
616633
617634 /* Collect statistics on uncollectable objects found and print
618635 * debugging information. */
619- for (gc = finalizers .gc .gc_next ; gc != & finalizers ;
620- gc = gc -> gc .gc_next ) {
636+ for (gc = finalizers .gc .gc_next ;
637+ gc != & finalizers ;
638+ gc = gc -> gc .gc_next ) {
621639 n ++ ;
622- if (debug & DEBUG_UNCOLLECTABLE ) {
640+ if (debug & DEBUG_UNCOLLECTABLE )
641+ debug_cycle ("uncollectable" , FROM_GC (gc ));
642+ }
643+ for (gc = reachable_from_finalizers .gc .gc_next ;
644+ gc != & reachable_from_finalizers ;
645+ gc = gc -> gc .gc_next ) {
646+ n ++ ;
647+ if (debug & DEBUG_UNCOLLECTABLE )
623648 debug_cycle ("uncollectable" , FROM_GC (gc ));
624- }
625649 }
626650 if (debug & DEBUG_STATS ) {
627651 if (m == 0 && n == 0 ) {
@@ -636,8 +660,10 @@ collect(int generation)
636660
637661 /* Append instances in the uncollectable set to a Python
638662 * reachable list of garbage. The programmer has to deal with
639- * this if they insist on creating this type of structure. */
640- handle_finalizers (& finalizers , old );
663+ * this if they insist on creating this type of structure.
664+ */
665+ handle_finalizers (& finalizers , old , 1 );
666+ handle_finalizers (& reachable_from_finalizers , old , 0 );
641667
642668 if (PyErr_Occurred ()) {
643669 if (gc_str == NULL ) {
0 commit comments