Merge "Upgrade libxml2 to 7d6837ba0e282e94eb8630ad791f427e44a57491"
diff --git a/HTMLtree.c b/HTMLtree.c
index cdb7f86..8d0c779 100644
--- a/HTMLtree.c
+++ b/HTMLtree.c
@@ -903,6 +903,12 @@
                 break;
             }
 
+            /*
+             * The parent should never be NULL here but we want to handle
+             * corrupted documents gracefully.
+             */
+            if (cur->parent == NULL)
+                return;
             cur = cur->parent;
 
             if ((cur->type == XML_HTML_DOCUMENT_NODE) ||
diff --git a/METADATA b/METADATA
index 71cd842..4335be1 100644
--- a/METADATA
+++ b/METADATA
@@ -7,13 +7,13 @@
   }
   url {
     type: ARCHIVE
-    value: "https://github.com/GNOME/libxml2/archive/f0fd1b67fc883a24cdd039abb3d4fe4696104d72.zip"
+    value: "https://github.com/GNOME/libxml2/archive/7d6837ba0e282e94eb8630ad791f427e44a57491.zip"
   }
-  version: "f0fd1b67fc883a24cdd039abb3d4fe4696104d72"
+  version: "7d6837ba0e282e94eb8630ad791f427e44a57491"
   license_type: NOTICE
   last_upgrade_date {
     year: 2020
-    month: 9
-    day: 1
+    month: 10
+    day: 28
   }
 }
diff --git a/Makefile.am b/Makefile.am
index 76a834e..0655dfd 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -4,7 +4,7 @@
 
 SUBDIRS = include . doc example fuzz xstc $(PYTHON_SUBDIR)
 
-DIST_SUBDIRS = include . doc example python xstc
+DIST_SUBDIRS = include . doc example fuzz python xstc
 
 AM_CPPFLAGS = -I$(top_builddir)/include -I$(srcdir)/include
 
diff --git a/fuzz/Makefile.am b/fuzz/Makefile.am
index 49b9554..2bbdbb1 100644
--- a/fuzz/Makefile.am
+++ b/fuzz/Makefile.am
@@ -1,6 +1,8 @@
 AUTOMAKE_OPTIONS = -Wno-syntax
 EXTRA_PROGRAMS = genSeed html regexp schema uri xml xpath
 check_PROGRAMS = testFuzzer
+EXTRA_DIST = html.dict regexp.dict schema.dict xml.dict xpath.dict \
+	     seed/uri
 CLEANFILES = $(EXTRA_PROGRAMS)
 AM_CPPFLAGS = -I$(top_srcdir)/include
 DEPENDENCIES = $(top_builddir)/libxml2.la
diff --git a/parser.c b/parser.c
index be14c32..85494df 100644
--- a/parser.c
+++ b/parser.c
@@ -4506,7 +4506,7 @@
             if (ctxt->instate == XML_PARSER_EOF)
 		return;
 	    in = ctxt->input->cur;
-	} while (((*in >= 0x20) && (*in <= 0x7F)) || (*in == 0x09));
+	} while (((*in >= 0x20) && (*in <= 0x7F)) || (*in == 0x09) || (*in == 0x0a));
 	nbchar = 0;
     }
     ctxt->input->line = line;
@@ -4987,7 +4987,7 @@
 	    ctxt->input->col++;
 	    goto get_more;
 	}
-    } while (((*in >= 0x20) && (*in <= 0x7F)) || (*in == 0x09));
+    } while (((*in >= 0x20) && (*in <= 0x7F)) || (*in == 0x09) || (*in == 0x0a));
     xmlParseCommentComplex(ctxt, buf, len, size);
     ctxt->instate = state;
     return;
