mirror of https://github.com/python/cpython
ensure gc tracking is off when invoking weakref callbacks (closes #26617)
This commit is contained in:
parent
b47c9d29d7
commit
8f657c35b9
|
@ -845,6 +845,14 @@ class ReferencesTestCase(TestBase):
|
||||||
with self.assertRaises(AttributeError):
|
with self.assertRaises(AttributeError):
|
||||||
ref1.__callback__ = lambda ref: None
|
ref1.__callback__ = lambda ref: None
|
||||||
|
|
||||||
|
def test_callback_gcs(self):
|
||||||
|
class ObjectWithDel(Object):
|
||||||
|
def __del__(self): pass
|
||||||
|
x = ObjectWithDel(1)
|
||||||
|
ref1 = weakref.ref(x, lambda ref: support.gc_collect())
|
||||||
|
del x
|
||||||
|
support.gc_collect()
|
||||||
|
|
||||||
|
|
||||||
class SubclassableWeakrefTestCase(TestBase):
|
class SubclassableWeakrefTestCase(TestBase):
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,8 @@ Release date: TBA
|
||||||
Core and Builtins
|
Core and Builtins
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
|
- Issue #26617: Fix crash when GC runs during weakref callbacks.
|
||||||
|
|
||||||
- Issue #27942: String constants now interned recursively in tuples and frozensets.
|
- Issue #27942: String constants now interned recursively in tuples and frozensets.
|
||||||
|
|
||||||
- Issue #21578: Fixed misleading error message when ImportError called with
|
- Issue #21578: Fixed misleading error message when ImportError called with
|
||||||
|
|
|
@ -1123,11 +1123,6 @@ subtype_dealloc(PyObject *self)
|
||||||
Py_TRASHCAN_SAFE_BEGIN(self);
|
Py_TRASHCAN_SAFE_BEGIN(self);
|
||||||
--_PyTrash_delete_nesting;
|
--_PyTrash_delete_nesting;
|
||||||
-- tstate->trash_delete_nesting;
|
-- tstate->trash_delete_nesting;
|
||||||
/* DO NOT restore GC tracking at this point. weakref callbacks
|
|
||||||
* (if any, and whether directly here or indirectly in something we
|
|
||||||
* call) may trigger GC, and if self is tracked at that point, it
|
|
||||||
* will look like trash to GC and GC will try to delete self again.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* Find the nearest base with a different tp_dealloc */
|
/* Find the nearest base with a different tp_dealloc */
|
||||||
base = type;
|
base = type;
|
||||||
|
@ -1138,30 +1133,36 @@ subtype_dealloc(PyObject *self)
|
||||||
|
|
||||||
has_finalizer = type->tp_finalize || type->tp_del;
|
has_finalizer = type->tp_finalize || type->tp_del;
|
||||||
|
|
||||||
/* Maybe call finalizer; exit early if resurrected */
|
|
||||||
if (has_finalizer)
|
|
||||||
_PyObject_GC_TRACK(self);
|
|
||||||
|
|
||||||
if (type->tp_finalize) {
|
if (type->tp_finalize) {
|
||||||
|
_PyObject_GC_TRACK(self);
|
||||||
if (PyObject_CallFinalizerFromDealloc(self) < 0) {
|
if (PyObject_CallFinalizerFromDealloc(self) < 0) {
|
||||||
/* Resurrected */
|
/* Resurrected */
|
||||||
goto endlabel;
|
goto endlabel;
|
||||||
}
|
}
|
||||||
|
_PyObject_GC_UNTRACK(self);
|
||||||
}
|
}
|
||||||
/* If we added a weaklist, we clear it. Do this *before* calling
|
/*
|
||||||
tp_del, clearing slots, or clearing the instance dict. */
|
If we added a weaklist, we clear it. Do this *before* calling tp_del,
|
||||||
|
clearing slots, or clearing the instance dict.
|
||||||
|
|
||||||
|
GC tracking must be off at this point. weakref callbacks (if any, and
|
||||||
|
whether directly here or indirectly in something we call) may trigger GC,
|
||||||
|
and if self is tracked at that point, it will look like trash to GC and GC
|
||||||
|
will try to delete self again.
|
||||||
|
*/
|
||||||
if (type->tp_weaklistoffset && !base->tp_weaklistoffset)
|
if (type->tp_weaklistoffset && !base->tp_weaklistoffset)
|
||||||
PyObject_ClearWeakRefs(self);
|
PyObject_ClearWeakRefs(self);
|
||||||
|
|
||||||
if (type->tp_del) {
|
if (type->tp_del) {
|
||||||
|
_PyObject_GC_TRACK(self);
|
||||||
type->tp_del(self);
|
type->tp_del(self);
|
||||||
if (self->ob_refcnt > 0) {
|
if (self->ob_refcnt > 0) {
|
||||||
/* Resurrected */
|
/* Resurrected */
|
||||||
goto endlabel;
|
goto endlabel;
|
||||||
}
|
}
|
||||||
|
_PyObject_GC_UNTRACK(self);
|
||||||
}
|
}
|
||||||
if (has_finalizer) {
|
if (has_finalizer) {
|
||||||
_PyObject_GC_UNTRACK(self);
|
|
||||||
/* New weakrefs could be created during the finalizer call.
|
/* New weakrefs could be created during the finalizer call.
|
||||||
If this occurs, clear them out without calling their
|
If this occurs, clear them out without calling their
|
||||||
finalizers since they might rely on part of the object
|
finalizers since they might rely on part of the object
|
||||||
|
|
Loading…
Reference in New Issue