浏览代码

Expat 2.4.6

Source commit: 0b38e8b8da8b4a710a906b6eb41cf9a8ef86febb
Martin Prikryl 3 年之前
父节点
当前提交
23a829a2a2

+ 6 - 6
libs/expat/CMake.README

@@ -3,25 +3,25 @@
 The cmake based buildsystem for expat works on Windows (cygwin, mingw, Visual
 The cmake based buildsystem for expat works on Windows (cygwin, mingw, Visual
 Studio) and should work on all other platform cmake supports.
 Studio) and should work on all other platform cmake supports.
 
 
-Assuming ~/expat-2.4.4 is the source directory of expat, add a subdirectory
+Assuming ~/expat-2.4.6 is the source directory of expat, add a subdirectory
 build and change into that directory:
 build and change into that directory:
-~/expat-2.4.4$ mkdir build && cd build
-~/expat-2.4.4/build$
+~/expat-2.4.6$ mkdir build && cd build
+~/expat-2.4.6/build$
 
 
 From that directory, call cmake first, then call make, make test and
 From that directory, call cmake first, then call make, make test and
 make install in the usual way:
 make install in the usual way:
-~/expat-2.4.4/build$ cmake ..
+~/expat-2.4.6/build$ cmake ..
 -- The C compiler identification is GNU
 -- The C compiler identification is GNU
 -- The CXX compiler identification is GNU
 -- The CXX compiler identification is GNU
 ....
 ....
 -- Configuring done
 -- Configuring done
 -- Generating done
 -- Generating done
--- Build files have been written to: /home/patrick/expat-2.4.4/build
+-- Build files have been written to: /home/patrick/expat-2.4.6/build
 
 
 If you want to specify the install location for your files, append
 If you want to specify the install location for your files, append
 -DCMAKE_INSTALL_PREFIX=/your/install/path to the cmake call.
 -DCMAKE_INSTALL_PREFIX=/your/install/path to the cmake call.
 
 
-~/expat-2.4.4/build$ make && make test && make install
+~/expat-2.4.6/build$ make && make test && make install
 Scanning dependencies of target expat
 Scanning dependencies of target expat
 [  5%] Building C object CMakeFiles/expat.dir/lib/xmlparse.c.o
 [  5%] Building C object CMakeFiles/expat.dir/lib/xmlparse.c.o
 [ 11%] Building C object CMakeFiles/expat.dir/lib/xmlrole.c.o
 [ 11%] Building C object CMakeFiles/expat.dir/lib/xmlrole.c.o

+ 2 - 2
libs/expat/CMakeLists.txt

@@ -64,7 +64,7 @@ endif()
 
 
 project(expat
 project(expat
     VERSION
     VERSION
-        2.4.4
+        2.4.6
     LANGUAGES
     LANGUAGES
         C
         C
 )
 )
@@ -408,7 +408,7 @@ if(EXPAT_WITH_LIBBSD)
 endif()
 endif()
 
 
 set(LIBCURRENT 9)   # sync
 set(LIBCURRENT 9)   # sync
-set(LIBREVISION 4)  # with
+set(LIBREVISION 6)  # with
 set(LIBAGE 8)       # configure.ac!
 set(LIBAGE 8)       # configure.ac!
 math(EXPR LIBCURRENT_MINUS_AGE "${LIBCURRENT} - ${LIBAGE}")
 math(EXPR LIBCURRENT_MINUS_AGE "${LIBCURRENT} - ${LIBAGE}")
 
 

+ 63 - 0
libs/expat/Changes

@@ -2,6 +2,69 @@ NOTE: We are looking for help with a few things:
       https://github.com/libexpat/libexpat/labels/help%20wanted
       https://github.com/libexpat/libexpat/labels/help%20wanted
       If you can help, please get in touch.  Thanks!
       If you can help, please get in touch.  Thanks!
 
 
+Release 2.4.6 Sun February 20 2022
+        Bug fixes:
+            #566  Fix a regression introduced by the fix for CVE-2022-25313
+                    in release 2.4.5 that affects applications that (1)
+                    call function XML_SetElementDeclHandler and (2) are
+                    parsing XML that contains nested element declarations
+                    (e.g. "<!ELEMENT junk ((bar|foo|xyz+), zebra*)>").
+
+        Other changes:
+       #567 #568  Version info bumped from 9:5:8 to 9:6:8;
+                    see https://verbump.de/ for what these numbers do
+
+        Special thanks to:
+            Matt Sergeant
+            Samanta Navarro
+            Sergei Trofimovich
+                 and
+            NixOS
+            Perl XML::Parser
+
+Release 2.4.5 Fri February 18 2022
+        Security fixes:
+            #562  CVE-2022-25235 -- Passing malformed 2- and 3-byte UTF-8
+                    sequences (e.g. from start tag names) to the XML
+                    processing application on top of Expat can cause
+                    arbitrary damage (e.g. code execution) depending
+                    on how invalid UTF-8 is handled inside the XML
+                    processor; validation was not their job but Expat's.
+                    Exploits with code execution are known to exist.
+            #561  CVE-2022-25236 -- Passing (one or more) namespace separator
+                    characters in "xmlns[:prefix]" attribute values
+                    made Expat send malformed tag names to the XML
+                    processor on top of Expat which can cause
+                    arbitrary damage (e.g. code execution) depending
+                    on such unexpectable cases are handled inside the XML
+                    processor; validation was not their job but Expat's.
+                    Exploits with code execution are known to exist.
+            #558  CVE-2022-25313 -- Fix stack exhaustion in doctype parsing
+                    that could be triggered by e.g. a 2 megabytes
+                    file with a large number of opening braces.
+                    Expected impact is denial of service or potentially
+                    arbitrary code execution.
+            #560  CVE-2022-25314 -- Fix integer overflow in function copyString;
+                    only affects the encoding name parameter at parser creation
+                    time which is often hardcoded (rather than user input),
+                    takes a value in the gigabytes to trigger, and a 64-bit
+                    machine.  Expected impact is denial of service.
+            #559  CVE-2022-25315 -- Fix integer overflow in function storeRawNames;
+                    needs input in the gigabytes and a 64-bit machine.
+                    Expected impact is denial of service or potentially
+                    arbitrary code execution.
+
+        Other changes:
+       #557 #564  Version info bumped from 9:4:8 to 9:5:8;
+                    see https://verbump.de/ for what these numbers do
+
+        Special thanks to:
+            Ivan Fratric
+            Samanta Navarro
+                 and
+            Google Project Zero
+            JetBrains
+
 Release 2.4.4 Sun January 30 2022
 Release 2.4.4 Sun January 30 2022
         Security fixes:
         Security fixes:
             #550  CVE-2022-23852 -- Fix signed integer overflow
             #550  CVE-2022-23852 -- Fix signed integer overflow

+ 1 - 1
libs/expat/README.md

