diff --git a/Include/object.h b/Include/object.h --- a/Include/object.h +++ b/Include/object.h @@ -507,6 +507,7 @@ PyAPI_FUNC(PyObject *) _PyObject_GetAttrId(PyObject *, struct _Py_Identifier *); PyAPI_FUNC(int) _PyObject_SetAttrId(PyObject *, struct _Py_Identifier *, PyObject *); PyAPI_FUNC(int) _PyObject_HasAttrId(PyObject *, struct _Py_Identifier *); +PyAPI_FUNC(void) _PyObject_ResurrectFromDealloc(PyObject *); #ifndef Py_LIMITED_API PyAPI_FUNC(PyObject **) _PyObject_GetDictPtr(PyObject *); #endif diff --git a/Modules/_io/iobase.c b/Modules/_io/iobase.c --- a/Modules/_io/iobase.c +++ b/Modules/_io/iobase.c @@ -236,24 +236,7 @@ PyErr_Restore(tp, v, tb); if (is_zombie) { if (--Py_REFCNT(self) != 0) { - /* The object lives again. The following code is taken from - slot_tp_del in typeobject.c. */ - Py_ssize_t refcnt = Py_REFCNT(self); - _Py_NewReference(self); - Py_REFCNT(self) = refcnt; - /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so - * we need to undo that. */ - _Py_DEC_REFTOTAL; - /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object - * chain, so no more to do there. - * If COUNT_ALLOCS, the original decref bumped tp_frees, and - * _Py_NewReference bumped tp_allocs: both of those need to be - * undone. - */ -#ifdef COUNT_ALLOCS - --Py_TYPE(self)->tp_frees; - --Py_TYPE(self)->tp_allocs; -#endif + _PyObject_ResurrectFromDealloc(self); return -1; } } @@ -286,13 +269,8 @@ However, if the derived class declares a __slots__, those slots are already gone. */ - if (_PyIOBase_finalize((PyObject *) self) < 0) { - /* When called from a heap type's dealloc, the type will be - decref'ed on return (see e.g. subtype_dealloc in typeobject.c). */ - if (PyType_HasFeature(Py_TYPE(self), Py_TPFLAGS_HEAPTYPE)) - Py_INCREF(Py_TYPE(self)); + if (_PyIOBase_finalize((PyObject *) self) < 0) return; - } _PyObject_GC_UNTRACK(self); if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); diff --git a/Objects/typeobject.c b/Objects/typeobject.c --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1117,6 +1117,45 @@ */ } +/* A function to do the necessary adjustments if we find that code + * run during a tp_dealloc or tp_free has resurrected an + * object. It adjusts the total reference count and adds a new + * reference to the type. + */ +void +_PyObject_ResurrectFromDealloc(PyObject *self) +{ + /* The object lives again. We must now undo the _Py_ForgetReference + * done in _Py_Dealloc in object.c. + */ + Py_ssize_t refcnt = Py_REFCNT(self); + assert(Py_REFCNT(self) != 0); + _Py_NewReference(self); + Py_REFCNT(self) = refcnt; + /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so + * we need to undo that. */ + _Py_DEC_REFTOTAL; + /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object + * chain, so no more to do there. + * If COUNT_ALLOCS, the original decref bumped tp_frees, and + * _Py_NewReference bumped tp_allocs: both of those need to be + * undone. + */ +#ifdef COUNT_ALLOCS + --Py_TYPE(self)->tp_frees; + --Py_TYPE(self)->tp_allocs; +#endif + + /* When called from a heap type's dealloc (subtype_dealloc avove), the type will be + * decref'ed on return. This counteracts that. There is no way to otherwise + * let subtype_dealloc know that calling a parent class' tp_dealloc slot caused + * the instance to be resurrected. + */ + if (PyType_HasFeature(Py_TYPE(self), Py_TPFLAGS_HEAPTYPE)) + Py_INCREF(Py_TYPE(self)); + return; +} + static PyTypeObject *solid_base(PyTypeObject *type); /* type test with subclassing support */ @@ -5511,26 +5550,7 @@ /* __del__ resurrected it! Make it look like the original Py_DECREF * never happened. */ - { - Py_ssize_t refcnt = self->ob_refcnt; - _Py_NewReference(self); - self->ob_refcnt = refcnt; - } - assert(!PyType_IS_GC(Py_TYPE(self)) || - _Py_AS_GC(self)->gc.gc_refs != _PyGC_REFS_UNTRACKED); - /* If Py_REF_DEBUG, _Py_NewReference bumped _Py_RefTotal, so - * we need to undo that. */ - _Py_DEC_REFTOTAL; - /* If Py_TRACE_REFS, _Py_NewReference re-added self to the object - * chain, so no more to do there. - * If COUNT_ALLOCS, the original decref bumped tp_frees, and - * _Py_NewReference bumped tp_allocs: both of those need to be - * undone. - */ -#ifdef COUNT_ALLOCS - --Py_TYPE(self)->tp_frees; - --Py_TYPE(self)->tp_allocs; -#endif + _PyObject_ResurrectFromDealloc(self); }

AltStyle によって変換されたページ (->オリジナル) /