diff options
author | Jeroen Demeyer <J.Demeyer@UGent.be> | 2019-05-10 17:21:11 (GMT) |
---|---|---|
committer | Antoine Pitrou <antoine@python.org> | 2019-05-10 17:21:10 (GMT) |
commit | 351c67416ba4451eb3928fa0b2e933c2f25df1a3 (patch) | |
tree | 5054fe93291fa93533ddd97622f329e96a31847e /Modules | |
parent | a2fedd8c910cb5f5b9bd568d6fd44d63f8f5cfa5 (diff) | |
download | cpython-351c67416ba4451eb3928fa0b2e933c2f25df1a3.zip cpython-351c67416ba4451eb3928fa0b2e933c2f25df1a3.tar.gz cpython-351c67416ba4451eb3928fa0b2e933c2f25df1a3.tar.bz2 |
bpo-35983: skip trashcan for subclasses (GH-11841)
Add new trashcan macros to deal with a double deallocation that could occur when the `tp_dealloc` of a subclass calls the `tp_dealloc` of a base class and that base class uses the trashcan mechanism.
Patch by Jeroen Demeyer.
Diffstat (limited to 'Modules')
-rw-r--r-- | Modules/_elementtree.c | 4 | ||||
-rw-r--r-- | Modules/_testcapimodule.c | 76 |
2 files changed, 78 insertions, 2 deletions
diff --git a/Modules/_elementtree.c b/Modules/_elementtree.c index e9a0ea2..f5fc443 100644 --- a/Modules/_elementtree.c +++ b/Modules/_elementtree.c @@ -669,7 +669,7 @@ element_dealloc(ElementObject* self) { /* bpo-31095: UnTrack is needed before calling any callbacks */ PyObject_GC_UnTrack(self); - Py_TRASHCAN_SAFE_BEGIN(self) + Py_TRASHCAN_BEGIN(self, element_dealloc) if (self->weakreflist != NULL) PyObject_ClearWeakRefs((PyObject *) self); @@ -680,7 +680,7 @@ element_dealloc(ElementObject* self) RELEASE(sizeof(ElementObject), "destroy element"); Py_TYPE(self)->tp_free((PyObject *)self); - Py_TRASHCAN_SAFE_END(self) + Py_TRASHCAN_END } /* -------------------------------------------------------------------- */ diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c index c52e349..04d75ac 100644 --- a/Modules/_testcapimodule.c +++ b/Modules/_testcapimodule.c @@ -5451,6 +5451,76 @@ recurse_infinitely_error_init(PyObject *self, PyObject *args, PyObject *kwds) } +/* Test bpo-35983: create a subclass of "list" which checks that instances + * are not deallocated twice */ + +typedef struct { + PyListObject list; + int deallocated; +} MyListObject; + +static PyObject * +MyList_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +{ + PyObject* op = PyList_Type.tp_new(type, args, kwds); + ((MyListObject*)op)->deallocated = 0; + return op; +} + +void +MyList_dealloc(MyListObject* op) +{ + if (op->deallocated) { + /* We cannot raise exceptions here but we still want the testsuite + * to fail when we hit this */ + Py_FatalError("MyList instance deallocated twice"); + } + op->deallocated = 1; + PyList_Type.tp_dealloc((PyObject *)op); +} + +static PyTypeObject MyList_Type = { + PyVarObject_HEAD_INIT(NULL, 0) + "MyList", + sizeof(MyListObject), + 0, + (destructor)MyList_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* &PyList_Type */ /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + MyList_new, /* tp_new */ +}; + + /* Test PEP 560 */ typedef struct { @@ -5564,6 +5634,12 @@ PyInit__testcapi(void) Py_INCREF(&awaitType); PyModule_AddObject(m, "awaitType", (PyObject *)&awaitType); + MyList_Type.tp_base = &PyList_Type; + if (PyType_Ready(&MyList_Type) < 0) + return NULL; + Py_INCREF(&MyList_Type); + PyModule_AddObject(m, "MyList", (PyObject *)&MyList_Type); + if (PyType_Ready(&GenericAlias_Type) < 0) return NULL; Py_INCREF(&GenericAlias_Type); |