@@ -5,7 +5,7 @@
 [![Downloads GitHub](https://img.shields.io/github/downloads/libexpat/libexpat/total?label=Downloads%20GitHub)](https://github.com/libexpat/libexpat/releases)
 [![Downloads GitHub](https://img.shields.io/github/downloads/libexpat/libexpat/total?label=Downloads%20GitHub)](https://github.com/libexpat/libexpat/releases)
 
 
 
 
-# Expat, Release 2.4.4
+# Expat, Release 2.4.6
 
 
 This is Expat, a C library for parsing XML, started by
 This is Expat, a C library for parsing XML, started by
 [James Clark](https://en.wikipedia.org/wiki/James_Clark_%28programmer%29) in 1997.
 [James Clark](https://en.wikipedia.org/wiki/James_Clark_%28programmer%29) in 1997.

+ 11 - 11
libs/expat/configure

@@ -1,6 +1,6 @@
 #! /bin/sh
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.71 for expat 2.4.4.
+# Generated by GNU Autoconf 2.71 for expat 2.4.6.
 #
 #
 # Report bugs to <[email protected]>.
 # Report bugs to <[email protected]>.
 #
 #
@@ -621,8 +621,8 @@ MAKEFLAGS=
 # Identity of this package.
 # Identity of this package.
 PACKAGE_NAME='expat'
 PACKAGE_NAME='expat'
 PACKAGE_TARNAME='expat'
 PACKAGE_TARNAME='expat'
-PACKAGE_VERSION='2.4.4'
-PACKAGE_STRING='expat 2.4.4'
+PACKAGE_VERSION='2.4.6'
+PACKAGE_STRING='expat 2.4.6'
 PACKAGE_BUGREPORT='[email protected]'
 PACKAGE_BUGREPORT='[email protected]'
 PACKAGE_URL=''
 PACKAGE_URL=''
 
 
@@ -1414,7 +1414,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
   cat <<_ACEOF
-\`configure' configures expat 2.4.4 to adapt to many kinds of systems.
+\`configure' configures expat 2.4.6 to adapt to many kinds of systems.
 
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
 
@@ -1485,7 +1485,7 @@ fi
 
 
 if test -n "$ac_init_help"; then
 if test -n "$ac_init_help"; then
   case $ac_init_help in
   case $ac_init_help in
-     short | recursive ) echo "Configuration of expat 2.4.4:";;
+     short | recursive ) echo "Configuration of expat 2.4.6:";;
    esac
    esac
   cat <<\_ACEOF
   cat <<\_ACEOF
 
 
@@ -1619,7 +1619,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
 if $ac_init_version; then
   cat <<\_ACEOF
   cat <<\_ACEOF
-expat configure 2.4.4
+expat configure 2.4.6
 generated by GNU Autoconf 2.71
 generated by GNU Autoconf 2.71
 
 
 Copyright (C) 2021 Free Software Foundation, Inc.
 Copyright (C) 2021 Free Software Foundation, Inc.
@@ -2250,7 +2250,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 running configure, to aid debugging if configure makes a mistake.
 
 
-It was created by expat $as_me 2.4.4, which was
+It was created by expat $as_me 2.4.6, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
 
   $ $0$ac_configure_args_raw
   $ $0$ac_configure_args_raw
@@ -3817,7 +3817,7 @@ fi
 
 
 # Define the identity of the package.
 # Define the identity of the package.
  PACKAGE='expat'
  PACKAGE='expat'
- VERSION='2.4.4'
+ VERSION='2.4.6'
 
 
 
 
 printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
 printf "%s\n" "#define PACKAGE \"$PACKAGE\"" >>confdefs.h
@@ -3924,7 +3924,7 @@ fi
 
 
 
 
 LIBCURRENT=9   # sync
 LIBCURRENT=9   # sync
-LIBREVISION=4  # with
+LIBREVISION=6  # with
 LIBAGE=8       # CMakeLists.txt!
 LIBAGE=8       # CMakeLists.txt!
 
 
 ac_config_headers="$ac_config_headers expat_config.h"
 ac_config_headers="$ac_config_headers expat_config.h"
@@ -20227,7 +20227,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 # values after options handling.
 ac_log="
 ac_log="
-This file was extended by expat $as_me 2.4.4, which was
+This file was extended by expat $as_me 2.4.6, which was
 generated by GNU Autoconf 2.71.  Invocation command line was
 generated by GNU Autoconf 2.71.  Invocation command line was
 
 
   CONFIG_FILES    = $CONFIG_FILES
   CONFIG_FILES    = $CONFIG_FILES
@@ -20295,7 +20295,7 @@ ac_cs_config_escaped=`printf "%s\n" "$ac_cs_config" | sed "s/^ //; s/'/'\\\\\\\\
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_config='$ac_cs_config_escaped'
 ac_cs_version="\\
 ac_cs_version="\\
-expat config.status 2.4.4
+expat config.status 2.4.6
 configured by $0, generated by GNU Autoconf 2.71,
 configured by $0, generated by GNU Autoconf 2.71,
   with options \\"\$ac_cs_config\\"
   with options \\"\$ac_cs_config\\"
 
 

+ 1 - 1
libs/expat/configure.ac

@@ -82,7 +82,7 @@ dnl If the API changes incompatibly set LIBAGE back to 0
 dnl
 dnl
 
 
 LIBCURRENT=9   # sync
 LIBCURRENT=9   # sync
-LIBREVISION=4  # with
+LIBREVISION=6  # with
 LIBAGE=8       # CMakeLists.txt!
 LIBAGE=8       # CMakeLists.txt!
 
 
 AC_CONFIG_HEADERS([expat_config.h])
 AC_CONFIG_HEADERS([expat_config.h])

+ 1 - 1
libs/expat/doc/Makefile.am

@@ -6,7 +6,7 @@
 #                      \___/_/\_\ .__/ \__,_|\__|
 #                      \___/_/\_\ .__/ \__,_|\__|
 #                               |_| XML parser
 #                               |_| XML parser
 #
 #
-# Copyright (c) 2017-2021 Sebastian Pipping <[email protected]>
+# Copyright (c) 2017-2022 Sebastian Pipping <[email protected]>
 # Copyright (c) 2017      Stephen Groat <[email protected]>
 # Copyright (c) 2017      Stephen Groat <[email protected]>
 # Copyright (c) 2017      Joe Orton <[email protected]>
 # Copyright (c) 2017      Joe Orton <[email protected]>
 # Licensed under the MIT license:
 # Licensed under the MIT license:

+ 1 - 1
libs/expat/doc/Makefile.in

@@ -22,7 +22,7 @@
 #                      \___/_/\_\ .__/ \__,_|\__|
 #                      \___/_/\_\ .__/ \__,_|\__|
 #                               |_| XML parser
 #                               |_| XML parser
 #
 #
-# Copyright (c) 2017-2021 Sebastian Pipping <[email protected]>
+# Copyright (c) 2017-2022 Sebastian Pipping <[email protected]>
 # Copyright (c) 2017      Stephen Groat <[email protected]>
 # Copyright (c) 2017      Stephen Groat <[email protected]>
 # Copyright (c) 2017      Joe Orton <[email protected]>
 # Copyright (c) 2017      Joe Orton <[email protected]>
 # Licensed under the MIT license:
 # Licensed under the MIT license:

+ 1 - 1
libs/expat/doc/reference.html

@@ -49,7 +49,7 @@
   <div>
   <div>
     <h1>
     <h1>
       The Expat XML Parser
       The Expat XML Parser
-      <small>Release 2.4.4</small>
+      <small>Release 2.4.6</small>
     </h1>
     </h1>
   </div>
   </div>
 <div class="content">
 <div class="content">

+ 1 - 1
libs/expat/doc/xmlwf.1

@@ -5,7 +5,7 @@
 \\$2 \(la\\$1\(ra\\$3
 \\$2 \(la\\$1\(ra\\$3
 ..
 ..
 .if \n(.g .mso www.tmac
 .if \n(.g .mso www.tmac
-.TH XMLWF 1 "January 30, 2022" "" ""
+.TH XMLWF 1 "February 20, 2022" "" ""
 .SH NAME
 .SH NAME
 xmlwf \- Determines if an XML document is well-formed
 xmlwf \- Determines if an XML document is well-formed
 .SH SYNOPSIS
 .SH SYNOPSIS

+ 1 - 1
libs/expat/doc/xmlwf.xml

@@ -21,7 +21,7 @@
           "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
           "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
   <!ENTITY dhfirstname "<firstname>Scott</firstname>">
   <!ENTITY dhfirstname "<firstname>Scott</firstname>">
   <!ENTITY dhsurname   "<surname>Bronson</surname>">
   <!ENTITY dhsurname   "<surname>Bronson</surname>">
-  <!ENTITY dhdate      "<date>January 30, 2022</date>">
+  <!ENTITY dhdate      "<date>February 20, 2022</date>">
   <!-- Please adjust this^^ date whenever cutting a new release. -->
   <!-- Please adjust this^^ date whenever cutting a new release. -->
   <!ENTITY dhsection   "<manvolnum>1</manvolnum>">
   <!ENTITY dhsection   "<manvolnum>1</manvolnum>">
   <!ENTITY dhemail     "<email>[email protected]</email>">
   <!ENTITY dhemail     "<email>[email protected]</email>">

+ 1 - 1
libs/expat/examples/elements.c

@@ -13,7 +13,7 @@
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
    Copyright (c) 1997-2000 Thai Open Source Software Center Ltd
    Copyright (c) 2001-2003 Fred L. Drake, Jr. <[email protected]>
    Copyright (c) 2001-2003 Fred L. Drake, Jr. <[email protected]>
    Copyright (c) 2004-2006 Karl Waclawek <[email protected]>
    Copyright (c) 2004-2006 Karl Waclawek <[email protected]>
-   Copyright (c) 2005-2007 Steven Solie <s[email protected]>
+   Copyright (c) 2005-2007 Steven Solie <s[email protected]>
    Copyright (c) 2016-2019 Sebastian Pipping <[email protected]>
    Copyright (c) 2016-2019 Sebastian Pipping <[email protected]>
    Copyright (c) 2017      Rhodri James <[email protected]>
    Copyright (c) 2017      Rhodri James <[email protected]>
    Copyright (c) 2019      Zhongyuan Zhou <[email protected]>
    Copyright (c) 2019      Zhongyuan Zhou <[email protected]>

+ 1 - 1
libs/expat/examples/outline.c

@@ -10,7 +10,7 @@
 
 
    Copyright (c) 2000      Clark Cooper <[email protected]>
    Copyright (c) 2000      Clark Cooper <[email protected]>
    Copyright (c) 2001-2003 Fred L. Drake, Jr. <[email protected]>
    Copyright (c) 2001-2003 Fred L. Drake, Jr. <[email protected]>
-   Copyright (c) 2005-2007 Steven Solie <s[email protected]>
+   Copyright (c) 2005-2007 Steven Solie <s[email protected]>
    Copyright (c) 2005-2006 Karl Waclawek <[email protected]>
    Copyright (c) 2005-2006 Karl Waclawek <[email protected]>
    Copyright (c) 2016-2019 Sebastian Pipping <[email protected]>
    Copyright (c) 2016-2019 Sebastian Pipping <[email protected]>
    Copyright (c) 2017      Rhodri James <[email protected]>
    Copyright (c) 2017      Rhodri James <[email protected]>

+ 3 - 3
libs/expat/expat_config.h

@@ -77,7 +77,7 @@
 #define PACKAGE_NAME "expat"
 #define PACKAGE_NAME "expat"
 
 
 /* Define to the full name and version of this package. */
 /* Define to the full name and version of this package. */
-#define PACKAGE_STRING "expat 2.4.4"
+#define PACKAGE_STRING "expat 2.4.6"
 
 
 /* Define to the one symbol short name of this package. */
 /* Define to the one symbol short name of this package. */
 #define PACKAGE_TARNAME "expat"
 #define PACKAGE_TARNAME "expat"
@@ -86,7 +86,7 @@
 #define PACKAGE_URL ""
 #define PACKAGE_URL ""
 
 
 /* Define to the version of this package. */
 /* Define to the version of this package. */
-#define PACKAGE_VERSION "2.4.4"
+#define PACKAGE_VERSION "2.4.6"
 
 
 /* Define to 1 if all of the C90 standard headers exist (not just the ones
 /* Define to 1 if all of the C90 standard headers exist (not just the ones
    required in a freestanding environment). This macro is provided for
    required in a freestanding environment). This macro is provided for
@@ -94,7 +94,7 @@
 #define STDC_HEADERS 1
 #define STDC_HEADERS 1
 
 
 /* Version number of package */
 /* Version number of package */
-#define VERSION "2.4.4"
+#define VERSION "2.4.6"
 
 
 /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
 /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
    significant byte first (like Motorola and SPARC, unlike Intel). */
    significant byte first (like Motorola and SPARC, unlike Intel). */

+ 1 - 1
libs/expat/lib/expat.h

@@ -1041,7 +1041,7 @@ XML_SetBillionLaughsAttackProtectionActivationThreshold(
 */
 */
 #define XML_MAJOR_VERSION 2
 #define XML_MAJOR_VERSION 2
 #define XML_MINOR_VERSION 4
 #define XML_MINOR_VERSION 4
-#define XML_MICRO_VERSION 4
+#define XML_MICRO_VERSION 6
 
 
 #ifdef __cplusplus
 #ifdef __cplusplus
 }
 }

+ 116 - 45
libs/expat/lib/xmlparse.c

@@ -1,4 +1,4 @@
-/* 2e2c8ce5f11a473d65ec313ab20ceee6afefb355f5405afc06e7204e2e41c8c0 (2.4.4+)
+/* a30d2613dcfdef81475a9d1a349134d2d42722172fdaa7d5bb12ed2aa74b9596 (2.4.6+)
                             __  __            _
                             __  __            _
                          ___\ \/ /_ __   __ _| |_
                          ___\ \/ /_ __   __ _| |_
                         / _ \\  /| '_ \ / _` | __|
                         / _ \\  /| '_ \ / _` | __|
@@ -11,7 +11,7 @@
    Copyright (c) 2000-2006 Fred L. Drake, Jr. <[email protected]>
    Copyright (c) 2000-2006 Fred L. Drake, Jr. <[email protected]>
    Copyright (c) 2001-2002 Greg Stein <[email protected]>
    Copyright (c) 2001-2002 Greg Stein <[email protected]>
    Copyright (c) 2002-2016 Karl Waclawek <[email protected]>
    Copyright (c) 2002-2016 Karl Waclawek <[email protected]>
-   Copyright (c) 2005-2009 Steven Solie <s[email protected]>
+   Copyright (c) 2005-2009 Steven Solie <s[email protected]>
    Copyright (c) 2016      Eric Rahm <[email protected]>
    Copyright (c) 2016      Eric Rahm <[email protected]>
    Copyright (c) 2016-2022 Sebastian Pipping <[email protected]>
    Copyright (c) 2016-2022 Sebastian Pipping <[email protected]>
    Copyright (c) 2016      Gaurav <[email protected]>
    Copyright (c) 2016      Gaurav <[email protected]>
@@ -718,8 +718,7 @@ XML_ParserCreate(const XML_Char *encodingName) {
 
 
 XML_Parser XMLCALL
 XML_Parser XMLCALL
 XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep) {
 XML_ParserCreateNS(const XML_Char *encodingName, XML_Char nsSep) {
-  XML_Char tmp[2];
-  *tmp = nsSep;
+  XML_Char tmp[2] = {nsSep, 0};
   return XML_ParserCreate_MM(encodingName, NULL, tmp);
   return XML_ParserCreate_MM(encodingName, NULL, tmp);
 }
 }
 
 
@@ -1344,8 +1343,7 @@ XML_ExternalEntityParserCreate(XML_Parser oldParser, const XML_Char *context,
      would be otherwise.
      would be otherwise.
   */
   */
   if (parser->m_ns) {
   if (parser->m_ns) {
-    XML_Char tmp[2];
-    *tmp = parser->m_namespaceSeparator;
+    XML_Char tmp[2] = {parser->m_namespaceSeparator, 0};
     parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd);
     parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd);
   } else {
   } else {
     parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd);
     parser = parserCreate(encodingName, &parser->m_mem, NULL, newDtd);
@@ -2563,6 +2561,7 @@ storeRawNames(XML_Parser parser) {
   while (tag) {
   while (tag) {
     int bufSize;
     int bufSize;
     int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1);
     int nameLen = sizeof(XML_Char) * (tag->name.strLen + 1);
+    size_t rawNameLen;
     char *rawNameBuf = tag->buf + nameLen;
     char *rawNameBuf = tag->buf + nameLen;
     /* Stop if already stored.  Since m_tagStack is a stack, we can stop
     /* Stop if already stored.  Since m_tagStack is a stack, we can stop
        at the first entry that has already been copied; everything
        at the first entry that has already been copied; everything
@@ -2574,7 +2573,11 @@ storeRawNames(XML_Parser parser) {
     /* For re-use purposes we need to ensure that the
     /* For re-use purposes we need to ensure that the
        size of tag->buf is a multiple of sizeof(XML_Char).
        size of tag->buf is a multiple of sizeof(XML_Char).
     */
     */
-    bufSize = nameLen + ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
+    rawNameLen = ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
+    /* Detect and prevent integer overflow. */
+    if (rawNameLen > (size_t)INT_MAX - nameLen)
+      return XML_FALSE;
+    bufSize = nameLen + (int)rawNameLen;
     if (bufSize > tag->bufEnd - tag->buf) {
     if (bufSize > tag->bufEnd - tag->buf) {
       char *temp = (char *)REALLOC(parser, tag->buf, bufSize);
       char *temp = (char *)REALLOC(parser, tag->buf, bufSize);
       if (temp == NULL)
       if (temp == NULL)
@@ -3756,6 +3759,17 @@ addBinding(XML_Parser parser, PREFIX *prefix, const ATTRIBUTE_ID *attId,
     if (! mustBeXML && isXMLNS
     if (! mustBeXML && isXMLNS
         && (len > xmlnsLen || uri[len] != xmlnsNamespace[len]))
         && (len > xmlnsLen || uri[len] != xmlnsNamespace[len]))
       isXMLNS = XML_FALSE;
       isXMLNS = XML_FALSE;
+
+    // NOTE: While Expat does not validate namespace URIs against RFC 3986,
+    //       we have to at least make sure that the XML processor on top of
+    //       Expat (that is splitting tag names by namespace separator into
+    //       2- or 3-tuples (uri-local or uri-local-prefix)) cannot be confused
+    //       by an attacker putting additional namespace separator characters
+    //       into namespace declarations.  That would be ambiguous and not to
+    //       be expected.
+    if (parser->m_ns && (uri[len] == parser->m_namespaceSeparator)) {
+      return XML_ERROR_SYNTAX;
+    }
   }
   }
   isXML = isXML && len == xmlLen;
   isXML = isXML && len == xmlLen;
   isXMLNS = isXMLNS && len == xmlnsLen;
   isXMLNS = isXMLNS && len == xmlnsLen;
@@ -7317,44 +7331,15 @@ nextScaffoldPart(XML_Parser parser) {
   return next;
   return next;
 }
 }
 
 
-static void
-build_node(XML_Parser parser, int src_node, XML_Content *dest,
-           XML_Content **contpos, XML_Char **strpos) {
-  DTD *const dtd = parser->m_dtd; /* save one level of indirection */
-  dest->type = dtd->scaffold[src_node].type;
-  dest->quant = dtd->scaffold[src_node].quant;
-  if (dest->type == XML_CTYPE_NAME) {
-    const XML_Char *src;
-    dest->name = *strpos;
-    src = dtd->scaffold[src_node].name;
-    for (;;) {
-      *(*strpos)++ = *src;
-      if (! *src)
-        break;
-      src++;
-    }
-    dest->numchildren = 0;
-    dest->children = NULL;
-  } else {
-    unsigned int i;
-    int cn;
-    dest->numchildren = dtd->scaffold[src_node].childcnt;
-    dest->children = *contpos;
-    *contpos += dest->numchildren;
-    for (i = 0, cn = dtd->scaffold[src_node].firstchild; i < dest->numchildren;
-         i++, cn = dtd->scaffold[cn].nextsib) {
-      build_node(parser, cn, &(dest->children[i]), contpos, strpos);
-    }
-    dest->name = NULL;
-  }
-}
-
 static XML_Content *
 static XML_Content *
 build_model(XML_Parser parser) {
 build_model(XML_Parser parser) {
+  /* Function build_model transforms the existing parser->m_dtd->scaffold
+   * array of CONTENT_SCAFFOLD tree nodes into a new array of
+   * XML_Content tree nodes followed by a gapless list of zero-terminated
+   * strings. */
   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
   DTD *const dtd = parser->m_dtd; /* save one level of indirection */
   XML_Content *ret;
   XML_Content *ret;
-  XML_Content *cpos;
-  XML_Char *str;
+  XML_Char *str; /* the current string writing location */
 
 
   /* Detect and prevent integer overflow.
   /* Detect and prevent integer overflow.
    * The preprocessor guard addresses the "always false" warning
    * The preprocessor guard addresses the "always false" warning
@@ -7380,10 +7365,96 @@ build_model(XML_Parser parser) {
   if (! ret)
   if (! ret)
     return NULL;
     return NULL;
 
 
-  str = (XML_Char *)(&ret[dtd->scaffCount]);
-  cpos = &ret[1];
+  /* What follows is an iterative implementation (of what was previously done
+   * recursively in a dedicated function called "build_node".  The old recursive
+   * build_node could be forced into stack exhaustion from input as small as a
+   * few megabyte, and so that was a security issue.  Hence, a function call
+   * stack is avoided now by resolving recursion.)
+   *
+   * The iterative approach works as follows:
+   *
+   * - We have two writing pointers, both walking up the result array; one does
+   *   the work, the other creates "jobs" for its colleague to do, and leads
+   *   the way:
+   *
+   *   - The faster one, pointer jobDest, always leads and writes "what job
+   *     to do" by the other, once they reach that place in the
+   *     array: leader "jobDest" stores the source node array index (relative
+   *     to array dtd->scaffold) in field "numchildren".
+   *
+   *   - The slower one, pointer dest, looks at the value stored in the
+   *     "numchildren" field (which actually holds a source node array index
+   *     at that time) and puts the real data from dtd->scaffold in.
+   *
+   * - Before the loop starts, jobDest writes source array index 0
+   *   (where the root node is located) so that dest will have something to do
+   *   when it starts operation.
+   *
+   * - Whenever nodes with children are encountered, jobDest appends
+   *   them as new jobs, in order.  As a result, tree node siblings are
+   *   adjacent in the resulting array, for example:
+   *
+   *     [0] root, has two children
+   *       [1] first child of 0, has three children
+   *         [3] first child of 1, does not have children
+   *         [4] second child of 1, does not have children
+   *         [5] third child of 1, does not have children
+   *       [2] second child of 0, does not have children
+   *
+   *   Or (the same data) presented in flat array view:
+   *
+   *     [0] root, has two children
+   *
+   *     [1] first child of 0, has three children
+   *     [2] second child of 0, does not have children
+   *
+   *     [3] first child of 1, does not have children
+   *     [4] second child of 1, does not have children
+   *     [5] third child of 1, does not have children
+   *
+   * - The algorithm repeats until all target array indices have been processed.
+   */
+  XML_Content *dest = ret; /* tree node writing location, moves upwards */
+  XML_Content *const destLimit = &ret[dtd->scaffCount];
+  XML_Content *jobDest = ret; /* next free writing location in target array */
+  str = (XML_Char *)&ret[dtd->scaffCount];
+
+  /* Add the starting job, the root node (index 0) of the source tree  */
+  (jobDest++)->numchildren = 0;
+
+  for (; dest < destLimit; dest++) {
+    /* Retrieve source tree array index from job storage */
+    const int src_node = (int)dest->numchildren;
+
+    /* Convert item */
+    dest->type = dtd->scaffold[src_node].type;
+    dest->quant = dtd->scaffold[src_node].quant;
+    if (dest->type == XML_CTYPE_NAME) {
+      const XML_Char *src;
+      dest->name = str;
+      src = dtd->scaffold[src_node].name;
+      for (;;) {
+        *str++ = *src;
+        if (! *src)
+          break;
+        src++;
+      }
+      dest->numchildren = 0;
+      dest->children = NULL;
+    } else {
+      unsigned int i;
+      int cn;
+      dest->name = NULL;
+      dest->numchildren = dtd->scaffold[src_node].childcnt;
+      dest->children = jobDest;
+
+      /* Append scaffold indices of children to array */
+      for (i = 0, cn = dtd->scaffold[src_node].firstchild;
+           i < dest->numchildren; i++, cn = dtd->scaffold[cn].nextsib)
+        (jobDest++)->numchildren = (unsigned int)cn;
+    }
+  }
 
 
-  build_node(parser, 0, ret, &cpos, &str);
   return ret;
   return ret;
 }
 }
 
 
@@ -7412,7 +7483,7 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr,
 
 
 static XML_Char *
 static XML_Char *
 copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) {
 copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) {
-  int charsRequired = 0;
+  size_t charsRequired = 0;
   XML_Char *result;
   XML_Char *result;
 
 
   /* First determine how long the string is */
   /* First determine how long the string is */

+ 1 - 1
libs/expat/lib/xmlrole.c

@@ -11,7 +11,7 @@
    Copyright (c) 2002      Greg Stein <[email protected]>
    Copyright (c) 2002      Greg Stein <[email protected]>
    Copyright (c) 2002-2006 Karl Waclawek <[email protected]>
    Copyright (c) 2002-2006 Karl Waclawek <[email protected]>
    Copyright (c) 2002-2003 Fred L. Drake, Jr. <[email protected]>
    Copyright (c) 2002-2003 Fred L. Drake, Jr. <[email protected]>
-   Copyright (c) 2005-2009 Steven Solie <s[email protected]>
+   Copyright (c) 2005-2009 Steven Solie <s[email protected]>
    Copyright (c) 2016-2021 Sebastian Pipping <[email protected]>
    Copyright (c) 2016-2021 Sebastian Pipping <[email protected]>
    Copyright (c) 2017      Rhodri James <[email protected]>
    Copyright (c) 2017      Rhodri James <[email protected]>
    Copyright (c) 2019      David Loffredo <[email protected]>
    Copyright (c) 2019      David Loffredo <[email protected]>

+ 2 - 7
libs/expat/lib/xmltok.c

@@ -11,8 +11,8 @@
    Copyright (c) 2001-2003 Fred L. Drake, Jr. <[email protected]>
    Copyright (c) 2001-2003 Fred L. Drake, Jr. <[email protected]>
    Copyright (c) 2002      Greg Stein <[email protected]>
    Copyright (c) 2002      Greg Stein <[email protected]>
    Copyright (c) 2002-2016 Karl Waclawek <[email protected]>
    Copyright (c) 2002-2016 Karl Waclawek <[email protected]>
-   Copyright (c) 2005-2009 Steven Solie <s[email protected]>
-   Copyright (c) 2016-2021 Sebastian Pipping <[email protected]>
+   Copyright (c) 2005-2009 Steven Solie <s[email protected]>
+   Copyright (c) 2016-2022 Sebastian Pipping <[email protected]>
    Copyright (c) 2016      Pascal Cuoq <[email protected]>
    Copyright (c) 2016      Pascal Cuoq <[email protected]>
    Copyright (c) 2016      Don Lewis <[email protected]>
    Copyright (c) 2016      Don Lewis <[email protected]>
    Copyright (c) 2017      Rhodri James <[email protected]>
    Copyright (c) 2017      Rhodri James <[email protected]>
@@ -98,11 +98,6 @@
         + ((((byte)[1]) & 3) << 1) + ((((byte)[2]) >> 5) & 1)]                 \
         + ((((byte)[1]) & 3) << 1) + ((((byte)[2]) >> 5) & 1)]                 \
    & (1u << (((byte)[2]) & 0x1F)))
    & (1u << (((byte)[2]) & 0x1F)))
 
 
-#define UTF8_GET_NAMING(pages, p, n)                                           \
-  ((n) == 2                                                                    \
-       ? UTF8_GET_NAMING2(pages, (const unsigned char *)(p))                   \
-       : ((n) == 3 ? UTF8_GET_NAMING3(pages, (const unsigned char *)(p)) : 0))
-
 /* Detection of invalid UTF-8 sequences is based on Table 3.1B
 /* Detection of invalid UTF-8 sequences is based on Table 3.1B
    of Unicode 3.2: http://www.unicode.org/unicode/reports/tr28/
    of Unicode 3.2: http://www.unicode.org/unicode/reports/tr28/
    with the additional restriction of not allowing the Unicode
    with the additional restriction of not allowing the Unicode

+ 12 - 8
libs/expat/lib/xmltok_impl.c

@@ -10,7 +10,7 @@
    Copyright (c) 2000      Clark Cooper <[email protected]>
    Copyright (c) 2000      Clark Cooper <[email protected]>
    Copyright (c) 2002      Fred L. Drake, Jr. <[email protected]>
    Copyright (c) 2002      Fred L. Drake, Jr. <[email protected]>
    Copyright (c) 2002-2016 Karl Waclawek <[email protected]>
    Copyright (c) 2002-2016 Karl Waclawek <[email protected]>
-   Copyright (c) 2016-2021 Sebastian Pipping <[email protected]>
+   Copyright (c) 2016-2022 Sebastian Pipping <[email protected]>
    Copyright (c) 2017      Rhodri James <[email protected]>
    Copyright (c) 2017      Rhodri James <[email protected]>
    Copyright (c) 2018      Benjamin Peterson <[email protected]>
    Copyright (c) 2018      Benjamin Peterson <[email protected]>
    Copyright (c) 2018      Anton Maklakov <[email protected]>
    Copyright (c) 2018      Anton Maklakov <[email protected]>
@@ -69,7 +69,7 @@
   case BT_LEAD##n:                                                             \
   case BT_LEAD##n:                                                             \
     if (end - ptr < n)                                                         \
     if (end - ptr < n)                                                         \
       return XML_TOK_PARTIAL_CHAR;                                             \
       return XML_TOK_PARTIAL_CHAR;                                             \
-    if (! IS_NAME_CHAR(enc, ptr, n)) {                                         \
+    if (IS_INVALID_CHAR(enc, ptr, n) || ! IS_NAME_CHAR(enc, ptr, n)) {         \
       *nextTokPtr = ptr;                                                       \
       *nextTokPtr = ptr;                                                       \
       return XML_TOK_INVALID;                                                  \
       return XML_TOK_INVALID;                                                  \
     }                                                                          \
     }                                                                          \
@@ -98,7 +98,7 @@
   case BT_LEAD##n:                                                             \
   case BT_LEAD##n:                                                             \
     if (end - ptr < n)                                                         \
     if (end - ptr < n)                                                         \
       return XML_TOK_PARTIAL_CHAR;                                             \
       return XML_TOK_PARTIAL_CHAR;                                             \
-    if (! IS_NMSTRT_CHAR(enc, ptr, n)) {                                       \
+    if (IS_INVALID_CHAR(enc, ptr, n) || ! IS_NMSTRT_CHAR(enc, ptr, n)) {       \
       *nextTokPtr = ptr;                                                       \
       *nextTokPtr = ptr;                                                       \
       return XML_TOK_INVALID;                                                  \
       return XML_TOK_INVALID;                                                  \
     }                                                                          \
     }                                                                          \
@@ -1142,6 +1142,10 @@ PREFIX(prologTok)(const ENCODING *enc, const char *ptr, const char *end,
   case BT_LEAD##n:                                                             \
   case BT_LEAD##n:                                                             \
     if (end - ptr < n)                                                         \
     if (end - ptr < n)                                                         \
       return XML_TOK_PARTIAL_CHAR;                                             \
       return XML_TOK_PARTIAL_CHAR;                                             \
+    if (IS_INVALID_CHAR(enc, ptr, n)) {                                        \
+      *nextTokPtr = ptr;                                                       \
+      return XML_TOK_INVALID;                                                  \
+    }                                                                          \
     if (IS_NMSTRT_CHAR(enc, ptr, n)) {                                         \
     if (IS_NMSTRT_CHAR(enc, ptr, n)) {                                         \
       ptr += n;                                                                \
       ptr += n;                                                                \
       tok = XML_TOK_NAME;                                                      \
       tok = XML_TOK_NAME;                                                      \
@@ -1270,7 +1274,7 @@ PREFIX(attributeValueTok)(const ENCODING *enc, const char *ptr, const char *end,
     switch (BYTE_TYPE(enc, ptr)) {
     switch (BYTE_TYPE(enc, ptr)) {
 #  define LEAD_CASE(n)                                                         \
 #  define LEAD_CASE(n)                                                         \
   case BT_LEAD##n:                                                             \
   case BT_LEAD##n:                                                             \
-    ptr += n;                                                                  \
+    ptr += n; /* NOTE: The encoding has already been validated. */             \
     break;
     break;
       LEAD_CASE(2)
       LEAD_CASE(2)
       LEAD_CASE(3)
       LEAD_CASE(3)
@@ -1339,7 +1343,7 @@ PREFIX(entityValueTok)(const ENCODING *enc, const char *ptr, const char *end,
     switch (BYTE_TYPE(enc, ptr)) {
     switch (BYTE_TYPE(enc, ptr)) {
 #  define LEAD_CASE(n)                                                         \
 #  define LEAD_CASE(n)                                                         \
   case BT_LEAD##n:                                                             \
   case BT_LEAD##n:                                                             \
-    ptr += n;                                                                  \
+    ptr += n; /* NOTE: The encoding has already been validated. */             \
     break;
     break;
       LEAD_CASE(2)
       LEAD_CASE(2)
       LEAD_CASE(3)
       LEAD_CASE(3)
@@ -1518,7 +1522,7 @@ PREFIX(getAtts)(const ENCODING *enc, const char *ptr, int attsMax,
       state = inName;                                                          \
       state = inName;                                                          \
     }
     }
 #  define LEAD_CASE(n)                                                         \
 #  define LEAD_CASE(n)                                                         \
-  case BT_LEAD##n:                                                             \
+  case BT_LEAD##n: /* NOTE: The encoding has already been validated. */        \
     START_NAME ptr += (n - MINBPC(enc));                                       \
     START_NAME ptr += (n - MINBPC(enc));                                       \
     break;
     break;
       LEAD_CASE(2)
       LEAD_CASE(2)
@@ -1730,7 +1734,7 @@ PREFIX(nameLength)(const ENCODING *enc, const char *ptr) {
     switch (BYTE_TYPE(enc, ptr)) {
     switch (BYTE_TYPE(enc, ptr)) {
 #  define LEAD_CASE(n)                                                         \
 #  define LEAD_CASE(n)                                                         \
   case BT_LEAD##n:                                                             \
   case BT_LEAD##n:                                                             \
-    ptr += n;                                                                  \
+    ptr += n; /* NOTE: The encoding has already been validated. */             \
     break;
     break;
       LEAD_CASE(2)
       LEAD_CASE(2)
       LEAD_CASE(3)
       LEAD_CASE(3)
@@ -1775,7 +1779,7 @@ PREFIX(updatePosition)(const ENCODING *enc, const char *ptr, const char *end,
     switch (BYTE_TYPE(enc, ptr)) {
     switch (BYTE_TYPE(enc, ptr)) {
 #  define LEAD_CASE(n)                                                         \
 #  define LEAD_CASE(n)                                                         \
   case BT_LEAD##n:                                                             \
   case BT_LEAD##n:                                                             \
-    ptr += n;                                                                  \
+    ptr += n; /* NOTE: The encoding has already been validated. */             \
     pos->columnNumber++;                                                       \
     pos->columnNumber++;                                                       \
     break;
     break;
       LEAD_CASE(2)
       LEAD_CASE(2)

+ 1 - 1
libs/expat/tests/benchmark/benchmark.c

@@ -7,7 +7,7 @@
                                  |_| XML parser
                                  |_| XML parser
 
 
    Copyright (c) 2003-2006 Karl Waclawek <[email protected]>
    Copyright (c) 2003-2006 Karl Waclawek <[email protected]>
-   Copyright (c) 2005-2007 Steven Solie <s[email protected]>
+   Copyright (c) 2005-2007 Steven Solie <s[email protected]>
    Copyright (c) 2017      Sebastian Pipping <[email protected]>
    Copyright (c) 2017      Sebastian Pipping <[email protected]>
    Copyright (c) 2017      Rhodri James <[email protected]>
    Copyright (c) 2017      Rhodri James <[email protected]>
    Licensed under the MIT license:
    Licensed under the MIT license:

+ 218 - 2
libs/expat/tests/runtests.c

@@ -8,7 +8,7 @@
 
 
    Copyright (c) 2001-2006 Fred L. Drake, Jr. <[email protected]>
    Copyright (c) 2001-2006 Fred L. Drake, Jr. <[email protected]>
    Copyright (c) 2003      Greg Stein <[email protected]>
    Copyright (c) 2003      Greg Stein <[email protected]>
-   Copyright (c) 2005-2007 Steven Solie <s[email protected]>
+   Copyright (c) 2005-2007 Steven Solie <s[email protected]>
    Copyright (c) 2005-2012 Karl Waclawek <[email protected]>
    Copyright (c) 2005-2012 Karl Waclawek <[email protected]>
    Copyright (c) 2016-2022 Sebastian Pipping <[email protected]>
    Copyright (c) 2016-2022 Sebastian Pipping <[email protected]>
    Copyright (c) 2017-2018 Rhodri James <[email protected]>
    Copyright (c) 2017-2018 Rhodri James <[email protected]>
@@ -2664,6 +2664,82 @@ START_TEST(test_dtd_elements) {
 }
 }
 END_TEST
 END_TEST
 
 
+static void XMLCALL
+element_decl_check_model(void *userData, const XML_Char *name,
+                         XML_Content *model) {
+  UNUSED_P(userData);
+  uint32_t errorFlags = 0;
+
+  /* Expected model array structure is this:
+   * [0] (type 6, quant 0)
+   *   [1] (type 5, quant 0)
+   *     [3] (type 4, quant 0, name "bar")
+   *     [4] (type 4, quant 0, name "foo")
+   *     [5] (type 4, quant 3, name "xyz")
+   *   [2] (type 4, quant 2, name "zebra")
+   */
+  errorFlags |= ((xcstrcmp(name, XCS("junk")) == 0) ? 0 : (1u << 0));
+  errorFlags |= ((model != NULL) ? 0 : (1u << 1));
+
+  errorFlags |= ((model[0].type == XML_CTYPE_SEQ) ? 0 : (1u << 2));
+  errorFlags |= ((model[0].quant == XML_CQUANT_NONE) ? 0 : (1u << 3));
+  errorFlags |= ((model[0].numchildren == 2) ? 0 : (1u << 4));
+  errorFlags |= ((model[0].children == &model[1]) ? 0 : (1u << 5));
+  errorFlags |= ((model[0].name == NULL) ? 0 : (1u << 6));
+
+  errorFlags |= ((model[1].type == XML_CTYPE_CHOICE) ? 0 : (1u << 7));
+  errorFlags |= ((model[1].quant == XML_CQUANT_NONE) ? 0 : (1u << 8));
+  errorFlags |= ((model[1].numchildren == 3) ? 0 : (1u << 9));
+  errorFlags |= ((model[1].children == &model[3]) ? 0 : (1u << 10));
+  errorFlags |= ((model[1].name == NULL) ? 0 : (1u << 11));
+
+  errorFlags |= ((model[2].type == XML_CTYPE_NAME) ? 0 : (1u << 12));
+  errorFlags |= ((model[2].quant == XML_CQUANT_REP) ? 0 : (1u << 13));
+  errorFlags |= ((model[2].numchildren == 0) ? 0 : (1u << 14));
+  errorFlags |= ((model[2].children == NULL) ? 0 : (1u << 15));
+  errorFlags |= ((xcstrcmp(model[2].name, XCS("zebra")) == 0) ? 0 : (1u << 16));
+
+  errorFlags |= ((model[3].type == XML_CTYPE_NAME) ? 0 : (1u << 17));
+  errorFlags |= ((model[3].quant == XML_CQUANT_NONE) ? 0 : (1u << 18));
+  errorFlags |= ((model[3].numchildren == 0) ? 0 : (1u << 19));
+  errorFlags |= ((model[3].children == NULL) ? 0 : (1u << 20));
+  errorFlags |= ((xcstrcmp(model[3].name, XCS("bar")) == 0) ? 0 : (1u << 21));
+
+  errorFlags |= ((model[4].type == XML_CTYPE_NAME) ? 0 : (1u << 22));
+  errorFlags |= ((model[4].quant == XML_CQUANT_NONE) ? 0 : (1u << 23));
+  errorFlags |= ((model[4].numchildren == 0) ? 0 : (1u << 24));
+  errorFlags |= ((model[4].children == NULL) ? 0 : (1u << 25));
+  errorFlags |= ((xcstrcmp(model[4].name, XCS("foo")) == 0) ? 0 : (1u << 26));
+
+  errorFlags |= ((model[5].type == XML_CTYPE_NAME) ? 0 : (1u << 27));
+  errorFlags |= ((model[5].quant == XML_CQUANT_PLUS) ? 0 : (1u << 28));
+  errorFlags |= ((model[5].numchildren == 0) ? 0 : (1u << 29));
+  errorFlags |= ((model[5].children == NULL) ? 0 : (1u << 30));
+  errorFlags |= ((xcstrcmp(model[5].name, XCS("xyz")) == 0) ? 0 : (1u << 31));
+
+  XML_SetUserData(g_parser, (void *)(uintptr_t)errorFlags);
+  XML_FreeContentModel(g_parser, model);
+}
+
+START_TEST(test_dtd_elements_nesting) {
+  // Payload inspired by a test in Perl's XML::Parser
+  const char *text = "<!DOCTYPE foo [\n"
+                     "<!ELEMENT junk ((bar|foo|xyz+), zebra*)>\n"
+                     "]>\n"
+                     "<foo/>";
+
+  XML_SetUserData(g_parser, (void *)(uintptr_t)-1);
+
+  XML_SetElementDeclHandler(g_parser, element_decl_check_model);
+  if (XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE)
+      == XML_STATUS_ERROR)
+    xml_failure(g_parser);
+
+  if ((uint32_t)(uintptr_t)XML_GetUserData(g_parser) != 0)
+    fail("Element declaration model regression detected");
+}
+END_TEST
+
 /* Test foreign DTD handling */
 /* Test foreign DTD handling */
 START_TEST(test_set_foreign_dtd) {
 START_TEST(test_set_foreign_dtd) {
   const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n";
   const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n";
@@ -5998,6 +6074,105 @@ START_TEST(test_utf8_in_cdata_section_2) {
 }
 }
 END_TEST
 END_TEST
 
 
+START_TEST(test_utf8_in_start_tags) {
+  struct test_case {
+    bool goodName;
+    bool goodNameStart;
+    const char *tagName;
+  };
+
+  // The idea with the tests below is this:
+  // We want to cover 1-, 2- and 3-byte sequences, 4-byte sequences
+  // go to isNever and are hence not a concern.
+  //
+  // We start with a character that is a valid name character
+  // (or even name-start character, see XML 1.0r4 spec) and then we flip
+  // single bits at places where (1) the result leaves the UTF-8 encoding space
+  // and (2) we stay in the same n-byte sequence family.
+  //
+  // The flipped bits are highlighted in angle brackets in comments,
+  // e.g. "[<1>011 1001]" means we had [0011 1001] but we now flipped
+  // the most significant bit to 1 to leave UTF-8 encoding space.
+  struct test_case cases[] = {
+      // 1-byte UTF-8: [0xxx xxxx]
+      {true, true, "\x3A"},   // [0011 1010] = ASCII colon ':'
+      {false, false, "\xBA"}, // [<1>011 1010]
+      {true, false, "\x39"},  // [0011 1001] = ASCII nine '9'
+      {false, false, "\xB9"}, // [<1>011 1001]
+
+      // 2-byte UTF-8: [110x xxxx] [10xx xxxx]
+      {true, true, "\xDB\xA5"},   // [1101 1011] [1010 0101] =
+                                  // Arabic small waw U+06E5
+      {false, false, "\x9B\xA5"}, // [1<0>01 1011] [1010 0101]
+      {false, false, "\xDB\x25"}, // [1101 1011] [<0>010 0101]
+      {false, false, "\xDB\xE5"}, // [1101 1011] [1<1>10 0101]
+      {true, false, "\xCC\x81"},  // [1100 1100] [1000 0001] =
+                                  // combining char U+0301
+      {false, false, "\x8C\x81"}, // [1<0>00 1100] [1000 0001]
+      {false, false, "\xCC\x01"}, // [1100 1100] [<0>000 0001]
+      {false, false, "\xCC\xC1"}, // [1100 1100] [1<1>00 0001]
+
+      // 3-byte UTF-8: [1110 xxxx] [10xx xxxx] [10xxxxxx]
+      {true, true, "\xE0\xA4\x85"},   // [1110 0000] [1010 0100] [1000 0101] =
+                                      // Devanagari Letter A U+0905
+      {false, false, "\xA0\xA4\x85"}, // [1<0>10 0000] [1010 0100] [1000 0101]
+      {false, false, "\xE0\x24\x85"}, // [1110 0000] [<0>010 0100] [1000 0101]
+      {false, false, "\xE0\xE4\x85"}, // [1110 0000] [1<1>10 0100] [1000 0101]
+      {false, false, "\xE0\xA4\x05"}, // [1110 0000] [1010 0100] [<0>000 0101]
+      {false, false, "\xE0\xA4\xC5"}, // [1110 0000] [1010 0100] [1<1>00 0101]
+      {true, false, "\xE0\xA4\x81"},  // [1110 0000] [1010 0100] [1000 0001] =
+                                      // combining char U+0901
+      {false, false, "\xA0\xA4\x81"}, // [1<0>10 0000] [1010 0100] [1000 0001]
+      {false, false, "\xE0\x24\x81"}, // [1110 0000] [<0>010 0100] [1000 0001]
+      {false, false, "\xE0\xE4\x81"}, // [1110 0000] [1<1>10 0100] [1000 0001]
+      {false, false, "\xE0\xA4\x01"}, // [1110 0000] [1010 0100] [<0>000 0001]
+      {false, false, "\xE0\xA4\xC1"}, // [1110 0000] [1010 0100] [1<1>00 0001]
+  };
+  const bool atNameStart[] = {true, false};
+
+  size_t i = 0;
+  char doc[1024];
+  size_t failCount = 0;
+
+  for (; i < sizeof(cases) / sizeof(cases[0]); i++) {
+    size_t j = 0;
+    for (; j < sizeof(atNameStart) / sizeof(atNameStart[0]); j++) {
+      const bool expectedSuccess
+          = atNameStart[j] ? cases[i].goodNameStart : cases[i].goodName;
+      sprintf(doc, "<%s%s><!--", atNameStart[j] ? "" : "a", cases[i].tagName);
+      XML_Parser parser = XML_ParserCreate(NULL);
+
+      const enum XML_Status status
+          = XML_Parse(parser, doc, (int)strlen(doc), /*isFinal=*/XML_FALSE);
+
+      bool success = true;
+      if ((status == XML_STATUS_OK) != expectedSuccess) {
+        success = false;
+      }
+      if ((status == XML_STATUS_ERROR)
+          && (XML_GetErrorCode(parser) != XML_ERROR_INVALID_TOKEN)) {
+        success = false;
+      }
+
+      if (! success) {
+        fprintf(
+            stderr,
+            "FAIL case %2u (%sat name start, %u-byte sequence, error code %d)\n",
+            (unsigned)i + 1u, atNameStart[j] ? "    " : "not ",
+            (unsigned)strlen(cases[i].tagName), XML_GetErrorCode(parser));
+        failCount++;
+      }
+
+      XML_ParserFree(parser);
+    }
+  }
+
+  if (failCount > 0) {
+    fail("UTF-8 regression detected");
+  }
+}
+END_TEST
+
 /* Test trailing spaces in elements are accepted */
 /* Test trailing spaces in elements are accepted */
 static void XMLCALL
 static void XMLCALL
 record_element_end_handler(void *userData, const XML_Char *name) {
 record_element_end_handler(void *userData, const XML_Char *name) {
@@ -6175,6 +6350,14 @@ START_TEST(test_bad_doctype) {
 }
 }
 END_TEST
 END_TEST
 
 
+START_TEST(test_bad_doctype_utf8) {
+  const char *text = "<!DOCTYPE \xDB\x25"
+                     "doc><doc/>"; // [1101 1011] [<0>010 0101]
+  expect_failure(text, XML_ERROR_INVALID_TOKEN,
+                 "Invalid UTF-8 in DOCTYPE not faulted");
+}
+END_TEST
+
 START_TEST(test_bad_doctype_utf16) {
 START_TEST(test_bad_doctype_utf16) {
   const char text[] =
   const char text[] =
       /* <!DOCTYPE doc [ \x06f2 ]><doc/>
       /* <!DOCTYPE doc [ \x06f2 ]><doc/>
@@ -7220,6 +7403,35 @@ START_TEST(test_ns_double_colon_doctype) {
 }
 }
 END_TEST
 END_TEST
 
 
+START_TEST(test_ns_separator_in_uri) {
+  struct test_case {
+    enum XML_Status expectedStatus;
+    const char *doc;
+  };
+  struct test_case cases[] = {
+      {XML_STATUS_OK, "<doc xmlns='one_two' />"},
+      {XML_STATUS_ERROR, "<doc xmlns='one&#x0A;two' />"},
+  };
+
+  size_t i = 0;
+  size_t failCount = 0;
+  for (; i < sizeof(cases) / sizeof(cases[0]); i++) {
+    XML_Parser parser = XML_ParserCreateNS(NULL, '\n');
+    XML_SetElementHandler(parser, dummy_start_element, dummy_end_element);
+    if (XML_Parse(parser, cases[i].doc, (int)strlen(cases[i].doc),
+                  /*isFinal*/ XML_TRUE)
+        != cases[i].expectedStatus) {
+      failCount++;
+    }
+    XML_ParserFree(parser);
+  }
+
+  if (failCount) {
+    fail("Namespace separator handling is broken");
+  }
+}
+END_TEST
+
 /* Control variable; the number of times duff_allocator() will successfully
 /* Control variable; the number of times duff_allocator() will successfully
  * allocate */
  * allocate */
 #define ALLOC_ALWAYS_SUCCEED (-1)
 #define ALLOC_ALWAYS_SUCCEED (-1)
@@ -7376,7 +7588,7 @@ START_TEST(test_misc_version) {
     fail("Version mismatch");
     fail("Version mismatch");
 
 
 #if ! defined(XML_UNICODE) || defined(XML_UNICODE_WCHAR_T)
 #if ! defined(XML_UNICODE) || defined(XML_UNICODE_WCHAR_T)
-  if (xcstrcmp(version_text, XCS("expat_2.4.4"))) /* needs bump on releases */
+  if (xcstrcmp(version_text, XCS("expat_2.4.6"))) /* needs bump on releases */
     fail("XML_*_VERSION in expat.h out of sync?\n");
     fail("XML_*_VERSION in expat.h out of sync?\n");
 #else
 #else
   /* If we have XML_UNICODE defined but not XML_UNICODE_WCHAR_T
   /* If we have XML_UNICODE defined but not XML_UNICODE_WCHAR_T
@@ -11727,6 +11939,7 @@ make_suite(void) {
   tcase_add_test(tc_basic, test_memory_allocation);
   tcase_add_test(tc_basic, test_memory_allocation);
   tcase_add_test(tc_basic, test_default_current);
   tcase_add_test(tc_basic, test_default_current);
   tcase_add_test(tc_basic, test_dtd_elements);
   tcase_add_test(tc_basic, test_dtd_elements);
+  tcase_add_test(tc_basic, test_dtd_elements_nesting);
   tcase_add_test__ifdef_xml_dtd(tc_basic, test_set_foreign_dtd);
   tcase_add_test__ifdef_xml_dtd(tc_basic, test_set_foreign_dtd);
   tcase_add_test__ifdef_xml_dtd(tc_basic, test_foreign_dtd_not_standalone);
   tcase_add_test__ifdef_xml_dtd(tc_basic, test_foreign_dtd_not_standalone);
   tcase_add_test__ifdef_xml_dtd(tc_basic, test_invalid_foreign_dtd);
   tcase_add_test__ifdef_xml_dtd(tc_basic, test_invalid_foreign_dtd);
@@ -11841,6 +12054,7 @@ make_suite(void) {
   tcase_add_test(tc_basic, test_ext_entity_utf8_non_bom);
   tcase_add_test(tc_basic, test_ext_entity_utf8_non_bom);
   tcase_add_test(tc_basic, test_utf8_in_cdata_section);
   tcase_add_test(tc_basic, test_utf8_in_cdata_section);
   tcase_add_test(tc_basic, test_utf8_in_cdata_section_2);
   tcase_add_test(tc_basic, test_utf8_in_cdata_section_2);
+  tcase_add_test(tc_basic, test_utf8_in_start_tags);
   tcase_add_test(tc_basic, test_trailing_spaces_in_elements);
   tcase_add_test(tc_basic, test_trailing_spaces_in_elements);
   tcase_add_test(tc_basic, test_utf16_attribute);
   tcase_add_test(tc_basic, test_utf16_attribute);
   tcase_add_test(tc_basic, test_utf16_second_attr);
   tcase_add_test(tc_basic, test_utf16_second_attr);
@@ -11849,6 +12063,7 @@ make_suite(void) {
   tcase_add_test(tc_basic, test_bad_attr_desc_keyword);
   tcase_add_test(tc_basic, test_bad_attr_desc_keyword);
   tcase_add_test(tc_basic, test_bad_attr_desc_keyword_utf16);
   tcase_add_test(tc_basic, test_bad_attr_desc_keyword_utf16);
   tcase_add_test(tc_basic, test_bad_doctype);
   tcase_add_test(tc_basic, test_bad_doctype);
+  tcase_add_test(tc_basic, test_bad_doctype_utf8);
   tcase_add_test(tc_basic, test_bad_doctype_utf16);
   tcase_add_test(tc_basic, test_bad_doctype_utf16);
   tcase_add_test(tc_basic, test_bad_doctype_plus);
   tcase_add_test(tc_basic, test_bad_doctype_plus);
   tcase_add_test(tc_basic, test_bad_doctype_star);
   tcase_add_test(tc_basic, test_bad_doctype_star);
@@ -11905,6 +12120,7 @@ make_suite(void) {
   tcase_add_test(tc_namespace, test_ns_utf16_doctype);
   tcase_add_test(tc_namespace, test_ns_utf16_doctype);
   tcase_add_test(tc_namespace, test_ns_invalid_doctype);
   tcase_add_test(tc_namespace, test_ns_invalid_doctype);
   tcase_add_test(tc_namespace, test_ns_double_colon_doctype);
   tcase_add_test(tc_namespace, test_ns_double_colon_doctype);
+  tcase_add_test(tc_namespace, test_ns_separator_in_uri);
 
 
   suite_add_tcase(s, tc_misc);
   suite_add_tcase(s, tc_misc);
   tcase_add_checked_fixture(tc_misc, NULL, basic_teardown);
   tcase_add_checked_fixture(tc_misc, NULL, basic_teardown);

+ 1 - 1
libs/expat/win32/expat.iss

@@ -36,7 +36,7 @@
 ; OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 ; OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
 ; USE OR OTHER DEALINGS IN THE SOFTWARE.
 ; USE OR OTHER DEALINGS IN THE SOFTWARE.
 
 
-#define expatVer "2.4.4"
+#define expatVer "2.4.6"
 
 
 [Setup]
 [Setup]
 AppName=Expat
 AppName=Expat

+ 1 - 1
libs/expat/xmlwf/xmlfile.c

@@ -10,7 +10,7 @@
    Copyright (c) 2000      Clark Cooper <[email protected]>
    Copyright (c) 2000      Clark Cooper <[email protected]>
    Copyright (c) 2002-2003 Fred L. Drake, Jr. <[email protected]>
    Copyright (c) 2002-2003 Fred L. Drake, Jr. <[email protected]>
    Copyright (c) 2004-2006 Karl Waclawek <[email protected]>
    Copyright (c) 2004-2006 Karl Waclawek <[email protected]>
-   Copyright (c) 2005-2007 Steven Solie <s[email protected]>
+   Copyright (c) 2005-2007 Steven Solie <s[email protected]>
    Copyright (c) 2016-2021 Sebastian Pipping <[email protected]>
    Copyright (c) 2016-2021 Sebastian Pipping <[email protected]>
    Copyright (c) 2017      Rhodri James <[email protected]>
    Copyright (c) 2017      Rhodri James <[email protected]>
    Copyright (c) 2019      David Loffredo <[email protected]>
    Copyright (c) 2019      David Loffredo <[email protected]>

+ 1 - 1
libs/expat/xmlwf/xmlwf.c

@@ -10,7 +10,7 @@
    Copyright (c) 2000      Clark Cooper <[email protected]>
    Copyright (c) 2000      Clark Cooper <[email protected]>
    Copyright (c) 2001-2003 Fred L. Drake, Jr. <[email protected]>
    Copyright (c) 2001-2003 Fred L. Drake, Jr. <[email protected]>
    Copyright (c) 2004-2009 Karl Waclawek <[email protected]>
    Copyright (c) 2004-2009 Karl Waclawek <[email protected]>
-   Copyright (c) 2005-2007 Steven Solie <s[email protected]>
+   Copyright (c) 2005-2007 Steven Solie <s[email protected]>
    Copyright (c) 2016-2022 Sebastian Pipping <[email protected]>
    Copyright (c) 2016-2022 Sebastian Pipping <[email protected]>
    Copyright (c) 2017      Rhodri James <[email protected]>
    Copyright (c) 2017      Rhodri James <[email protected]>
    Copyright (c) 2019      David Loffredo <[email protected]>
    Copyright (c) 2019      David Loffredo <[email protected]>