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);
|
Py_INCREF(self);
|
||||||
it->root_element = self;
|
it->root_element = self;
|
||||||
|
|
||||||
PyObject_GC_Track(it);
|
|
||||||
|
|
||||||
it->parent_stack = PyMem_New(ParentLocator, INIT_PARENT_STACK_SIZE);
|
it->parent_stack = PyMem_New(ParentLocator, INIT_PARENT_STACK_SIZE);
|
||||||
if (it->parent_stack == NULL) {
|
if (it->parent_stack == NULL) {
|
||||||
Py_DECREF(it);
|
Py_DECREF(it);
|
||||||
|
@ -2328,6 +2326,8 @@ create_elementiter(ElementObject *self, PyObject *tag, int gettext)
|
||||||
it->parent_stack_used = 0;
|
it->parent_stack_used = 0;
|
||||||
it->parent_stack_size = INIT_PARENT_STACK_SIZE;
|
it->parent_stack_size = INIT_PARENT_STACK_SIZE;
|
||||||
|
|
||||||
|
PyObject_GC_Track(it);
|
||||||
|
|
||||||
return (PyObject *)it;
|
return (PyObject *)it;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1922,6 +1922,18 @@ _PyGC_Dump(PyGC_Head *g)
|
||||||
_PyObject_Dump(FROM_GC(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
|
/* extension modules might be compiled with GC support so these
|
||||||
functions must always be available */
|
functions must always be available */
|
||||||
|
|
||||||
|
@ -1935,6 +1947,13 @@ PyObject_GC_Track(void *op_raw)
|
||||||
"by the garbage collector");
|
"by the garbage collector");
|
||||||
}
|
}
|
||||||
_PyObject_GC_TRACK(op);
|
_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
|
void
|
||||||
|
|
|
@ -938,7 +938,6 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
|
||||||
new_parser->handlers = 0;
|
new_parser->handlers = 0;
|
||||||
new_parser->intern = self->intern;
|
new_parser->intern = self->intern;
|
||||||
Py_XINCREF(new_parser->intern);
|
Py_XINCREF(new_parser->intern);
|
||||||
PyObject_GC_Track(new_parser);
|
|
||||||
|
|
||||||
if (self->buffer != NULL) {
|
if (self->buffer != NULL) {
|
||||||
new_parser->buffer = PyMem_Malloc(new_parser->buffer_size);
|
new_parser->buffer = PyMem_Malloc(new_parser->buffer_size);
|
||||||
|
@ -975,6 +974,8 @@ pyexpat_xmlparser_ExternalEntityParserCreate_impl(xmlparseobject *self,
|
||||||
handler_info[i].handler);
|
handler_info[i].handler);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PyObject_GC_Track(new_parser);
|
||||||
return (PyObject *)new_parser;
|
return (PyObject *)new_parser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1122,7 +1123,6 @@ newxmlparseobject(const char *encoding, const char *namespace_separator, PyObjec
|
||||||
self->handlers = NULL;
|
self->handlers = NULL;
|
||||||
self->intern = intern;
|
self->intern = intern;
|
||||||
Py_XINCREF(self->intern);
|
Py_XINCREF(self->intern);
|
||||||
PyObject_GC_Track(self);
|
|
||||||
|
|
||||||
/* namespace_separator is either NULL or contains one char + \0 */
|
/* namespace_separator is either NULL or contains one char + \0 */
|
||||||
self->itself = XML_ParserCreate_MM(encoding, &ExpatMemoryHandler,
|
self->itself = XML_ParserCreate_MM(encoding, &ExpatMemoryHandler,
|
||||||
|
@ -1152,6 +1152,7 @@ newxmlparseobject(const char *encoding, const char *namespace_separator, PyObjec
|
||||||
}
|
}
|
||||||
clear_handlers(self, 1);
|
clear_handlers(self, 1);
|
||||||
|
|
||||||
|
PyObject_GC_Track(self);
|
||||||
return (PyObject*)self;
|
return (PyObject*)self;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue