From de5b624f10e9d29ff1b3bbc07358774a3725898e Mon Sep 17 00:00:00 2001
From: Nick Wellnhofer <wellnhofer@aevum.de>
Date: Sat, 8 May 2021 20:21:29 +0200
Subject: [PATCH] Fix handling of unexpected EOF in xmlParseContent

Readd the XML_ERR_TAG_NOT_FINISHED error on unexpected EOF which was
removed in commit 62150ed2.

This commit also introduced a regression for direct users of
xmlParseContent. Unclosed tags weren't checked.
---
 parser.c                     | 48 +++++++++++++++++++++++++++++++++++++-------
 python/tests/tstLastError.py |  4 ++--
 result/errors/754947.xml.err |  2 +-
 3 files changed, 44 insertions(+), 10 deletions(-)

diff --git a/parser.c b/parser.c
index c2948ca..dd58282 100644
--- a/parser.c
+++ b/parser.c
@@ -9837,16 +9837,15 @@ xmlParseCDSect(xmlParserCtxtPtr ctxt) {
 }
 
 /**
- * xmlParseContent:
+ * xmlParseContentInternal:
  * @ctxt:  an XML parser context
  *
- * Parse a content:
- *
- * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
+ * Parse a content sequence. Stops at EOF or '</'. Leaves checking of
+ * unexpected EOF to the caller.
  */
 
-void
-xmlParseContent(xmlParserCtxtPtr ctxt) {
+static void
+xmlParseContentInternal(xmlParserCtxtPtr ctxt) {
     int nameNr = ctxt->nameNr;
 
     GROW;
@@ -9922,6 +9921,30 @@ xmlParseContent(xmlParserCtxtPtr ctxt) {
 }
 
 /**
+ * xmlParseContent:
+ * @ctxt:  an XML parser context
+ *
+ * Parse a content sequence. Stops at EOF or '</'.
+ *
+ * [43] content ::= (element | CharData | Reference | CDSect | PI | Comment)*
+ */
+
+void
+xmlParseContent(xmlParserCtxtPtr ctxt) {
+    int nameNr = ctxt->nameNr;
+
+    xmlParseContentInternal(ctxt);
+
+    if ((ctxt->instate != XML_PARSER_EOF) && (ctxt->nameNr > nameNr)) {
+        const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1];
+        int line = (ptrdiff_t) ctxt->pushTab[ctxt->nameNr * 4 - 2];
+        xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED,
+                "Premature end of data in tag %s line %d\n",
+		name, line, NULL);
+    }
+}
+
+/**
  * xmlParseElement:
  * @ctxt:  an XML parser context
  *
@@ -9939,9 +9962,20 @@ void
 xmlParseElement(xmlParserCtxtPtr ctxt) {
     if (xmlParseElementStart(ctxt) != 0)
         return;
-    xmlParseContent(ctxt);
+
+    xmlParseContentInternal(ctxt);
     if (ctxt->instate == XML_PARSER_EOF)
 	return;
+
+    if (CUR == 0) {
+        const xmlChar *name = ctxt->nameTab[ctxt->nameNr - 1];
+        int line = (ptrdiff_t) ctxt->pushTab[ctxt->nameNr * 4 - 2];
+        xmlFatalErrMsgStrIntStr(ctxt, XML_ERR_TAG_NOT_FINISHED,
+                "Premature end of data in tag %s line %d\n",
+		name, line, NULL);
+        return;
+    }
+
     xmlParseElementEnd(ctxt);
 }
 
diff --git a/python/tests/tstLastError.py b/python/tests/tstLastError.py
index 1758a9f..36ffe5f 100755
--- a/python/tests/tstLastError.py
+++ b/python/tests/tstLastError.py
@@ -71,8 +71,8 @@ class TestCase(unittest.TestCase):
                         (s,len(s),"dummy.xml",None,0),
                         libxml2.treeError,
                         domain=libxml2.XML_FROM_PARSER,
-                        code=libxml2.XML_ERR_LTSLASH_REQUIRED,
-                        message='EndTag: \'</\' not found\n',
+                        code=libxml2.XML_ERR_TAG_NOT_FINISHED,
+                        message='Premature end of data in tag x line 1\n',
                         level=libxml2.XML_ERR_FATAL,
                         file='dummy.xml',
                         line=3)
diff --git a/result/errors/754947.xml.err b/result/errors/754947.xml.err
index 51e9b4e..f45cb5a 100644
--- a/result/errors/754947.xml.err
+++ b/result/errors/754947.xml.err
@@ -2,6 +2,6 @@
 Bytes: 0xEE 0x5D 0x5D 0x3E
 <d><![CDATA[0000000000000î]]>
                          ^
-./test/errors/754947.xml:1: parser error : EndTag: '</' not found
+./test/errors/754947.xml:1: parser error : Premature end of data in tag d line 1
 <d><![CDATA[0000000000000î]]>
                              ^
-- 
1.8.3.1

