mirror of
https://github.com/python/cpython.git
synced 2025-10-04 22:20:46 +00:00
bpo-31095: fix potential crash during GC (GH-3195)
(cherry picked from commit a6296d34a4
)
This commit is contained in:
parent
7d8282d25d
commit
2eea952b1b
14 changed files with 60 additions and 13 deletions
|
@ -728,8 +728,9 @@ functions. With :c:func:`Py_VISIT`, :c:func:`Noddy_traverse` can be simplified:
|
|||
uniformity across these boring implementations.
|
||||
|
||||
We also need to provide a method for clearing any subobjects that can
|
||||
participate in cycles. We implement the method and reimplement the deallocator
|
||||
to use it::
|
||||
participate in cycles.
|
||||
|
||||
::
|
||||
|
||||
static int
|
||||
Noddy_clear(Noddy *self)
|
||||
|
@ -747,13 +748,6 @@ to use it::
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
Noddy_dealloc(Noddy* self)
|
||||
{
|
||||
Noddy_clear(self);
|
||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||
}
|
||||
|
||||
Notice the use of a temporary variable in :c:func:`Noddy_clear`. We use the
|
||||
temporary variable so that we can set each member to *NULL* before decrementing
|
||||
its reference count. We do this because, as was discussed earlier, if the
|
||||
|
@ -776,6 +770,23 @@ be simplified::
|
|||
return 0;
|
||||
}
|
||||
|
||||
Note that :c:func:`Noddy_dealloc` may call arbitrary functions through
|
||||
``__del__`` method or weakref callback. It means circular GC can be
|
||||
triggered inside the function. Since GC assumes reference count is not zero,
|
||||
we need to untrack the object from GC by calling :c:func:`PyObject_GC_UnTrack`
|
||||
before clearing members. Here is reimplemented deallocator which uses
|
||||
:c:func:`PyObject_GC_UnTrack` and :c:func:`Noddy_clear`.
|
||||
|
||||
::
|
||||
|
||||
static void
|
||||
Noddy_dealloc(Noddy* self)
|
||||
{
|
||||
PyObject_GC_UnTrack(self);
|
||||
Noddy_clear(self);
|
||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||
}
|
||||
|
||||
Finally, we add the :const:`Py_TPFLAGS_HAVE_GC` flag to the class flags::
|
||||
|
||||
Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC, /* tp_flags */
|
||||
|
|
|
@ -46,6 +46,7 @@ Noddy_clear(Noddy *self)
|
|||
static void
|
||||
Noddy_dealloc(Noddy* self)
|
||||
{
|
||||
PyObject_GC_UnTrack(self);
|
||||
Noddy_clear(self);
|
||||
Py_TYPE(self)->tp_free((PyObject*)self);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
Fix potential crash during GC caused by ``tp_dealloc`` which doesn't call
|
||||
``PyObject_GC_UnTrack()``.
|
|
@ -1706,6 +1706,8 @@ dequeiter_traverse(dequeiterobject *dio, visitproc visit, void *arg)
|
|||
static void
|
||||
dequeiter_dealloc(dequeiterobject *dio)
|
||||
{
|
||||
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
||||
PyObject_GC_UnTrack(dio);
|
||||
Py_XDECREF(dio->deque);
|
||||
PyObject_GC_Del(dio);
|
||||
}
|
||||
|
@ -2086,6 +2088,8 @@ static PyMemberDef defdict_members[] = {
|
|||
static void
|
||||
defdict_dealloc(defdictobject *dd)
|
||||
{
|
||||
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
||||
PyObject_GC_UnTrack(dd);
|
||||
Py_CLEAR(dd->default_factory);
|
||||
PyDict_Type.tp_dealloc((PyObject *)dd);
|
||||
}
|
||||
|
|
|
@ -627,6 +627,7 @@ element_gc_clear(ElementObject *self)
|
|||
static void
|
||||
element_dealloc(ElementObject* self)
|
||||
{
|
||||
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
||||
PyObject_GC_UnTrack(self);
|
||||
Py_TRASHCAN_SAFE_BEGIN(self)
|
||||
|
||||
|
@ -2048,6 +2049,8 @@ elementiter_dealloc(ElementIterObject *it)
|
|||
{
|
||||
Py_ssize_t i = it->parent_stack_used;
|
||||
it->parent_stack_used = 0;
|
||||
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
||||
PyObject_GC_UnTrack(it);
|
||||
while (i--)
|
||||
Py_XDECREF(it->parent_stack[i].parent);
|
||||
PyMem_Free(it->parent_stack);
|
||||
|
@ -2055,7 +2058,6 @@ elementiter_dealloc(ElementIterObject *it)
|
|||
Py_XDECREF(it->sought_tag);
|
||||
Py_XDECREF(it->root_element);
|
||||
|
||||
PyObject_GC_UnTrack(it);
|
||||
PyObject_GC_Del(it);
|
||||
}
|
||||
|
||||
|
|
|
@ -116,6 +116,7 @@ partial_new(PyTypeObject *type, PyObject *args, PyObject *kw)
|
|||
static void
|
||||
partial_dealloc(partialobject *pto)
|
||||
{
|
||||
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
||||
PyObject_GC_UnTrack(pto);
|
||||
if (pto->weakreflist != NULL)
|
||||
PyObject_ClearWeakRefs((PyObject *) pto);
|
||||
|
@ -1038,7 +1039,11 @@ lru_cache_clear_list(lru_list_elem *link)
|
|||
static void
|
||||
lru_cache_dealloc(lru_cache_object *obj)
|
||||
{
|
||||
lru_list_elem *list = lru_cache_unlink_list(obj);
|
||||
lru_list_elem *list;
|
||||
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
||||
PyObject_GC_UnTrack(obj);
|
||||
|
||||
list = lru_cache_unlink_list(obj);
|
||||
Py_XDECREF(obj->maxsize_O);
|
||||
Py_XDECREF(obj->func);
|
||||
Py_XDECREF(obj->cache);
|
||||
|
|
|
@ -1131,6 +1131,8 @@ bytesiobuf_traverse(bytesiobuf *self, visitproc visit, void *arg)
|
|||
static void
|
||||
bytesiobuf_dealloc(bytesiobuf *self)
|
||||
{
|
||||
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
||||
PyObject_GC_UnTrack(self);
|
||||
Py_CLEAR(self->source);
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
}
|
||||
|
|
|
@ -655,7 +655,8 @@ py_encode_basestring(PyObject* self UNUSED, PyObject *pystr)
|
|||
static void
|
||||
scanner_dealloc(PyObject *self)
|
||||
{
|
||||
/* Deallocate scanner object */
|
||||
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
||||
PyObject_GC_UnTrack(self);
|
||||
scanner_clear(self);
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
}
|
||||
|
@ -1793,7 +1794,8 @@ bail:
|
|||
static void
|
||||
encoder_dealloc(PyObject *self)
|
||||
{
|
||||
/* Deallocate Encoder */
|
||||
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
||||
PyObject_GC_UnTrack(self);
|
||||
encoder_clear(self);
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
}
|
||||
|
|
|
@ -2776,6 +2776,8 @@ context_clear(PySSLContext *self)
|
|||
static void
|
||||
context_dealloc(PySSLContext *self)
|
||||
{
|
||||
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
||||
PyObject_GC_UnTrack(self);
|
||||
context_clear(self);
|
||||
SSL_CTX_free(self->ctx);
|
||||
#ifdef OPENSSL_NPN_NEGOTIATED
|
||||
|
@ -4284,6 +4286,7 @@ static PyTypeObject PySSLMemoryBIO_Type = {
|
|||
static void
|
||||
PySSLSession_dealloc(PySSLSession *self)
|
||||
{
|
||||
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
||||
PyObject_GC_UnTrack(self);
|
||||
Py_XDECREF(self->ctx);
|
||||
if (self->session != NULL) {
|
||||
|
|
|
@ -1605,6 +1605,8 @@ typedef struct {
|
|||
static void
|
||||
unpackiter_dealloc(unpackiterobject *self)
|
||||
{
|
||||
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
||||
PyObject_GC_UnTrack(self);
|
||||
Py_XDECREF(self->so);
|
||||
PyBuffer_Release(&self->buf);
|
||||
PyObject_GC_Del(self);
|
||||
|
|
|
@ -2006,6 +2006,8 @@ dict_dealloc(PyDictObject *mp)
|
|||
PyObject **values = mp->ma_values;
|
||||
PyDictKeysObject *keys = mp->ma_keys;
|
||||
Py_ssize_t i, n;
|
||||
|
||||
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
||||
PyObject_GC_UnTrack(mp);
|
||||
Py_TRASHCAN_SAFE_BEGIN(mp)
|
||||
if (values != NULL) {
|
||||
|
@ -3432,6 +3434,8 @@ dictiter_new(PyDictObject *dict, PyTypeObject *itertype)
|
|||
static void
|
||||
dictiter_dealloc(dictiterobject *di)
|
||||
{
|
||||
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
||||
_PyObject_GC_UNTRACK(di);
|
||||
Py_XDECREF(di->di_dict);
|
||||
Py_XDECREF(di->di_result);
|
||||
PyObject_GC_Del(di);
|
||||
|
@ -3800,6 +3804,8 @@ dictiter_reduce(dictiterobject *di)
|
|||
static void
|
||||
dictview_dealloc(_PyDictViewObject *dv)
|
||||
{
|
||||
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
||||
_PyObject_GC_UNTRACK(dv);
|
||||
Py_XDECREF(dv->dv_dict);
|
||||
PyObject_GC_Del(dv);
|
||||
}
|
||||
|
|
|
@ -556,6 +556,7 @@ set_dealloc(PySetObject *so)
|
|||
setentry *entry;
|
||||
Py_ssize_t used = so->used;
|
||||
|
||||
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
||||
PyObject_GC_UnTrack(so);
|
||||
Py_TRASHCAN_SAFE_BEGIN(so)
|
||||
if (so->weakreflist != NULL)
|
||||
|
@ -812,6 +813,8 @@ typedef struct {
|
|||
static void
|
||||
setiter_dealloc(setiterobject *si)
|
||||
{
|
||||
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
||||
_PyObject_GC_UNTRACK(si);
|
||||
Py_XDECREF(si->si_set);
|
||||
PyObject_GC_Del(si);
|
||||
}
|
||||
|
|
|
@ -630,6 +630,8 @@ typedef struct {
|
|||
static void
|
||||
ast_dealloc(AST_object *self)
|
||||
{
|
||||
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
||||
PyObject_GC_UnTrack(self);
|
||||
Py_CLEAR(self->dict);
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
}
|
||||
|
|
|
@ -512,6 +512,8 @@ typedef struct {
|
|||
static void
|
||||
ast_dealloc(AST_object *self)
|
||||
{
|
||||
/* bpo-31095: UnTrack is needed before calling any callbacks */
|
||||
PyObject_GC_UnTrack(self);
|
||||
Py_CLEAR(self->dict);
|
||||
Py_TYPE(self)->tp_free(self);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue