diff options
author | Nick Wellnhofer <wellnhofer@aevum.de> | 2019-09-23 17:13:05 +0200 |
---|---|---|
committer | Nick Wellnhofer <wellnhofer@aevum.de> | 2019-09-23 17:46:32 +0200 |
commit | 1fbcf4098ba2aefe241de8d7ceb229b995d8daec (patch) | |
tree | a10a9d4cb89067b1b008a9fe01fa2ab77d33ebae | |
parent | 0762c9b69ba01628f72eada1c64ff3d361fb5716 (diff) | |
download | libxml2-1fbcf4098ba2aefe241de8d7ceb229b995d8daec.tar.gz |
Make xmlTextReaderFreeNodeList non-recursive
Avoid call stack overflow when freeing deeply nested documents.
Found by OSS-Fuzz.
-rw-r--r-- | xmlreader.c | 32 |
1 files 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; + } } } |