@@ -14077,7 +14077,7 @@
 
     if ((ctxt->wellFormed) || recovery) {
         ret = ctxt->myDoc;
-	if (ret != NULL) {
+	if ((ret != NULL) && (ctxt->input->buf != NULL)) {
 	    if (ctxt->input->buf->compressed > 0)
 		ret->compression = 9;
 	    else
diff --git a/uri.c b/uri.c
index 91c4619..7e9a9f4 100644
--- a/uri.c
+++ b/uri.c
@@ -11,6 +11,7 @@
 #define IN_LIBXML
 #include "libxml.h"
 
+#include <limits.h>
 #include <string.h>
 
 #include <libxml/xmlmemory.h>
@@ -329,9 +330,14 @@
 
     if (ISA_DIGIT(cur)) {
 	while (ISA_DIGIT(cur)) {
-	    port = port * 10 + (*cur - '0');
-            if (port > 99999999)
-                port = 99999999;
+            int digit = *cur - '0';
+
+            if (port > INT_MAX / 10)
+                return(1);
+            port *= 10;
+            if (port > INT_MAX - digit)
+                return(1);
+	    port += digit;
 
 	    cur++;
 	}
diff --git a/win32/configure.js b/win32/configure.js
index e2ab31d..cec64c5 100644
--- a/win32/configure.js
+++ b/win32/configure.js
@@ -208,15 +208,15 @@
 	while (cf.AtEndOfStream != true) {
 		ln = cf.ReadLine();
 		s = new String(ln);
-		if (s.search(/^LIBXML_MAJOR_VERSION=/) != -1) {
-			vf.WriteLine(s);
-			verMajor = s.substring(s.indexOf("=") + 1, s.length);
-		} else if(s.search(/^LIBXML_MINOR_VERSION=/) != -1) {
-			vf.WriteLine(s);
-			verMinor = s.substring(s.indexOf("=") + 1, s.length);
-		} else if(s.search(/^LIBXML_MICRO_VERSION=/) != -1) {
-			vf.WriteLine(s);
-			verMicro = s.substring(s.indexOf("=") + 1, s.length);
+		if (m = s.match(/^m4_define\(\[MAJOR_VERSION\], (\w+)\)/)) {
+			vf.WriteLine("LIBXML_MAJOR_VERSION=" + m[1]);
+			verMajor = m[1];
+		} else if(m = s.match(/^m4_define\(\[MINOR_VERSION\], (\w+)\)/)) {
+			vf.WriteLine("LIBXML_MINOR_VERSION=" + m[1]);
+			verMinor = m[1];
+		} else if(m = s.match(/^m4_define\(\[MICRO_VERSION\], (\w+)\)/)) {
+			vf.WriteLine("LIBXML_MICRO_VERSION=" + m[1]);
+			verMicro = m[1];
 		} else if(s.search(/^LIBXML_MICRO_VERSION_SUFFIX=/) != -1) {
 			vf.WriteLine(s);
 			verMicroSuffix = s.substring(s.indexOf("=") + 1, s.length);
diff --git a/xinclude.c b/xinclude.c
index f48e0af..1636caf 100644
--- a/xinclude.c
+++ b/xinclude.c
@@ -72,7 +72,7 @@
 
     int                 txtNr; /* number of unparsed documents */
     int                txtMax; /* size of unparsed documents tab */
-    xmlNodePtr        *txtTab; /* array of unparsed text nodes */
+    xmlChar *         *txtTab; /* array of unparsed text strings */
     xmlURL         *txturlTab; /* array of unparsed text URLs */
 
     xmlChar *             url; /* the current URL processed */
@@ -393,18 +393,22 @@
 	if (ctxt->incTab[i] != NULL)
 	    xmlXIncludeFreeRef(ctxt->incTab[i]);
     }
+    if (ctxt->incTab != NULL)
+	xmlFree(ctxt->incTab);
+    if (ctxt->txtTab != NULL) {
+	for (i = 0;i < ctxt->txtNr;i++) {
+	    if (ctxt->txtTab[i] != NULL)
+		xmlFree(ctxt->txtTab[i]);
+	}
+	xmlFree(ctxt->txtTab);
+    }
     if (ctxt->txturlTab != NULL) {
 	for (i = 0;i < ctxt->txtNr;i++) {
 	    if (ctxt->txturlTab[i] != NULL)
 		xmlFree(ctxt->txturlTab[i]);
 	}
-    }
-    if (ctxt->incTab != NULL)
-	xmlFree(ctxt->incTab);
-    if (ctxt->txtTab != NULL)
-	xmlFree(ctxt->txtTab);
-    if (ctxt->txturlTab != NULL)
 	xmlFree(ctxt->txturlTab);
+    }
     if (ctxt->base != NULL) {
         xmlFree(ctxt->base);
     }
@@ -764,13 +768,14 @@
  * Add a new text node to the list
  */
 static void
-xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, xmlNodePtr txt, const xmlURL url) {
+xmlXIncludeAddTxt(xmlXIncludeCtxtPtr ctxt, const xmlChar *txt,
+                  const xmlURL url) {
 #ifdef DEBUG_XINCLUDE
     xmlGenericError(xmlGenericErrorContext, "Adding text %s\n", url);
 #endif
     if (ctxt->txtMax == 0) {
 	ctxt->txtMax = 4;
-        ctxt->txtTab = (xmlNodePtr *) xmlMalloc(ctxt->txtMax *
+        ctxt->txtTab = (xmlChar **) xmlMalloc(ctxt->txtMax *
 		                          sizeof(ctxt->txtTab[0]));
         if (ctxt->txtTab == NULL) {
 	    xmlXIncludeErrMemory(ctxt, NULL, "processing text");
@@ -785,7 +790,7 @@
     }
     if (ctxt->txtNr >= ctxt->txtMax) {
 	ctxt->txtMax *= 2;
-        ctxt->txtTab = (xmlNodePtr *) xmlRealloc(ctxt->txtTab,
+        ctxt->txtTab = (xmlChar **) xmlRealloc(ctxt->txtTab,
 	             ctxt->txtMax * sizeof(ctxt->txtTab[0]));
         if (ctxt->txtTab == NULL) {
 	    xmlXIncludeErrMemory(ctxt, NULL, "processing text");
@@ -798,7 +803,7 @@
 	    return;
 	}
     }
-    ctxt->txtTab[ctxt->txtNr] = txt;
+    ctxt->txtTab[ctxt->txtNr] = xmlStrdup(txt);
     ctxt->txturlTab[ctxt->txtNr] = xmlStrdup(url);
     ctxt->txtNr++;
 }
@@ -1845,7 +1850,7 @@
      */
     for (i = 0; i < ctxt->txtNr; i++) {
 	if (xmlStrEqual(URL, ctxt->txturlTab[i])) {
-	    node = xmlCopyNode(ctxt->txtTab[i], 1);
+            node = xmlNewText(ctxt->txtTab[i]);
 	    goto loaded;
 	}
     }
@@ -1935,7 +1940,7 @@
 	xmlBufShrink(buf->buffer, len);
     }
     xmlFreeParserCtxt(pctxt);
-    xmlXIncludeAddTxt(ctxt, node, URL);
+    xmlXIncludeAddTxt(ctxt, node->content, URL);
     xmlFreeInputStream(inputStream);
 
 loaded:
diff --git a/xmlreader.c b/xmlreader.c
index a9b9ef9..01adf74 100644
--- a/xmlreader.c
+++ b/xmlreader.c
@@ -359,12 +359,12 @@
 	xmlDeregisterNodeDefaultValue((xmlNodePtr) cur);
 
     /* Check for ID removal -> leading to invalid references ! */
-    if ((cur->parent != NULL) && (cur->parent->doc != NULL) &&
-	((cur->parent->doc->intSubset != NULL) ||
-	 (cur->parent->doc->extSubset != NULL))) {
+    if ((cur->parent != NULL) && (cur->parent->doc != NULL)) {
         if (xmlIsID(cur->parent->doc, cur->parent, cur))
 	    xmlTextReaderRemoveID(cur->parent->doc, cur);
-        if (xmlIsRef(cur->parent->doc, cur->parent, cur))
+	if (((cur->parent->doc->intSubset != NULL) ||
+	     (cur->parent->doc->extSubset != NULL)) &&
+            (xmlIsRef(cur->parent->doc, cur->parent, cur)))
             xmlTextReaderRemoveRef(cur->parent->doc, cur);
     }
     if (cur->children != NULL)
diff --git a/xmlregexp.c b/xmlregexp.c
index f971f0c..40dabb2 100644
--- a/xmlregexp.c
+++ b/xmlregexp.c
@@ -5155,7 +5155,7 @@
 	} else {
 	    xmlFAParseCharRange(ctxt);
 	}
-    } while ((CUR != ']') && (CUR != '^') && (CUR != '-') &&
+    } while ((CUR != ']') && (CUR != '-') &&
              (CUR != 0) && (ctxt->error == 0));
 }
 
@@ -5170,34 +5170,31 @@
  */
 static void
 xmlFAParseCharGroup(xmlRegParserCtxtPtr ctxt) {
-    int n = ctxt->neg;
-    while ((CUR != ']') && (ctxt->error == 0)) {
-	if (CUR == '^') {
-	    int neg = ctxt->neg;
+    int neg = ctxt->neg;
 
-	    NEXT;
-	    ctxt->neg = !ctxt->neg;
-	    xmlFAParsePosCharGroup(ctxt);
-	    ctxt->neg = neg;
-	} else if ((CUR == '-') && (NXT(1) == '[')) {
-	    int neg = ctxt->neg;
-	    ctxt->neg = 2;
+    if (CUR == '^') {
+	NEXT;
+	ctxt->neg = !ctxt->neg;
+	xmlFAParsePosCharGroup(ctxt);
+	ctxt->neg = neg;
+    }
+    while ((CUR != ']') && (ctxt->error == 0)) {
+	if ((CUR == '-') && (NXT(1) == '[')) {
 	    NEXT;	/* eat the '-' */
 	    NEXT;	/* eat the '[' */
+	    ctxt->neg = 2;
 	    xmlFAParseCharGroup(ctxt);
+	    ctxt->neg = neg;
 	    if (CUR == ']') {
 		NEXT;
 	    } else {
 		ERROR("charClassExpr: ']' expected");
-		break;
 	    }
-	    ctxt->neg = neg;
 	    break;
-	} else if (CUR != ']') {
+	} else {
 	    xmlFAParsePosCharGroup(ctxt);
 	}
     }
-    ctxt->neg = n;
 }
 
 /**
diff --git a/xmlsave.c b/xmlsave.c
index 2225628..61a4045 100644
--- a/xmlsave.c
+++ b/xmlsave.c
@@ -1058,6 +1058,12 @@
                 break;
             }
 
+            /*
+             * The parent should never be NULL here but we want to handle
+             * corrupted documents gracefully.
+             */
+            if (cur->parent == NULL)
+                return;
             cur = cur->parent;
 
             if (cur->type == XML_ELEMENT_NODE) {
@@ -1686,6 +1692,12 @@
                 break;
             }
 
+            /*
+             * The parent should never be NULL here but we want to handle
+             * corrupted documents gracefully.
+             */
+            if (cur->parent == NULL)
+                return;
             cur = cur->parent;
 
             if (cur->type == XML_ELEMENT_NODE) {
diff --git a/xpath.c b/xpath.c
index 2850a1a..6ee7e57 100644
--- a/xpath.c
+++ b/xpath.c
@@ -11677,11 +11677,11 @@
         res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
 
         if (ctxt->error != XPATH_EXPRESSION_OK)
-            goto exit;
+            break;
         if (res < 0) {
             /* Shouldn't happen */
             xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
-            goto exit;
+            break;
         }
 
         if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
@@ -11700,15 +11700,7 @@
 
         if (res != 0) {
             if (pos == maxPos) {
-                /* Clear remaining nodes and exit loop. */
-                if (hasNsNodes) {
-                    for (i++; i < set->nodeNr; i++) {
-                        node = set->nodeTab[i];
-                        if ((node != NULL) &&
-                            (node->type == XML_NAMESPACE_DECL))
-                            xmlXPathNodeSetFreeNs((xmlNsPtr) node);
-                    }
-                }
+                i += 1;
                 break;
             }
 
@@ -11716,6 +11708,15 @@
         }
     }
 
+    /* Free remaining nodes. */
+    if (hasNsNodes) {
+        for (; i < set->nodeNr; i++) {
+            xmlNodePtr node = set->nodeTab[i];
+            if ((node != NULL) && (node->type == XML_NAMESPACE_DECL))
+                xmlXPathNodeSetFreeNs((xmlNsPtr) node);
+        }
+    }
+
     set->nodeNr = j;
 
     /* If too many elements were removed, shrink table to preserve memory. */
@@ -11736,7 +11737,6 @@
         }
     }
 
-exit:
     xpctxt->node = oldnode;
     xpctxt->doc = olddoc;
     xpctxt->contextSize = oldcs;
@@ -11801,11 +11801,11 @@
         res = xmlXPathCompOpEvalToBoolean(ctxt, filterOp, 1);
 
         if (ctxt->error != XPATH_EXPRESSION_OK)
-            goto exit;
+            break;
         if (res < 0) {
             /* Shouldn't happen */
             xmlXPathErr(ctxt, XPATH_EXPR_ERROR);
-            goto exit;
+            break;
         }
 
         if ((res != 0) && ((pos >= minPos) && (pos <= maxPos))) {
@@ -11823,10 +11823,7 @@
 
         if (res != 0) {
             if (pos == maxPos) {
-                /* Clear remaining nodes and exit loop. */
-                for (i++; i < locset->locNr; i++) {
-                    xmlXPathFreeObject(locset->locTab[i]);
-                }
+                i += 1;
                 break;
             }
 
@@ -11834,6 +11831,10 @@
         }
     }
 
+    /* Free remaining nodes. */
+    for (; i < locset->locNr; i++)
+        xmlXPathFreeObject(locset->locTab[i]);
+
     locset->locNr = j;
 
     /* If too many elements were removed, shrink table to preserve memory. */
@@ -11854,7 +11855,6 @@
         }
     }
 
-exit:
     xpctxt->node = oldnode;
     xpctxt->doc = olddoc;
     xpctxt->contextSize = oldcs;
@@ -14234,7 +14234,7 @@
         return(comp);
 #endif
 
-    xmlXPathInit();
+    xmlInitParser();
 
     pctxt = xmlXPathNewParserContext(str, ctxt);
     if (pctxt == NULL)
@@ -14323,7 +14323,7 @@
 
     if (comp == NULL)
 	return(-1);
-    xmlXPathInit();
+    xmlInitParser();
 
 #ifndef LIBXML_THREAD_ENABLED
     reentance++;
@@ -14468,7 +14468,7 @@
 
     CHECK_CTXT(ctx)
 
-    xmlXPathInit();
+    xmlInitParser();
 
     ctxt = xmlXPathNewParserContext(str, ctx);
     if (ctxt == NULL)
diff --git a/xpointer.c b/xpointer.c
index 39f4ac7..ad2c288 100644
--- a/xpointer.c
+++ b/xpointer.c
@@ -1352,7 +1352,7 @@
     xmlXPathObjectPtr init = NULL;
     int stack = 0;
 
-    xmlXPathInit();
+    xmlInitParser();
 
     if ((ctx == NULL) || (str == NULL))
 	return(NULL);
@@ -2706,10 +2706,10 @@
 xmlXPtrStringRangeFunction(xmlXPathParserContextPtr ctxt, int nargs) {
     int i, startindex, endindex = 0, fendindex;
     xmlNodePtr start, end = 0, fend;
-    xmlXPathObjectPtr set;
+    xmlXPathObjectPtr set = NULL;
     xmlLocationSetPtr oldset;
-    xmlLocationSetPtr newset;
-    xmlXPathObjectPtr string;
+    xmlLocationSetPtr newset = NULL;
+    xmlXPathObjectPtr string = NULL;
     xmlXPathObjectPtr position = NULL;
     xmlXPathObjectPtr number = NULL;
     int found, pos = 0, num = 0;
@@ -2721,29 +2721,39 @@
 	XP_ERROR(XPATH_INVALID_ARITY);
 
     if (nargs >= 4) {
-	CHECK_TYPE(XPATH_NUMBER);
+        if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NUMBER)) {
+            xmlXPathErr(ctxt, XPATH_INVALID_TYPE);
+            goto error;
+        }
 	number = valuePop(ctxt);
 	if (number != NULL)
 	    num = (int) number->floatval;
     }
     if (nargs >= 3) {
-	CHECK_TYPE(XPATH_NUMBER);
+        if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_NUMBER)) {
+            xmlXPathErr(ctxt, XPATH_INVALID_TYPE);
+            goto error;
+        }
 	position = valuePop(ctxt);
 	if (position != NULL)
 	    pos = (int) position->floatval;
     }
