From 1fbcf4098ba2aefe241de8d7ceb229b995d8daec Mon Sep 17 00:00:00 2001 From: Nick Wellnhofer Date: Mon, 23 Sep 2019 17:13:05 +0200 Subject: [PATCH] Make xmlTextReaderFreeNodeList non-recursive Avoid call stack overflow when freeing deeply nested documents. Found by OSS-Fuzz. --- xmlreader.c | 32 +++++++++++++++++++++++--------- 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/xmlreader.c b/xmlreader.c index d7150710..9229c18c 100644 --- a/xmlreader.c +++ b/xmlreader.c @@ -348,7 +348,9 @@ xmlTextReaderFreePropList(xmlTextReaderPtr reader, xmlAttrPtr cur) { static void xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur) { xmlNodePtr next; + xmlNodePtr parent; xmlDictPtr dict; + size_t depth = 0; if ((reader != NULL) && (reader->ctxt != NULL)) dict = reader->ctxt->dict; @@ -364,18 +366,21 @@ xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur) { xmlFreeDoc((xmlDocPtr) cur); 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; + parent = cur->parent; + /* unroll to speed up freeing the document */ 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)) xmlDeregisterNodeDefaultValue(cur); @@ -414,7 +419,16 @@ xmlTextReaderFreeNodeList(xmlTextReaderPtr reader, xmlNodePtr cur) { xmlFree(cur); } } - cur = next; + + if (next != NULL) { + cur = next; + } else { + if ((depth == 0) || (parent == NULL)) + break; + depth -= 1; + cur = parent; + cur->children = NULL; + } } }