From 1fbcf4098ba2aefe241de8d7ceb229b995d8daec Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Mon, 23 Sep 2019 17:13:05 +0200
Subject: [PATCH 3/3] 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 d715071..9229c18 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;
+        }
     }
 }
 
-- 
1.7.12.4