-    CHECK_TYPE(XPATH_STRING);
+    if ((ctxt->value == NULL) || (ctxt->value->type != XPATH_STRING)) {
+        xmlXPathErr(ctxt, XPATH_INVALID_TYPE);
+        goto error;
+    }
     string = valuePop(ctxt);
     if ((ctxt->value == NULL) ||
 	((ctxt->value->type != XPATH_LOCATIONSET) &&
-	 (ctxt->value->type != XPATH_NODESET)))
-        XP_ERROR(XPATH_INVALID_TYPE)
-
+	 (ctxt->value->type != XPATH_NODESET))) {
+        xmlXPathErr(ctxt, XPATH_INVALID_TYPE);
+        goto error;
+    }
     set = valuePop(ctxt);
     newset = xmlXPtrLocationSetCreate(NULL);
     if (newset == NULL) {
-	xmlXPathFreeObject(set);
-        XP_ERROR(XPATH_MEMORY_ERROR);
+        xmlXPathErr(ctxt, XPATH_MEMORY_ERROR);
+        goto error;
     }
     if (set->nodesetval == NULL) {
         goto error;
@@ -2756,8 +2766,10 @@
 	 */
 	tmp = xmlXPtrNewLocationSetNodeSet(set->nodesetval);
 	xmlXPathFreeObject(set);
-	if (tmp == NULL)
-	     XP_ERROR(XPATH_MEMORY_ERROR)
+	if (tmp == NULL) {
+            xmlXPathErr(ctxt, XPATH_MEMORY_ERROR);
+            goto error;
+        }
 	set = tmp;
     }
     oldset = (xmlLocationSetPtr) set->user;
@@ -2830,7 +2842,8 @@
      * Save the new value and cleanup
      */
 error:
-    valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
+    if (newset != NULL)
+        valuePush(ctxt, xmlXPtrWrapLocationSet(newset));
     xmlXPathFreeObject(set);
     xmlXPathFreeObject(string);
     if (position) xmlXPathFreeObject(position);