1
0
mirror of https://gitlab.gnome.org/GNOME/libxml2.git synced 2025-10-26 00:37:43 +03:00

Make xmlTextReaderFreeNodeList non-recursive

Avoid call stack overflow when freeing deeply nested documents.

Found by OSS-Fuzz.
This commit is contained in:
Nick Wellnhofer
2019-09-23 17:13:05 +02:00
parent 0762c9b69b
commit 1fbcf4098b

View File

@@ -348,7 +348,9 @@ xmlTextReaderFreePropList(xmlTextReaderPtr reader, xmlAttrPtr cur) {
static void static void
xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur) { xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur) {
xmlNodePtr next; xmlNodePtr next;
xmlNodePtr parent;
xmlDictPtr dict; xmlDictPtr dict;
size_t depth = 0;
if ((reader != NULL) && (reader->ctxt != NULL)) if ((reader != NULL) && (reader->ctxt != NULL))
dict = reader->ctxt->dict; dict = reader->ctxt->dict;
@@ -364,18 +366,21 @@ xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur) {
xmlFreeDoc((xmlDocPtr) cur); xmlFreeDoc((xmlDocPtr) cur);
return; return;
} }
while (cur != NULL) { while (1) {
while ((cur->children != NULL) &&
(cur->children->parent == cur) &&
(cur->type != XML_DTD_NODE) &&
(cur->type != XML_ENTITY_REF_NODE)) {
cur = cur->children;
depth += 1;
}
next = cur->next; next = cur->next;
parent = cur->parent;
/* unroll to speed up freeing the document */ /* unroll to speed up freeing the document */
if (cur->type != XML_DTD_NODE) { if (cur->type != XML_DTD_NODE) {
if ((cur->children != NULL) &&
(cur->type != XML_ENTITY_REF_NODE)) {
if (cur->children->parent == cur)
xmlTextReaderFreeNodeList(reader, cur->children);
cur->children = NULL;
}
if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue)) if ((__xmlRegisterCallbacks) && (xmlDeregisterNodeDefaultValue))
xmlDeregisterNodeDefaultValue(cur); xmlDeregisterNodeDefaultValue(cur);
@@ -414,7 +419,16 @@ xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur) {
xmlFree(cur); xmlFree(cur);
} }
} }
cur = next;
if (next != NULL) {
cur = next;
} else {
if ((depth == 0) || (parent == NULL))
break;
depth -= 1;
cur = parent;
cur->children = NULL;
}
} }
} }