@@ -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 */
@@ -1037,62 +1048,6 @@ handle_weakrefs(PyGC_Head *unreachable, PyGC_Head *old)
10371048 return num_freed ;
10381049}
10391050
1040- /* Clear all weakrefs to unreachable objects. When this returns, no object in
1041- * `unreachable` is weakly referenced anymore.
1042- */
1043- static void
1044- clear_weakrefs (PyGC_Head * unreachable )
1045- {
1046- PyGC_Head * gc ;
1047- PyGC_Head * next ;
1048-
1049- for (gc = GC_NEXT (unreachable ); gc != unreachable ; gc = next ) {
1050- PyWeakReference * * wrlist ;
1051-
1052- PyObject * op = FROM_GC (gc );
1053- next = GC_NEXT (gc );
1054-
1055- if (PyWeakref_Check (op )) {
1056- /* A weakref inside the unreachable set must be cleared. If we
1057- * allow its callback to execute inside delete_garbage(), it
1058- * could expose objects that have tp_clear already called on
1059- * them. Or, it could resurrect unreachable objects. One way
1060- * this can happen is if some container objects do not implement
1061- * tp_traverse. Then, wr_object can be outside the unreachable
1062- * set but can be deallocated as a result of breaking the
1063- * reference cycle. If we don't clear the weakref, the callback
1064- * will run and potentially cause a crash. See bpo-38006 for
1065- * one example.
1066- */
1067- _PyWeakref_ClearRef ((PyWeakReference * )op );
1068- }
1069-
1070- if (! _PyType_SUPPORTS_WEAKREFS (Py_TYPE (op ))) {
1071- continue ;
1072- }
1073-
1074- /* It supports weakrefs. Does it have any?
1075- *
1076- * This is never triggered for static types so we can avoid the
1077- * (slightly) more costly _PyObject_GET_WEAKREFS_LISTPTR().
1078- */
1079- wrlist = _PyObject_GET_WEAKREFS_LISTPTR_FROM_OFFSET (op );
1080-
1081- /* `op` may have some weakrefs. March over the list, clear
1082- * all the weakrefs.
1083- */
1084- for (PyWeakReference * wr = * wrlist ; wr != NULL ; wr = * wrlist ) {
1085- /* _PyWeakref_ClearRef clears the weakref but leaves
1086- * the callback pointer intact. Obscure: it also
1087- * changes *wrlist.
1088- */
1089- _PyObject_ASSERT ((PyObject * )wr , wr -> wr_object == op );
1090- _PyWeakref_ClearRef (wr );
1091- _PyObject_ASSERT ((PyObject * )wr , wr -> wr_object == Py_None );
1092- }
1093- }
1094- }
1095-
10961051static void
10971052debug_cycle (const char * msg , PyObject * op )
10981053{
@@ -1793,7 +1748,7 @@ gc_collect_region(PyThreadState *tstate,
17931748 }
17941749
17951750 /* Clear weakrefs and invoke callbacks as necessary. */
1796- stats -> collected += handle_weakrefs (& unreachable , to );
1751+ stats -> collected += handle_weakrefs (& unreachable , to , true );
17971752 gc_list_validate_space (to , gcstate -> visited_space );
17981753 validate_list (to , collecting_clear_unreachable_clear );
17991754 validate_list (& unreachable , collecting_set_unreachable_clear );
@@ -1811,9 +1766,9 @@ gc_collect_region(PyThreadState *tstate,
18111766 * code must be allowed to access those unreachable objects. During
18121767 * delete_garbage(), finalizers outside the unreachable set might run
18131768 * and create new weakrefs. If those weakrefs were not cleared, they
1814- * could reveal unreachable objects.
1769+ * could reveal unreachable objects. Callbacks are not executed.
18151770 */
1816- clear_weakrefs (& final_unreachable );
1771+ handle_weakrefs (& final_unreachable , NULL , false );
18171772
18181773 /* Call tp_clear on objects in the final_unreachable set. This will cause
18191774 * the reference cycles to be broken. It may also cause some objects
0 commit comments