@@ -747,7 +747,7 @@ move_legacy_finalizer_reachable(PyGC_Head *finalizers)
747747 * no object in `unreachable` is weakly referenced anymore.
748748 */
749749static int
750- handle_weakrefs (PyGC_Head * unreachable , PyGC_Head * old )
750+ handle_weakrefs (PyGC_Head * unreachable , PyGC_Head * old , bool allow_callbacks )
751751{
752752 PyGC_Head * gc ;
753753 PyObject * op ; /* generally FROM_GC(gc) */
@@ -756,7 +756,9 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old)
756756 PyGC_Head * next ;
757757 int num_freed = 0 ;
758758
759- gc_list_init (& wrcb_to_call );
759+ if (allow_callbacks ) {
760+ gc_list_init (& wrcb_to_call );
761+ }
760762
761763 /* Clear all weakrefs to the objects in unreachable. If such a weakref
762764 * also has a callback, move it into `wrcb_to_call` if the callback
@@ -812,6 +814,11 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old)
812814 _PyObject_ASSERT ((PyObject * )wr , wr -> wr_object == op );
813815 _PyWeakref_ClearRef (wr );
814816 _PyObject_ASSERT ((PyObject * )wr , wr -> wr_object == Py_None );
817+
818+ if (!allow_callbacks ) {
819+ continue ;
820+ }
821+
815822 if (wr -> wr_callback == NULL ) {
816823 /* no callback */
817824 continue ;
@@ -864,6 +871,10 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old)
864871 }
865872 }
866873
874+ if (!allow_callbacks ) {
875+ return 0 ;
876+ }
877+
867878 /* Invoke the callbacks we decided to honor. It's safe to invoke them
868879 * because they can't reference unreachable objects.
869880 */
@@ -1399,8 +1410,7 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason)
13991410 }
14001411
14011412 /* Clear weakrefs and invoke callbacks as necessary. */
1402- m += handle_weakrefs (& unreachable , old );
1403-
1413+ m += handle_weakrefs (& unreachable , old , true);
14041414 validate_list (old , collecting_clear_unreachable_clear );
14051415 validate_list (& unreachable , collecting_set_unreachable_clear );
14061416
@@ -1413,6 +1423,14 @@ gc_collect_main(PyThreadState *tstate, int generation, _PyGC_Reason reason)
14131423 PyGC_Head final_unreachable ;
14141424 handle_resurrected_objects (& unreachable , & final_unreachable , old );
14151425
1426+ /* Clear weakrefs to objects in the unreachable set. No Python-level
1427+ * code must be allowed to access those unreachable objects. During
1428+ * delete_garbage(), finalizers outside the unreachable set might run
1429+ * and create new weakrefs. If those weakrefs were not cleared, they
1430+ * could reveal unreachable objects. Callbacks are not executed.
1431+ */
1432+ handle_weakrefs (& final_unreachable , NULL , false);
1433+
14161434 /* Call tp_clear on objects in the final_unreachable set. This will cause
14171435 * the reference cycles to be broken. It may also cause some objects
14181436 * in finalizers to be freed.
0 commit comments