| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -827,6 +827,14 @@ def test_set_callback_attribute(self): | |||
| 827 | 827 | with self.assertRaises(AttributeError): | |
| 828 | 828 | ref1.__callback__ = lambda ref: None | |
| 829 | 829 | ||
| 830 | + def test_callback_gcs(self): | ||
| 831 | + class ObjectWithDel(Object): | ||
| 832 | + def __del__(self): pass | ||
| 833 | + x = ObjectWithDel(1) | ||
| 834 | + ref1 = weakref.ref(x, lambda ref: support.gc_collect()) | ||
| 835 | + del x | ||
| 836 | + support.gc_collect() | ||
| 837 | + | ||
| 830 | 838 | ||
| 831 | 839 | class SubclassableWeakrefTestCase(TestBase): | |
| 832 | 840 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1 @@ | |||
| 1 | + Fix crash when GC runs during weakref callbacks. | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1116,11 +1116,6 @@ subtype_dealloc(PyObject *self) | |||
| 1116 | 1116 | Py_TRASHCAN_SAFE_BEGIN(self); | |
| 1117 | 1117 | --_PyTrash_delete_nesting; | |
| 1118 | 1118 | -- tstate->trash_delete_nesting; | |
| 1119 | - /* DO NOT restore GC tracking at this point. weakref callbacks | ||
| 1120 | - * (if any, and whether directly here or indirectly in something we | ||
| 1121 | - * call) may trigger GC, and if self is tracked at that point, it | ||
| 1122 | - * will look like trash to GC and GC will try to delete self again. | ||
| 1123 | - */ | ||
| 1124 | 1119 | ||
| 1125 | 1120 | /* Find the nearest base with a different tp_dealloc */ | |
| 1126 | 1121 | base = type; | |
@@ -1131,30 +1126,36 @@ subtype_dealloc(PyObject *self) | |||
| 1131 | 1126 | ||
| 1132 | 1127 | has_finalizer = type->tp_finalize || type->tp_del; | |
| 1133 | 1128 | ||
| 1134 | - /* Maybe call finalizer; exit early if resurrected */ | ||
| 1135 | - if (has_finalizer) | ||
| 1136 | - _PyObject_GC_TRACK(self); | ||
| 1137 | - | ||
| 1138 | 1129 | if (type->tp_finalize) { | |
| 1130 | + _PyObject_GC_TRACK(self); | ||
| 1139 | 1131 | if (PyObject_CallFinalizerFromDealloc(self) < 0) { | |
| 1140 | 1132 | /* Resurrected */ | |
| 1141 | 1133 | goto endlabel; | |
| 1142 | 1134 | } | |
| 1135 | + _PyObject_GC_UNTRACK(self); | ||
| 1143 | 1136 | } | |
| 1144 | - /* If we added a weaklist, we clear it. Do this *before* calling | ||
| 1145 | - tp_del, clearing slots, or clearing the instance dict. */ | ||
| 1137 | + /* | ||
| 1138 | + If we added a weaklist, we clear it. Do this *before* calling tp_del, | ||
| 1139 | + clearing slots, or clearing the instance dict. | ||
| 1140 | + | ||
| 1141 | + GC tracking must be off at this point. weakref callbacks (if any, and | ||
| 1142 | + whether directly here or indirectly in something we call) may trigger GC, | ||
| 1143 | + and if self is tracked at that point, it will look like trash to GC and GC | ||
| 1144 | + will try to delete self again. | ||
| 1145 | + */ | ||
| 1146 | 1146 | if (type->tp_weaklistoffset && !base->tp_weaklistoffset) | |
| 1147 | 1147 | PyObject_ClearWeakRefs(self); | |
| 1148 | 1148 | ||
| 1149 | 1149 | if (type->tp_del) { | |
| 1150 | + _PyObject_GC_TRACK(self); | ||
| 1150 | 1151 | type->tp_del(self); | |
| 1151 | 1152 | if (self->ob_refcnt > 0) { | |
| 1152 | 1153 | /* Resurrected */ | |
| 1153 | 1154 | goto endlabel; | |
| 1154 | 1155 | } | |
| 1156 | + _PyObject_GC_UNTRACK(self); | ||
| 1155 | 1157 | } | |
| 1156 | 1158 | if (has_finalizer) { | |
| 1157 | - _PyObject_GC_UNTRACK(self); | ||
| 1158 | 1159 | /* New weakrefs could be created during the finalizer call. | |
| 1159 | 1160 | If this occurs, clear them out without calling their | |
| 1160 | 1161 | finalizers since they might rely on part of the object | |
| Back | FazBrowse Home | New Git URL |
0 commit comments