summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorJeroen Demeyer <J.Demeyer@UGent.be>2019-05-10 17:21:11 (GMT)
committerAntoine Pitrou <antoine@python.org>2019-05-10 17:21:10 (GMT)
commit351c67416ba4451eb3928fa0b2e933c2f25df1a3 (patch)
tree5054fe93291fa93533ddd97622f329e96a31847e /Modules
parenta2fedd8c910cb5f5b9bd568d6fd44d63f8f5cfa5 (diff)
downloadcpython-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.c4
-rw-r--r--Modules/_testcapimodule.c76
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);