@@ -870,7 +870,7 @@ move_legacy_finalizer_reachable(PyGC_Head *finalizers)
870870 * no object in `unreachable` is weakly referenced anymore.
871871 */
872872static int
873- handle_weakrefs (PyGC_Head * unreachable , PyGC_Head * old )
873+ handle_weakrefs (PyGC_Head * unreachable , PyGC_Head * old , bool allow_callbacks )
874874{
875875 PyGC_Head * gc ;
876876 PyObject * op ; /* generally FROM_GC(gc) */
@@ -879,7 +879,9 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old)
879879 PyGC_Head * next ;
880880 int num_freed = 0 ;
881881
882- gc_list_init (& wrcb_to_call );
882+ if (allow_callbacks ) {
883+ gc_list_init (& wrcb_to_call );
884+ }
883885
884886 /* Clear all weakrefs to the objects in unreachable. If such a weakref
885887 * also has a callback, move it into `wrcb_to_call` if the callback
@@ -935,6 +937,11 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old)
935937 _PyObject_ASSERT ((PyObject * )wr , wr -> wr_object == op );
936938 _PyWeakref_ClearRef (wr );
937939 _PyObject_ASSERT ((PyObject * )wr , wr -> wr_object == Py_None );
940+
941+ if (!allow_callbacks ) {
942+ continue ;
943+ }
944+
938945 if (wr -> wr_callback == NULL ) {
939946 /* no callback */
940947 continue ;
@@ -987,6 +994,10 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old)
987994 }
988995 }
989996
997+ if (!allow_callbacks ) {
998+ return 0 ;
999+ }
1000+
9901001 /* Invoke the callbacks we decided to honor. It's safe to invoke them
9911002 * because they can't reference unreachable objects.
9921003 */
@@ -1739,7 +1750,7 @@ gc_collect_region(PyThreadState *tstate,
17391750 }
17401751
17411752 /* Clear weakrefs and invoke callbacks as necessary. */
1742- stats -> collected += handle_weakrefs (& unreachable , to );
1753+ stats -> collected += handle_weakrefs (& unreachable , to , true );
17431754 gc_list_validate_space (to , gcstate -> visited_space );
17441755 validate_list (to , collecting_clear_unreachable_clear );
17451756 validate_list (& unreachable , collecting_set_unreachable_clear );
@@ -1753,6 +1764,14 @@ gc_collect_region(PyThreadState *tstate,
17531764 gc_list_init (& final_unreachable );
17541765 handle_resurrected_objects (& unreachable , & final_unreachable , to );
17551766
1767+ /* Clear weakrefs to objects in the unreachable set. No Python-level
1768+ * code must be allowed to access those unreachable objects. During
1769+ * delete_garbage(), finalizers outside the unreachable set might run
1770+ * and create new weakrefs. If those weakrefs were not cleared, they
1771+ * could reveal unreachable objects. Callbacks are not executed.
1772+ */
1773+ handle_weakrefs (& final_unreachable , NULL , false);
1774+
17561775 /* Call tp_clear on objects in the final_unreachable set. This will cause
17571776 * the reference cycles to be broken. It may also cause some objects
17581777 * in finalizers to be freed.
0 commit comments