@@ -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 */
@@ -1737,7 +1748,7 @@ gc_collect_region(PyThreadState *tstate,
17371748 }
17381749
17391750 /* Clear weakrefs and invoke callbacks as necessary. */
1740- stats -> collected += handle_weakrefs (& unreachable , to );
1751+ stats -> collected += handle_weakrefs (& unreachable , to , true );
17411752 gc_list_validate_space (to , gcstate -> visited_space );
17421753 validate_list (to , collecting_clear_unreachable_clear );
17431754 validate_list (& unreachable , collecting_set_unreachable_clear );
@@ -1751,6 +1762,14 @@ gc_collect_region(PyThreadState *tstate,
17511762 gc_list_init (& final_unreachable );
17521763 handle_resurrected_objects (& unreachable , & final_unreachable , to );
17531764
1765+ /* Clear weakrefs to objects in the unreachable set. No Python-level
1766+ * code must be allowed to access those unreachable objects. During
1767+ * delete_garbage(), finalizers outside the unreachable set might run
1768+ * and create new weakrefs. If those weakrefs were not cleared, they
1769+ * could reveal unreachable objects. Callbacks are not executed.
1770+ */
1771+ handle_weakrefs (& final_unreachable , NULL , false);
1772+
17541773 /* Call tp_clear on objects in the final_unreachable set. This will cause
17551774 * the reference cycles to be broken. It may also cause some objects
17561775 * in finalizers to be freed.
0 commit comments