bpo-38392: PyObject_GC_Track() validates object in debug mode (GH-16615)
In debug mode, PyObject_GC_Track() now calls tp_traverse() of the object type to ensure that the object is valid: test that objects visited by tp_traverse() are valid. Fix pyexpat.c: only track the parser in the GC once the parser is fully initialized.
This commit is contained in:
parent
7775349895
commit
1b18455695
|
@ -0,0 +1,3 @@
|
|||
In debug mode, :c:func:`PyObject_GC_Track` now calls ``tp_traverse()`` of
|
||||
the object type to ensure that the object is valid: test that objects
|
||||
visited by ``tp_traverse()`` are valid.
|
|
@ -2317,8 +2317,6 @@ create_elementiter(ElementObject *self, PyObject *tag, int gettext)
|
|||
Py_INCREF(self);
|
||||
it->root_element = self;
|
||||
|
||||
PyObject_GC_Track(it);
|
||||
|
||||
it->parent_stack = PyMem_New(ParentLocator, INIT_PARENT_STACK_SIZE);
|
||||
if (it->parent_stack == NULL) {
|
||||
Py_DECREF(it);
|
||||
|
@ -2328,6 +2326,8 @@ create_elementiter(ElementObject *self, PyObject *tag, int gettext)
|
|||
it->parent_stack_used = 0;
|
||||
it->parent_stack_size = INIT_PARENT_STACK_SIZE;
|
||||
|
||||
PyObject_GC_Track(it);
|
||||
|
||||
return (PyObject *)it;
|
||||
}
|
||||
|
||||
|
|
|
@ -1922,6 +1922,18 @@ _PyGC_Dump(PyGC_Head *g)
|
|||
_PyObject_Dump(FROM_GC(g));
|
||||
}
|
||||
|
||||
static int
|
||||
visit_validate(PyObject *op, void *parent_raw)
|
||||
{
|
||||
PyObject *parent = _PyObject_CAST(parent_raw);
|
||||
if (_PyObject_IsFreed(op)) {
|
||||
_PyObject_ASSERT_FAILED_MSG(parent,
|
||||
"PyObject_GC_Track() object is not valid");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* extension modules might be compiled with GC support so these
|
||||
functions must always be available */
|
||||
|
||||
|
@ -1935,6 +1947,13 @@ PyObject_GC_Track(void *op_raw)
|
|||
"by the garbage collector");
|
||||
}
|
||||
_PyObject_GC_TRACK(op);
|
||||
|
||||
#ifdef Py_DEBUG
|
||||
/* Check that the object is valid: validate objects traversed
|
||||
by tp_traverse() */
|
||||
traverseproc traverse = Py_TYPE(op)->tp_traverse;
|
||||
(void)traverse(op, visit_validate, op);
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
|
|
|
@ -938,7 +938,6 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
|
|||
new_parser->handlers = 0;
|
||||
new_parser->intern = self->intern;
|
||||
Py_XINCREF(new_parser->intern);
|
||||
PyObject_GC_Track(new_parser);
|
||||
|
||||
if (self->buffer != NULL) {
|
||||
new_parser->buffer = PyMem_Malloc(new_parser->buffer_size);
|
||||
|
@ -975,6 +974,8 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
|
|||
handler_info[i].handler);
|
||||
}
|
||||
}
|
||||
|
||||
PyObject_GC_Track(new_parser);
|
||||
return (PyObject *)new_parser;
|
||||
}
|
||||
|
||||
|
@ -1122,7 +1123,6 @@ newxmlparseobject(const char *encoding, const char *namespace_separator, PyObjec
|
|||
self->handlers = NULL;
|
||||
self->intern = intern;
|
||||
Py_XINCREF(self->intern);
|
||||
PyObject_GC_Track(self);
|
||||
|
||||
/* namespace_separator is either NULL or contains one char + \0 */
|
||||
self->itself = XML_ParserCreate_MM(encoding, &ExpatMemoryHandler,
|
||||
|
@ -1152,6 +1152,7 @@ newxmlparseobject(const char *encoding, const char *namespace_separator, PyObjec
|
|||
}
|
||||
clear_handlers(self, 1);
|
||||
|
||||
PyObject_GC_Track(self);
|
||||
return (PyObject*)self;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue