untrusted comment: verify with openbsd-79-base.pub
RWTSdNN9A3yvWBaXW20zVPR4IRgze1LunEVMJE1cKCvYye/I8/iTgyG6RPpeL0KtIZOnjRqmd/DLuqnzWWKCISRbGdxn7ECPEQc=
OpenBSD 7.9 errata 014, August 22, 2026:
Backport all changes from libexpat 2.8.3.
CVE-2026-45186 CVE-2026-50219 CVE-2026-56131 CVE-2026-56132
CVE-2026-56403 CVE-2026-56404 CVE-2026-56405 CVE-2026-56406
CVE-2026-56407 CVE-2026-56408 CVE-2026-56409 CVE-2026-56410
CVE-2026-56411 CVE-2026-56412 CVE-2026-72522
Apply by doing:
signify -Vep /etc/signify/openbsd-79-base.pub -x 014_expat.patch.sig \
-m - | (cd /usr/src && patch -p0)
And then rebuild and install libexpat:
cd /usr/src/lib/libexpat
make obj
make
make install
Index: lib/libexpat/Changes
===================================================================
RCS file: /cvs/src/lib/libexpat/Changes,v
diff -u -p -r1.35 Changes
--- lib/libexpat/Changes 29 Apr 2026 18:07:41 -0000 1.35
+++ lib/libexpat/Changes 14 Aug 2026 17:31:10 -0000
@@ -6,29 +6,201 @@
|_| XML parser
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
-!! !!
-!! ~~~~~~~~~~~~ !!
-!! The following topics need *additional skilled C developers* to progress !!
-!! in a timely manner or at all (loosely ordered by descending priority): !!
-!! _______________________ !!
-!! - teaming up on fixing the UNFIXED SECURITY ISSUES listed at: !!
-!! """"""""""""""""""""""" !!
-!! https://github.com/libexpat/libexpat/issues/1160 !!
+!! !!
+!! Please see https://github.com/libexpat/libexpat/issues/1160 for details. !!
!! !!
-!! - teaming up on researching and fixing future security reports and !!
-!! ClusterFuzz findings with few-days-max response times in communication !!
-!! in order to (1) have a sound fix ready before the end of a 90 days !!
-!! grace period and (2) in a sustainable manner, !!
-!! !!
-!! - implementing and auto-testing XML 1.0r5 support !!
-!! (needs discussion before pull requests), !!
-!! !!
-!! For details, please reach out via e-mail to sebastian@pipping.org so we !!
-!! can schedule a voice call on the topic, in English or German. !!
-!! !!
-!! THANK YOU! Sebastian Pipping -- Berlin, 2026-03-17 !!
+!! Starting 2026-08-01, for up to six months my work maintaining libexpat !!
+!! will be funded by the City of Munich as part of their !!
+!! Open Source Sabbatical (https://opensource.muenchen.de/sabbatical.html) !!
+!! — thank you! !!
+!! Sebastian Pipping -- Berlin, 2026-08-03 !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+Mon August 10 2026
+ Security fixes:
+ #1296 CVE-2026-72522 -- Fix an out-of-bounds read and the resulting
+ infinite loop caused by treating low surrogates (Unicode)
+ the same as high surrogates in functions *_toUtf16.
+ Needs Expat compiled with 16bit character support
+ (e.g. with Firefox and/or on Windows) to be affected.
+ Upstream CVSS 3.1 vector:
+ AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H (CVSS score: 7.5)
+ (Note the "AV:N" for network/remote, the "AV:L" in NVD by
+ Mitre is mistaken.)
+ Original bug report from Mozilla at:
+ https://bugzilla.mozilla.org/show_bug.cgi?id=2053153
+
+ Bug fixes:
+ #1297 #1300 lib: Fix support for 2+ GiB documents (regression from 2.8.2)
+ #1286 lib: Reject empty version in the XML declaration
+ #1305 #1306 lib: Fix printf format for AIX
+
+ Other changes:
+ #1309 CMake|AIX: Enable EXPAT_DEV_URANDOM by default for AIX
+ #1295 CMake|Windows: Add a 64bit MinGW toolchain file
+ #1287 #1289 CMake|Windows: Start invoking MSVC with /source-charset:utf-8
+ #1289 CMake|Windows: Start requiring MSVC 2015 Update 2 or later
+ #1300 Document the current wrap-around issues with functions
+ - XML_GetCurrentByteIndex
+ - XML_GetCurrentColumnNumber
+ - XML_GetCurrentLineNumber
+ - XML_GetAttributeInfo
+ explicitly.
+ #1303 Address Clang Static Analyzer 22 warning
+ `core.NullPointerArithm`
+ #1313 #1314 Version info bumped from 13:2:12 (libexpat*.so.1.12.2)
+ to 13:3:12 (libexpat*.so.1.12.3); see https://verbump.de/
+ for what these numbers do
+
+ Infrastructure:
+ #1311 CI: Limit workflow runtime and package installation runtime
+ #1310 CI: Pin Cppcheck version for a robust CI
+ #1310 CI: Migrate Cppcheck CI from macOS to Linux
+ #1312 CI: Get CFLAGS and CXXFLAGS back in sync for both Emscripten
+ and WASI SDK
+ #1304 CI: Activate AddressSanitizer for MSVC Windows CI
+ #1308 CI: Introduce zizmor static analysis for GitHub Actions
+ #1308 CI: Start using `persist-credentials: false` with Git checkout
+ #1219 CI: Add a 7 day cooldown to Dependabot for GitHub Actions
+ #1302 #1303 CI: Bump Clang from 21 to 22
+ #1293 #1294 Update project status for 2026-08
+ #1301 #1307 Add SPDX license identifiers to the source code
+
+ Special thanks to:
+ Evgeny Kotkov
+ Henri Sivonen
+ Kartik Kenchi
+ Matthew Fernandez
+ Matthew Wozniczka
+ Stan Ulbrych
+ Tuukka Pasanen
+ William Woodruff
+ and
+ Anthropic
+ City of Munich Open Source Sabbatical
+ Mozilla Security Team
+ Subversion
+ zizmor static analysis
+
+Thu June 25 2026
+ Security fixes:
+ #1246 CVE-2026-50219 -- Disallow calls to functions
+ `XML_GetBuffer`, `XML_Parse`, `XML_ParseBuffer`,
+ `XML_ParserFree`, `XML_ParserReset` to guard e.g.
+ Expat bindings from memory corruption;
+ this CPython issue is related:
+ https://github.com/python/cpython/issues/146169
+ #1267 CVE-2026-56131 -- Protect XML_ResumeParser from being called
+ from a handler, plugging a hole in the fix
+ to CVE-2026-50219
+ #1272 CVE-2026-56132 -- Fix out-of-bound scaffolding index store
+ in `doProlog`
+ #1229 #1232 CVE-2026-56403 -- Integer overflow in `storeAtts`
+ #1249 CVE-2026-56404 -- Integer overflow in `addBinding`
+ #1251 CVE-2026-56405 -- Integer overflow in `getAttributeId`
+ #1255 CVE-2026-56406 -- Integer overflow in `XML_ParseBuffer`
+ #1262 CVE-2026-56407 -- Integer overflow in `textLen` handling
+ #565 CVE-2026-56408 -- Integer overflow in `copyString`
+ (commit 16e2efd867ea8567ffa012210b52ef5918e20817)
+ #1259 CVE-2026-56409 -- xmlwf: Integer overflow in output path join
+ #1252 CVE-2026-56410 -- xmlwf: Integer overflow in
+ `resolveSystemId`
+ #1263 CVE-2026-56411 -- xmlwf: Integer overflow in notation list
+ allocation
+ #1278 CVE-2026-56412 -- Guard XML_TOK_DATA_CHARS handler calls in
+ `doCdataSection`, plugging a hole in the fix to
+ CVE-2026-50219
+
+ Bug fixes:
+ #1260 xmlwf: Escape names and base URI in meta output
+ #1266 xmlwf: Pick a safe quote for notation system and public IDs
+
+ Other changes:
+ #1257 CMake|Autotools: Stop using /dev/urandom by default
+ #1244 #1254 CMake: Fix guard for Unix sources of entropy
+ #1183 #1270 CMake|Windows: Add missing export for symbol
+ `XML_SetHashSalt16Bytes`
+ #1236 CMake: Mark option EXPAT_OSSFUZZ_BUILD as advanced
+ #1283 Limit output indentation for EXPAT_ENTITY_DEBUG=1 and
+ allow unlimited indentation via EXPAT_ENTITY_DEBUG=2
+ #565 Replace some loops by use of `memcpy`, `strlen`, `wcslen`
+ #1220 lib: Use a size_t for group sizes
+ #1221 lib: Fix too-conservative integer overflow check when
+ appending raw name
+ #1222 lib: Simplify attribute allocation/management logic
+ #1224 Update fallthrough annotations to satisfy Clang and GCC
+ #1226 lib: Remove unnecessary void * casts in random code
+ #1228 lib: Reduce scope of locals in storeAtts
+ #1230 lib: Count attributes with size_t variables
+ #1238 Minor get-buffer improvements
+ #1239 #1240 lib|tests: Include header expat_config.h first
+ #1241 lib: Shrink size of XML_GetBuffer
+ #1242 lib: Remove a legacy comment
+ #1243 lib: XML_ParserReset: Extract repeated linked-list move logic
+ #1243 lib: Unify entity free lists
+ #1247 lib: Fix use of '0' as boolean literal
+ #1248 lib: Make XML_Index overflow check more intuitive
+ #1256 lib: Use size_t for counting string/URI lengths
+ #1258 lib: XML_GetInputContext: Remove use of 0 for NULL
+ #1261 Comment typo fixes
+ #1275 Teach Memory Sanitizer semantics of randomization functions
+ #1276 #1281 Version info bumped from 13:1:12 (libexpat*.so.1.12.1)
+ to 13:2:12 (libexpat*.so.1.12.2); see https://verbump.de/
+ for what these numbers do
+
+ Infrastructure:
+ #1231 perl-integration.yml: Bump to XML::Parser 2.59
+ #1237 emscripten.yml: Bump from Ubuntu 22.04 to 24.04
+ #1183 #1271 windows-build.yml: Cover completeness of file
+ libexpat.def.cmake
+ #1274 linux.yml: Make llvm-symbolizer available in CI
+
+ Special thanks to:
+ Alessandro Gario
+ Asher Darden
+ Christoph Reiter
+ Haris Hussain
+ Matthew Fernandez
+ Kartik Kenchi
+ Nick Begg
+ Sajin S
+ Yousef Shanableh
+ and
+ Anthropic
+ Astra Security
+ Trail of Bits
+
+Sun May 10 2026
+ Security fixes:
+ #1216 CVE-2026-45186 -- Fix quadratic runtime from attribute name
+ collision checks that allowed denial of service attacks
+ through moderately sized crafted XML input (CWE-407).
+ Please note that a layer of compression around XML can
+ significantly reduce the minimum attack payload size.
+ Upstream CVSS 3.1 vector:
+ AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H (CVSS score: 7.5)
+ (Note the "AV:N" for network/remote and the "AC:L"
+ for low complexity; the NVD entry from Mitre is mistaken.)
+
+ Other changes:
+ #1209 #1213 Drop more casts related to `void *` that C99 does not need
+ #1213 xmlwf: Streamline use of `mmap`
+ #1214 #1217 Version info bumped from 13:0:12 (libexpat*.so.1.12.0)
+ to 13:1:12 (libexpat*.so.1.12.1); see https://verbump.de/
+ for what these numbers do
+
+ Infrastructure:
+ #1210 CI: Cover compilation with Visual Studio 18 2026 on Windows
+ #1215 CI: Cover compilation for ARM64 on Windows
+ #1212 CI: Bump WASI SDK from 32 to 33
+
+ Special thanks to:
+ Berkay Eren Ürün
+ Matthew Fernandez
+ Nick Wellnhofer
+ Tania Somanna
+
+Fri April 24 2026
Security fixes:
#47 #1183 CVE-2026-41080 -- The existing hash flooding protection
(based on SipHash) only used 4 to 8 bytes of entropy for
@@ -45,6 +217,55 @@
internal machinery (by *not* calling either of the two
XML_SetHashSalt* functions).
+ Bug fixes:
+ #1188 Avoid propagating /dev/urandom file descriptor to child
+ processes
+ #1193 Fix interpretation of `errno` after randomization calls
+ #1195 Avoid assuming uint8_t is a character type
+
+ Other changes:
+ #1180 #1199 Add support for `getentropy(3)` as a source of entropy;
+ this helps with protecting against hash flooding attacks,
+ in particular with WASI SDK (where none of the other
+ entropy sources supported by libexpat are available).
+ #1200 Autotools: Add `--without-arc4random` and
+ `--without-arc4random-buf`
+ #1200 Autotools: Make `./configure` output report on available
+ high quality entropy sources
+ #1173 Autotools|macOS: Sync CMake templates with CMake 4.3.0
+ #1201 Autotools|CMake: Improve checks for `arc4random` and
+ `arc4random_buf` e.g. with modern glibc
+ #1201 CMake: Report on availability of functions `arc4random` and
+ `arc4random_buf`
+ #1201 CMake: Mark entropy related build switches as advanced
+ #1189 ..
+ #1203 #1204 Extract new files from entropy extraction code
+ #1194 Stop duplicating C tests 1:1 as C++ ("runtests_cxx")
+ #1202 Fix a comment typo in expat_external.h
+ #1187 Fix grammar in compile error message
+ #1192 examples: Build warning-free with -Wwrite-strings
+ #1171 tests: Address harmless warning from Coverity
+ #1170 #1176 Sync file headers
+ #1190 #1206 Version info bumped from 12:3:11 (libexpat*.so.1.11.3)
+ to 13:0:12 (libexpat*.so.1.12.0); see https://verbump.de/
+ for what these numbers do
+
+ Infrastructure:
+ #1166 #1167 ..
+ #1172 #1175 ..
+ #1178 #1179 ..
+ #1185 #1205 CI: Make Perl XML::Parser integration tests run against
+ both version 2.47 and the latest release 2.58
+ #1169 CI: Adapt to breaking changes regarding Inno Setup
+ #1173 CI: Adapt to breaking changes regarding CMake
+ #1174 CI: Include public corpus of fuzzer `xml_lpm_fuzzer` with
+ regression testing
+ #1181 #1182 CI: Bump WASI SDK from 30 to 32
+
+ Special thanks to:
+ Jérôme Duval
+ Matthew Fernandez
+
Release 2.7.5 Tue March 17 2026
Security fixes:
#1158 CVE-2026-32776 -- Fix NULL function pointer dereference for
@@ -1744,7 +1965,7 @@ Release 2.1.0 Sat March 24 2012
- Bug Fixes:
#1742315: Harmful XML_ParserCreateNS suggestion.
#1785430: Expat build fails on linux-amd64 with gcc version>=4.1 -O3.
- #1983953, 2517952, 2517962, 2649838:
+ #1983953, 2517952, 2517962, 2649838:
Build modifications using autoreconf instead of buildconf.sh.
#2815947, #2884086: OBJEXT and EXEEXT support while building.
#2517938: xmlwf should return non-zero exit status if not well-formed.
@@ -1770,7 +1991,7 @@ Release 2.1.0 Sat March 24 2012
See bug #2990652 and patch #3312568.
Added run-benchmark target to Makefile.in - relies on testdata module
present in the same relative location as in the repository.
-
+
Release 2.0.1 Tue June 5 2007
- Fixed bugs #1515266, #1515600: The character data handler's calling
of XML_StopParser() was not handled properly; if the parser was
Index: lib/libexpat/expat_config.h
===================================================================
RCS file: /cvs/src/lib/libexpat/expat_config.h,v
diff -u -p -r1.6 expat_config.h
--- lib/libexpat/expat_config.h 11 Feb 2024 00:56:28 -0000 1.6
+++ lib/libexpat/expat_config.h 14 Aug 2026 17:31:10 -0000
@@ -2,7 +2,6 @@
/* quick and dirty conf for OpenBSD */
-#define HAVE_ARC4RANDOM 1
#define HAVE_ARC4RANDOM_BUF 1
#define XML_CONTEXT_BYTES 1024
#define XML_DTD 1
Index: lib/libexpat/lib/ascii.h
===================================================================
RCS file: /cvs/src/lib/libexpat/lib/ascii.h,v
diff -u -p -r1.4 ascii.h
--- lib/libexpat/lib/ascii.h 26 May 2021 19:14:32 -0000 1.4
+++ lib/libexpat/lib/ascii.h 14 Aug 2026 17:31:10 -0000
@@ -31,6 +31,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#define ASCII_A 0x41
Index: lib/libexpat/lib/asciitab.h
===================================================================
RCS file: /cvs/src/lib/libexpat/lib/asciitab.h,v
diff -u -p -r1.4 asciitab.h
--- lib/libexpat/lib/asciitab.h 26 May 2021 19:14:32 -0000 1.4
+++ lib/libexpat/lib/asciitab.h 14 Aug 2026 17:31:10 -0000
@@ -30,6 +30,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
/* 0x00 */ BT_NONXML, BT_NONXML, BT_NONXML, BT_NONXML,
Index: lib/libexpat/lib/expat_external.h
===================================================================
RCS file: /cvs/src/lib/libexpat/lib/expat_external.h,v
diff -u -p -r1.11 expat_external.h
--- lib/libexpat/lib/expat_external.h 18 Mar 2026 11:50:19 -0000 1.11
+++ lib/libexpat/lib/expat_external.h 14 Aug 2026 17:31:10 -0000
@@ -12,9 +12,10 @@
Copyright (c) 2001-2002 Greg Stein
Copyright (c) 2002-2006 Karl Waclawek
Copyright (c) 2016 Cristian Rodríguez
- Copyright (c) 2016-2026 Sebastian Pipping
+ Copyright (c) 2016-2025 Sebastian Pipping
Copyright (c) 2017 Rhodri James
Copyright (c) 2018 Yury Gribov
+ Copyright (c) 2026 Matthew Fernandez
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -35,6 +36,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#ifndef Expat_External_INCLUDED
@@ -45,7 +48,7 @@
/* Expat tries very hard to make the API boundary very specifically
defined. There are two macros defined to control this boundary;
each of these can be defined before including this header to
- achieve some different behavior, but doing so it not recommended or
+ achieve some different behavior, but doing so is not recommended or
tested frequently.
XMLCALL - The calling convention to use for all calls across the
Index: lib/libexpat/lib/iasciitab.h
===================================================================
RCS file: /cvs/src/lib/libexpat/lib/iasciitab.h,v
diff -u -p -r1.4 iasciitab.h
--- lib/libexpat/lib/iasciitab.h 26 May 2021 19:14:32 -0000 1.4
+++ lib/libexpat/lib/iasciitab.h 14 Aug 2026 17:31:10 -0000
@@ -30,6 +30,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
/* Like asciitab.h, except that 0xD has code BT_S rather than BT_CR */
Index: lib/libexpat/lib/internal.h
===================================================================
RCS file: /cvs/src/lib/libexpat/lib/internal.h,v
diff -u -p -r1.17 internal.h
--- lib/libexpat/lib/internal.h 29 Apr 2026 18:07:41 -0000 1.17
+++ lib/libexpat/lib/internal.h 14 Aug 2026 17:31:10 -0000
@@ -28,7 +28,7 @@
Copyright (c) 2002-2003 Fred L. Drake, Jr.
Copyright (c) 2002-2006 Karl Waclawek
Copyright (c) 2003 Greg Stein
- Copyright (c) 2016-2025 Sebastian Pipping
+ Copyright (c) 2016-2026 Sebastian Pipping
Copyright (c) 2018 Yury Gribov
Copyright (c) 2019 David Loffredo
Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow
@@ -53,6 +53,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#if defined(__GNUC__) && defined(__i386__) && ! defined(__MINGW32__)
@@ -123,20 +125,11 @@
# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "u"
# endif
#else
+# include // PRIdPTR, PRIuPTR
# define EXPAT_FMT_LLX(midpart) "%" midpart "llx"
# define EXPAT_FMT_ULL(midpart) "%" midpart "llu"
-# if ! defined(ULONG_MAX)
-# error Compiler did not define ULONG_MAX for us
-# elif ULONG_MAX == 18446744073709551615u // 2^64-1
-# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
-# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "lu"
-# elif defined(__wasm32__) // 32bit mode Emscripten or WASI SDK
-# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "ld"
-# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "zu"
-# else
-# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "d"
-# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "u"
-# endif
+# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart PRIdPTR
+# define EXPAT_FMT_SIZE_T(midpart) "%" midpart PRIuPTR
#endif
#ifndef UNUSED_P
Index: lib/libexpat/lib/latin1tab.h
===================================================================
RCS file: /cvs/src/lib/libexpat/lib/latin1tab.h,v
diff -u -p -r1.4 latin1tab.h
--- lib/libexpat/lib/latin1tab.h 26 May 2021 19:14:32 -0000 1.4
+++ lib/libexpat/lib/latin1tab.h 14 Aug 2026 17:31:10 -0000
@@ -30,6 +30,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
/* 0x80 */ BT_OTHER, BT_OTHER, BT_OTHER, BT_OTHER,
Index: lib/libexpat/lib/nametab.h
===================================================================
RCS file: /cvs/src/lib/libexpat/lib/nametab.h,v
diff -u -p -r1.4 nametab.h
--- lib/libexpat/lib/nametab.h 26 May 2021 19:14:32 -0000 1.4
+++ lib/libexpat/lib/nametab.h 14 Aug 2026 17:31:10 -0000
@@ -28,6 +28,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
static const unsigned namingBitmap[] = {
Index: lib/libexpat/lib/siphash.h
===================================================================
RCS file: /cvs/src/lib/libexpat/lib/siphash.h,v
diff -u -p -r1.10 siphash.h
--- lib/libexpat/lib/siphash.h 5 Sep 2024 07:57:14 -0000 1.10
+++ lib/libexpat/lib/siphash.h 14 Aug 2026 17:31:10 -0000
@@ -8,6 +8,8 @@
*
* 1. https://www.131002.net/siphash/siphash24.c
* 2. https://www.131002.net/siphash/
+ *
+ * SPDX-License-Identifier: CC0-1.0
* --------------------------------------------------------------------------
* HISTORY:
*
@@ -100,6 +102,7 @@
#include /* size_t */
#include /* uint64_t uint32_t uint8_t */
+#define EXPAT_FALLTHROUGH do {} while(0)
/*
* Workaround to not require a C++11 compiler for using ULL suffix
@@ -234,25 +237,25 @@ sip24_final(struct siphash *H) {
switch (left) {
case 7:
b |= (uint64_t)H->buf[6] << 48;
- /* fall through */
+ EXPAT_FALLTHROUGH;
case 6:
b |= (uint64_t)H->buf[5] << 40;
- /* fall through */
+ EXPAT_FALLTHROUGH;
case 5:
b |= (uint64_t)H->buf[4] << 32;
- /* fall through */
+ EXPAT_FALLTHROUGH;
case 4:
b |= (uint64_t)H->buf[3] << 24;
- /* fall through */
+ EXPAT_FALLTHROUGH;
case 3:
b |= (uint64_t)H->buf[2] << 16;
- /* fall through */
+ EXPAT_FALLTHROUGH;
case 2:
b |= (uint64_t)H->buf[1] << 8;
- /* fall through */
+ EXPAT_FALLTHROUGH;
case 1:
b |= (uint64_t)H->buf[0] << 0;
- /* fall through */
+ EXPAT_FALLTHROUGH;
case 0:
break;
}
Index: lib/libexpat/lib/utf8tab.h
===================================================================
RCS file: /cvs/src/lib/libexpat/lib/utf8tab.h,v
diff -u -p -r1.4 utf8tab.h
--- lib/libexpat/lib/utf8tab.h 26 May 2021 19:14:32 -0000 1.4
+++ lib/libexpat/lib/utf8tab.h 14 Aug 2026 17:31:10 -0000
@@ -30,6 +30,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
/* 0x80 */ BT_TRAIL, BT_TRAIL, BT_TRAIL, BT_TRAIL,
Index: lib/libexpat/lib/winconfig.h
===================================================================
RCS file: /cvs/src/lib/libexpat/lib/winconfig.h,v
diff -u -p -r1.8 winconfig.h
--- lib/libexpat/lib/winconfig.h 11 Feb 2024 00:56:28 -0000 1.8
+++ lib/libexpat/lib/winconfig.h 14 Aug 2026 17:31:10 -0000
@@ -31,6 +31,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#ifndef WINCONFIG_H
Index: lib/libexpat/lib/xmlparse.c
===================================================================
RCS file: /cvs/src/lib/libexpat/lib/xmlparse.c,v
diff -u -p -r1.47 xmlparse.c
--- lib/libexpat/lib/xmlparse.c 29 Apr 2026 18:07:41 -0000 1.47
+++ lib/libexpat/lib/xmlparse.c 14 Aug 2026 17:31:11 -0000
@@ -1,4 +1,4 @@
-/* 93c1caa66e2b0310459482516af05505b57c5cb7b96df777105308fc585c85d1 (2.7.5+)
+/* ee5f82c3ffd57c5224394ba46f348dbce466d34d6c925a527ae46b1cfe6adf1d (2.8.3+)
__ __ _
___\ \/ /_ __ __ _| |_
/ _ \\ /| '_ \ / _` | __|
@@ -41,10 +41,16 @@
Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow
Copyright (c) 2024-2025 Berkay Eren Ürün
Copyright (c) 2024 Hanno Böck
- Copyright (c) 2025 Matthew Fernandez
+ Copyright (c) 2025-2026 Matthew Fernandez
Copyright (c) 2025 Atrem Borovik
Copyright (c) 2025 Alfonso Gregory
Copyright (c) 2026 Rosen Penev
+ Copyright (c) 2026 Francesco Bertolaccini
+ Copyright (c) 2026 Christian Ng
+ Copyright (c) 2026 Nick Begg
+ Copyright (c) 2026 Kartik Kenchi
+ Copyright (c) 2026 Haris Hussain
+ Copyright (c) 2026 Evgeny Kotkov
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -65,6 +71,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#define XML_BUILDING_EXPAT 1
@@ -84,28 +92,16 @@
# error XML_CONTEXT_BYTES must be defined, non-empty and >=0 (0 to disable, >=1 to enable; 1024 is a common default)
#endif
-#if defined(HAVE_SYSCALL_GETRANDOM)
-# if ! defined(_GNU_SOURCE)
-# define _GNU_SOURCE 1 /* syscall prototype */
-# endif
-#endif
-
-#ifdef _WIN32
-/* force stdlib to define rand_s() */
-# if ! defined(_CRT_RAND_S)
-# define _CRT_RAND_S
-# endif
-#endif
-
#include
#include
#include /* memset(), memcpy() */
#include
#include /* INT_MAX, UINT_MAX */
#include /* fprintf */
-#include /* getenv, rand_s */
-#include /* SIZE_MAX, uintptr_t */
+#include /* getenv */
+#include /* SIZE_MAX, UINT64_MAX, uint64_t, uintptr_t */
#include /* isnan */
+#include
#ifdef _WIN32
# define getpid GetCurrentProcessId
@@ -124,27 +120,12 @@
#include "ascii.h"
#include "expat.h"
#include "siphash.h"
-
-#if defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM)
-# if defined(HAVE_GETRANDOM)
-# include /* getrandom */
-# else
-# include /* syscall */
-# include /* SYS_getrandom */
-# endif
-# if ! defined(GRND_NONBLOCK)
-# define GRND_NONBLOCK 0x0001
-# endif /* defined(GRND_NONBLOCK) */
-#endif /* defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM) */
-
-#if defined(_WIN32) && ! defined(LOAD_LIBRARY_SEARCH_SYSTEM32)
-# define LOAD_LIBRARY_SEARCH_SYSTEM32 0x00000800
-#endif
+#define xcslen(s) (strlen(s))
#if ! defined(HAVE_GETRANDOM) && ! defined(HAVE_SYSCALL_GETRANDOM) \
&& ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM) \
- && ! defined(XML_DEV_URANDOM) && ! defined(_WIN32) \
- && ! defined(XML_POOR_ENTROPY)
+ && ! defined(HAVE_GETENTROPY) && ! defined(XML_DEV_URANDOM) \
+ && ! defined(_WIN32) && ! defined(XML_POOR_ENTROPY)
# error You do not have support for any sources of high quality entropy \
enabled. For end user security, that is probably not what you want. \
\
@@ -153,11 +134,12 @@
* Linux >=3.17 + glibc (including <2.25) (syscall SYS_getrandom): HAVE_SYSCALL_GETRANDOM, \
* BSD / macOS >=10.7 / glibc >=2.36 (arc4random_buf): HAVE_ARC4RANDOM_BUF, \
* BSD / macOS (including <10.7) / glibc >=2.36 (arc4random): HAVE_ARC4RANDOM, \
+ * BSD / macOS >=10.12 / glibc >=2.25 (getentropy): HAVE_GETENTROPY, \
* Linux (including <3.17) / BSD / macOS (including <10.7) / Solaris >=8 (/dev/urandom): XML_DEV_URANDOM, \
* Windows >=Vista (rand_s): _WIN32. \
\
- If insist on not using any of these, bypass this error by defining \
- XML_POOR_ENTROPY; you have been warned. \
+ If you insist on not using any of these, bypass this error by defining \
+ XML_POOR_ENTROPY and be vulnerable to hash flooding; you have been warned. \
\
If you have reasons to patch this detection code away or need changes \
to the build system, please open a bug. Thank you!
@@ -271,8 +253,8 @@ typedef struct binding {
struct binding *prevPrefixBinding;
const struct attribute_id *attId;
XML_Char *uri;
- int uriLen;
- int uriAlloc;
+ size_t uriLen;
+ size_t uriAlloc;
} BINDING;
typedef struct prefix {
@@ -284,9 +266,9 @@ typedef struct {
const XML_Char *str;
const XML_Char *localPart;
const XML_Char *prefix;
- int strLen;
- int uriLen;
- int prefixLen;
+ size_t strLen;
+ size_t uriLen;
+ size_t prefixLen;
} TAG_NAME;
/* TAG represents an open element.
@@ -385,9 +367,10 @@ typedef struct {
const XML_Char *name;
PREFIX *prefix;
const ATTRIBUTE_ID *idAtt;
- int nDefaultAtts;
- int allocDefaultAtts;
+ size_t nDefaultAtts;
+ size_t allocDefaultAtts;
DEFAULT_ATTRIBUTE *defaultAtts;
+ HASH_TABLE defaultAttsNames;
} ELEMENT_TYPE;
typedef struct {
@@ -417,6 +400,7 @@ typedef struct {
unsigned scaffCount;
int scaffLevel;
int *scaffIndex;
+ size_t scaffIndexSize;
} DTD;
enum EntityType {
@@ -588,6 +572,7 @@ static XML_Char *poolAppend(STRING_POOL
static XML_Char *poolStoreString(STRING_POOL *pool, const ENCODING *enc,
const char *ptr, const char *end);
static XML_Bool FASTCALL poolGrow(STRING_POOL *pool);
+static bool FASTCALL poolGrowUntil(STRING_POOL *pool, size_t needed);
static const XML_Char *FASTCALL poolCopyString(STRING_POOL *pool,
const XML_Char *s);
static const XML_Char *FASTCALL poolCopyStringNoFinish(STRING_POOL *pool,
@@ -642,16 +627,40 @@ static XML_Parser getRootParserOf(XML_Pa
static unsigned long getDebugLevel(const char *variableName,
unsigned long defaultDebugLevel);
+static bool poolAppendChar(STRING_POOL *pool, XML_Char c);
+
+static bool poolAppendChars(STRING_POOL *pool, const XML_Char *s, size_t len);
+
#define poolStart(pool) ((pool)->start)
#define poolLength(pool) ((pool)->ptr - (pool)->start)
#define poolChop(pool) ((void)--(pool->ptr))
#define poolLastChar(pool) (((pool)->ptr)[-1])
#define poolDiscard(pool) ((pool)->ptr = (pool)->start)
#define poolFinish(pool) ((pool)->start = (pool)->ptr)
-#define poolAppendChar(pool, c) \
- (((pool)->ptr == (pool)->end && ! poolGrow(pool)) \
- ? 0 \
- : ((*((pool)->ptr)++ = c), 1))
+
+bool
+poolAppendChar(STRING_POOL *pool, XML_Char c) {
+ if (pool->ptr == pool->end && ! poolGrow(pool))
+ return false;
+
+ *(pool->ptr)++ = c;
+ return true;
+}
+
+bool
+poolAppendChars(STRING_POOL *pool, const XML_Char *s, size_t len) {
+ // Detect and prevent integer overflow
+ if (len > SIZE_MAX / sizeof(XML_Char))
+ return false;
+
+ if (! poolGrowUntil(pool, len))
+ return false;
+
+ memcpy(pool->ptr, s, len * sizeof(XML_Char));
+ pool->ptr += len;
+
+ return true;
+}
#if ! defined(XML_TESTING)
const
@@ -683,7 +692,7 @@ struct XML_ParserStruct {
char *m_bufferEnd; // past last character to be parsed
const char *m_bufferLim; // allocated end of m_buffer
- XML_Index m_parseEndByteIndex;
+ uint64_t m_parseEndByteIndex;
const char *m_parseEndPtr;
size_t m_partialTokenBytesBefore; /* used in heuristic to avoid O(n^2) */
XML_Bool m_reparseDeferralEnabled;
@@ -730,11 +739,9 @@ struct XML_ParserStruct {
const char *m_eventEndPtr;
const char *m_positionPtr;
OPEN_INTERNAL_ENTITY *m_openInternalEntities;
- OPEN_INTERNAL_ENTITY *m_freeInternalEntities;
OPEN_INTERNAL_ENTITY *m_openAttributeEntities;
- OPEN_INTERNAL_ENTITY *m_freeAttributeEntities;
OPEN_INTERNAL_ENTITY *m_openValueEntities;
- OPEN_INTERNAL_ENTITY *m_freeValueEntities;
+ OPEN_INTERNAL_ENTITY *m_freeEntities;
XML_Bool m_defaultExpandInternalEntities;
int m_tagLevel;
ENTITY *m_declEntity;
@@ -754,7 +761,7 @@ struct XML_ParserStruct {
TAG *m_freeTagList;
BINDING *m_inheritedBindings;
BINDING *m_freeBindingList;
- int m_attsSize;
+ size_t m_attsSize;
int m_nSpecifiedAtts;
int m_idAttIndex;
ATTRIBUTE *m_atts;
@@ -768,7 +775,7 @@ struct XML_ParserStruct {
STRING_POOL m_tempPool;
STRING_POOL m_temp2Pool;
char *m_groupConnector;
- unsigned int m_groupSize;
+ size_t m_groupSize;
XML_Char m_namespaceSeparator;
XML_Parser m_parentParser;
XML_ParsingStatus m_parsingStatus;
@@ -785,6 +792,7 @@ struct XML_ParserStruct {
ENTITY_STATS m_entity_stats;
#endif
XML_Bool m_reenter;
+ unsigned m_handlerCallDepth;
};
#if XML_GE == 1
@@ -1037,135 +1045,6 @@ static const XML_Char implicitContext[]
ASCII_s, ASCII_p, ASCII_a, ASCII_c, ASCII_e,
'\0'};
-/* To avoid warnings about unused functions: */
-#if ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM)
-
-# if defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM)
-
-/* Obtain entropy on Linux 3.17+ */
-static int
-writeRandomBytes_getrandom_nonblock(void *target, size_t count) {
- int success = 0; /* full count bytes written? */
- size_t bytesWrittenTotal = 0;
- const unsigned int getrandomFlags = GRND_NONBLOCK;
-
- do {
- void *const currentTarget = (void *)((char *)target + bytesWrittenTotal);
- const size_t bytesToWrite = count - bytesWrittenTotal;
-
- assert(bytesToWrite <= INT_MAX);
-
- const int bytesWrittenMore =
-# if defined(HAVE_GETRANDOM)
- (int)getrandom(currentTarget, bytesToWrite, getrandomFlags);
-# else
- (int)syscall(SYS_getrandom, currentTarget, bytesToWrite,
- getrandomFlags);
-# endif
-
- if (bytesWrittenMore > 0) {
- bytesWrittenTotal += bytesWrittenMore;
- if (bytesWrittenTotal >= count)
- success = 1;
- }
- } while (! success && (errno == EINTR));
-
- return success;
-}
-
-# endif /* defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM) */
-
-# if ! defined(_WIN32) && defined(XML_DEV_URANDOM)
-
-/* Extract entropy from /dev/urandom */
-static int
-writeRandomBytes_dev_urandom(void *target, size_t count) {
- int success = 0; /* full count bytes written? */
- size_t bytesWrittenTotal = 0;
-
- const int fd = open("/dev/urandom", O_RDONLY);
- if (fd < 0) {
- return 0;
- }
-
- do {
- void *const currentTarget = (void *)((char *)target + bytesWrittenTotal);
- const size_t bytesToWrite = count - bytesWrittenTotal;
-
- const ssize_t bytesWrittenMore = read(fd, currentTarget, bytesToWrite);
-
- if (bytesWrittenMore > 0) {
- bytesWrittenTotal += bytesWrittenMore;
- if (bytesWrittenTotal >= count)
- success = 1;
- }
- } while (! success && (errno == EINTR));
-
- close(fd);
- return success;
-}
-
-# endif /* ! defined(_WIN32) && defined(XML_DEV_URANDOM) */
-
-#endif /* ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM) */
-
-#if defined(HAVE_ARC4RANDOM) && ! defined(HAVE_ARC4RANDOM_BUF)
-
-static void
-writeRandomBytes_arc4random(void *target, size_t count) {
- size_t bytesWrittenTotal = 0;
-
- while (bytesWrittenTotal < count) {
- const uint32_t random32 = arc4random();
- size_t i = 0;
-
- for (; (i < sizeof(random32)) && (bytesWrittenTotal < count);
- i++, bytesWrittenTotal++) {
- const uint8_t random8 = (uint8_t)(random32 >> (i * 8));
- ((uint8_t *)target)[bytesWrittenTotal] = random8;
- }
- }
-}
-
-#endif /* defined(HAVE_ARC4RANDOM) && ! defined(HAVE_ARC4RANDOM_BUF) */
-
-#ifdef _WIN32
-
-/* Provide declaration of rand_s() for MinGW-32 (not 64, which has it),
- as it didn't declare it in its header prior to version 5.3.0 of its
- runtime package (mingwrt, containing stdlib.h). The upstream fix
- was introduced at https://osdn.net/projects/mingw/ticket/39658 . */
-# if defined(__MINGW32__) && defined(__MINGW32_VERSION) \
- && __MINGW32_VERSION < 5003000L && ! defined(__MINGW64_VERSION_MAJOR)
-__declspec(dllimport) int rand_s(unsigned int *);
-# endif
-
-/* Obtain entropy on Windows using the rand_s() function which
- * generates cryptographically secure random numbers. Internally it
- * uses RtlGenRandom API which is present in Windows XP and later.
- */
-static int
-writeRandomBytes_rand_s(void *target, size_t count) {
- size_t bytesWrittenTotal = 0;
-
- while (bytesWrittenTotal < count) {
- unsigned int random32 = 0;
- size_t i = 0;
-
- if (rand_s(&random32))
- return 0; /* failure */
-
- for (; (i < sizeof(random32)) && (bytesWrittenTotal < count);
- i++, bytesWrittenTotal++) {
- const uint8_t random8 = (uint8_t)(random32 >> (i * 8));
- ((uint8_t *)target)[bytesWrittenTotal] = random8;
- }
- }
- return 1; /* success */
-}
-
-#endif /* _WIN32 */
-
#if ! defined(HAVE_ARC4RANDOM_BUF) && ! defined(HAVE_ARC4RANDOM)
static unsigned long
@@ -1222,6 +1101,11 @@ generate_hash_secret_salt(void) {
if (writeRandomBytes_rand_s(&entropy, sizeof(entropy))) {
return ENTROPY_DEBUG("rand_s", entropy);
}
+# elif defined(HAVE_GETENTROPY)
+ if (writeRandomBytes_getentropy(&entropy, sizeof(entropy))) {
+ return ENTROPY_DEBUG("getentropy", entropy);
+ }
+ errno = 0;
# elif defined(HAVE_GETRANDOM) || defined(HAVE_SYSCALL_GETRANDOM)
if (writeRandomBytes_getrandom_nonblock(&entropy, sizeof(entropy))) {
return ENTROPY_DEBUG("getrandom", entropy);
@@ -1252,6 +1136,23 @@ generate_hash_secret_salt(void) {
#endif
}
+static void
+beforeHandler(XML_Parser parser) {
+ assert(parser->m_handlerCallDepth < UINT_MAX);
+ parser->m_handlerCallDepth++;
+}
+
+static void
+afterHandler(XML_Parser parser) {
+ assert(parser->m_handlerCallDepth > 0);
+ parser->m_handlerCallDepth--;
+}
+
+static bool
+isCalledFromInsideHandler(XML_Parser parser) {
+ return parser->m_handlerCallDepth > 0;
+}
+
static enum XML_Error
callProcessor(XML_Parser parser, const char *start, const char *end,
const char **endPtr) {
@@ -1488,9 +1389,7 @@ parserCreate(const XML_Char *encodingNam
parser->m_freeBindingList = NULL;
parser->m_freeTagList = NULL;
- parser->m_freeInternalEntities = NULL;
- parser->m_freeAttributeEntities = NULL;
- parser->m_freeValueEntities = NULL;
+ parser->m_freeEntities = NULL;
parser->m_groupSize = 0;
parser->m_groupConnector = NULL;
@@ -1606,6 +1505,7 @@ parserInit(XML_Parser parser, const XML_
parser->m_parsingStatus.parsing = XML_INITIALIZED;
// Reentry can only be triggered inside m_processor calls
parser->m_reenter = XML_FALSE;
+ parser->m_handlerCallDepth = 0;
#ifdef XML_DTD
parser->m_isParamEntity = XML_FALSE;
parser->m_useForeignDTD = XML_FALSE;
@@ -1639,12 +1539,22 @@ moveToFreeBindingList(XML_Parser parser,
}
}
+/* Moves a list of entities onto the start of another list. */
+static void
+moveEntityList(OPEN_INTERNAL_ENTITY **dst, OPEN_INTERNAL_ENTITY **src) {
+ for (OPEN_INTERNAL_ENTITY *head = *src; head != NULL;) {
+ OPEN_INTERNAL_ENTITY *const openEntity = head;
+ head = head->next;
+ openEntity->next = *dst;
+ *dst = openEntity;
+ }
+}
+
XML_Bool XMLCALL
XML_ParserReset(XML_Parser parser, const XML_Char *encodingName) {
TAG *tStk;
- OPEN_INTERNAL_ENTITY *openEntityList;
- if (parser == NULL)
+ if ((parser == NULL) || isCalledFromInsideHandler(parser))
return XML_FALSE;
if (parser->m_parentParser)
@@ -1659,32 +1569,14 @@ XML_ParserReset(XML_Parser parser, const
tag->bindings = NULL;
parser->m_freeTagList = tag;
}
- /* move m_openInternalEntities to m_freeInternalEntities */
- openEntityList = parser->m_openInternalEntities;
- while (openEntityList) {
- OPEN_INTERNAL_ENTITY *openEntity = openEntityList;
- openEntityList = openEntity->next;
- openEntity->next = parser->m_freeInternalEntities;
- parser->m_freeInternalEntities = openEntity;
- }
- /* move m_openAttributeEntities to m_freeAttributeEntities (i.e. same task but
- * for attributes) */
- openEntityList = parser->m_openAttributeEntities;
- while (openEntityList) {
- OPEN_INTERNAL_ENTITY *openEntity = openEntityList;
- openEntityList = openEntity->next;
- openEntity->next = parser->m_freeAttributeEntities;
- parser->m_freeAttributeEntities = openEntity;
- }
- /* move m_openValueEntities to m_freeValueEntities (i.e. same task but
- * for value entities) */
- openEntityList = parser->m_openValueEntities;
- while (openEntityList) {
- OPEN_INTERNAL_ENTITY *openEntity = openEntityList;
- openEntityList = openEntity->next;
- openEntity->next = parser->m_freeValueEntities;
- parser->m_freeValueEntities = openEntity;
- }
+ /* move m_openInternalEntities to m_freeEntities */
+ moveEntityList(&parser->m_freeEntities, &parser->m_openInternalEntities);
+ /* move m_openAttributeEntities to m_freeEntities (i.e. same task but for
+ * attributes) */
+ moveEntityList(&parser->m_freeEntities, &parser->m_openAttributeEntities);
+ /* move m_openValueEntities to m_freeEntities (i.e. same task but for value
+ * entities) */
+ moveEntityList(&parser->m_freeEntities, &parser->m_openValueEntities);
moveToFreeBindingList(parser, parser->m_inheritedBindings);
FREE(parser, parser->m_unknownEncodingMem);
if (parser->m_unknownEncodingRelease)
@@ -1836,11 +1728,6 @@ XML_ExternalEntityParserCreate(XML_Parse
newDtd = oldDtd;
#endif /* XML_DTD */
- /* Note that the magical uses of the pre-processor to make field
- access look more like C++ require that `parser' be overwritten
- here. This makes this function more painful to follow than it
- would be otherwise.
- */
if (parser->m_ns) {
XML_Char tmp[2] = {parser->m_namespaceSeparator, 0};
parser = parserCreate(encodingName, &parser->m_mem, tmp, newDtd, oldParser);
@@ -1930,8 +1817,7 @@ destroyBindings(BINDING *bindings, XML_P
void XMLCALL
XML_ParserFree(XML_Parser parser) {
TAG *tagList;
- OPEN_INTERNAL_ENTITY *entityList;
- if (parser == NULL)
+ if ((parser == NULL) || isCalledFromInsideHandler(parser))
return;
/* free m_tagStack and m_freeTagList */
tagList = parser->m_tagStack;
@@ -1949,48 +1835,35 @@ XML_ParserFree(XML_Parser parser) {
destroyBindings(p->bindings, parser);
FREE(parser, p);
}
- /* free m_openInternalEntities and m_freeInternalEntities */
- entityList = parser->m_openInternalEntities;
- for (;;) {
- OPEN_INTERNAL_ENTITY *openEntity;
- if (entityList == NULL) {
- if (parser->m_freeInternalEntities == NULL)
- break;
- entityList = parser->m_freeInternalEntities;
- parser->m_freeInternalEntities = NULL;
- }
- openEntity = entityList;
+ /* free m_openInternalEntities */
+ for (OPEN_INTERNAL_ENTITY *entityList = parser->m_openInternalEntities;
+ entityList != NULL;) {
+ OPEN_INTERNAL_ENTITY *const openEntity = entityList;
entityList = entityList->next;
FREE(parser, openEntity);
}
- /* free m_openAttributeEntities and m_freeAttributeEntities */
- entityList = parser->m_openAttributeEntities;
- for (;;) {
- OPEN_INTERNAL_ENTITY *openEntity;
- if (entityList == NULL) {
- if (parser->m_freeAttributeEntities == NULL)
- break;
- entityList = parser->m_freeAttributeEntities;
- parser->m_freeAttributeEntities = NULL;
- }
- openEntity = entityList;
+ /* free m_openAttributeEntities */
+ for (OPEN_INTERNAL_ENTITY *entityList = parser->m_openAttributeEntities;
+ entityList != NULL;) {
+ OPEN_INTERNAL_ENTITY *const openEntity = entityList;
entityList = entityList->next;
FREE(parser, openEntity);
}
- /* free m_openValueEntities and m_freeValueEntities */
- entityList = parser->m_openValueEntities;
- for (;;) {
- OPEN_INTERNAL_ENTITY *openEntity;
- if (entityList == NULL) {
- if (parser->m_freeValueEntities == NULL)
- break;
- entityList = parser->m_freeValueEntities;
- parser->m_freeValueEntities = NULL;
- }
- openEntity = entityList;
+ /* free m_openValueEntities */
+ for (OPEN_INTERNAL_ENTITY *entityList = parser->m_openValueEntities;
+ entityList != NULL;) {
+ OPEN_INTERNAL_ENTITY *const openEntity = entityList;
+ entityList = entityList->next;
+ FREE(parser, openEntity);
+ }
+ /* free m_freeEntities */
+ for (OPEN_INTERNAL_ENTITY *entityList = parser->m_freeEntities;
+ entityList != NULL;) {
+ OPEN_INTERNAL_ENTITY *const openEntity = entityList;
entityList = entityList->next;
FREE(parser, openEntity);
}
+ parser->m_freeEntities = NULL;
destroyBindings(parser->m_freeBindingList, parser);
destroyBindings(parser->m_inheritedBindings, parser);
poolDestroy(&parser->m_tempPool);
@@ -2362,6 +2235,8 @@ XML_Parse(XML_Parser parser, const char
parser->m_errorCode = XML_ERROR_INVALID_ARGUMENT;
return XML_STATUS_ERROR;
}
+ if (isCalledFromInsideHandler(parser))
+ return XML_STATUS_ERROR;
switch (parser->m_parsingStatus.parsing) {
case XML_SUSPENDED:
parser->m_errorCode = XML_ERROR_SUSPENDED;
@@ -2374,7 +2249,7 @@ XML_Parse(XML_Parser parser, const char
parser->m_errorCode = XML_ERROR_NO_MEMORY;
return XML_STATUS_ERROR;
}
- /* fall through */
+ EXPAT_FALLTHROUGH;
default:
parser->m_parsingStatus.parsing = XML_PARSING;
}
@@ -2385,7 +2260,7 @@ XML_Parse(XML_Parser parser, const char
int nLeftOver;
enum XML_Status result;
/* Detect overflow (a+b > MAX <==> b > MAX-a) */
- if ((XML_Size)len > ((XML_Size)-1) / 2 - parser->m_parseEndByteIndex) {
+ if ((uint64_t)len > UINT64_MAX - parser->m_parseEndByteIndex) {
parser->m_errorCode = XML_ERROR_NO_MEMORY;
parser->m_eventPtr = parser->m_eventEndPtr = NULL;
parser->m_processor = errorProcessor;
@@ -2416,7 +2291,7 @@ XML_Parse(XML_Parser parser, const char
parser->m_parsingStatus.parsing = XML_FINISHED;
return XML_STATUS_OK;
}
- /* fall through */
+ EXPAT_FALLTHROUGH;
default:
result = XML_STATUS_OK;
}
@@ -2471,7 +2346,7 @@ XML_ParseBuffer(XML_Parser parser, int l
const char *start;
enum XML_Status result = XML_STATUS_OK;
- if (parser == NULL)
+ if ((parser == NULL) || isCalledFromInsideHandler(parser))
return XML_STATUS_ERROR;
if (len < 0) {
@@ -2497,11 +2372,19 @@ XML_ParseBuffer(XML_Parser parser, int l
parser->m_errorCode = XML_ERROR_NO_MEMORY;
return XML_STATUS_ERROR;
}
- /* fall through */
+ EXPAT_FALLTHROUGH;
default:
parser->m_parsingStatus.parsing = XML_PARSING;
}
+ // Detect and avoid integer overflow
+ if ((uint64_t)len > UINT64_MAX - parser->m_parseEndByteIndex) {
+ parser->m_errorCode = XML_ERROR_NO_MEMORY;
+ parser->m_eventPtr = parser->m_eventEndPtr = NULL;
+ parser->m_processor = errorProcessor;
+ return XML_STATUS_ERROR;
+ }
+
start = parser->m_bufferPtr;
parser->m_positionPtr = start;
parser->m_bufferEnd += len;
@@ -2527,6 +2410,7 @@ XML_ParseBuffer(XML_Parser parser, int l
parser->m_parsingStatus.parsing = XML_FINISHED;
return result;
}
+ break;
default:; /* should not happen */
}
}
@@ -2537,9 +2421,32 @@ XML_ParseBuffer(XML_Parser parser, int l
return result;
}
+/* Modifies `parser`’s buffer to be backed by `newBuf`. */
+static void
+setParserBuffer(XML_Parser parser, char *newBuf, int newBufSize, int keep) {
+ parser->m_bufferLim = newBuf + newBufSize;
+ if (parser->m_bufferPtr) {
+ const int parsing
+ = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr);
+ memcpy(newBuf, parser->m_bufferPtr - keep, parsing + keep);
+ // NOTE: We are avoiding FREE(..) here because parser->m_buffer
+ // is not being allocated with MALLOC(..) but with plain
+ // .malloc_fcn(..).
+ parser->m_mem.free_fcn(parser->m_buffer);
+ parser->m_buffer = newBuf;
+ parser->m_bufferEnd = newBuf + parsing + keep;
+ parser->m_bufferPtr = newBuf + keep;
+ } else {
+ /* This must be a brand new buffer with no data in it yet */
+ parser->m_buffer = newBuf;
+ parser->m_bufferEnd = newBuf;
+ parser->m_bufferPtr = newBuf;
+ }
+}
+
void *XMLCALL
XML_GetBuffer(XML_Parser parser, int len) {
- if (parser == NULL)
+ if ((parser == NULL) || isCalledFromInsideHandler(parser))
return NULL;
if (len < 0) {
parser->m_errorCode = XML_ERROR_NO_MEMORY;
@@ -2560,9 +2467,6 @@ XML_GetBuffer(XML_Parser parser, int len
parser->m_lastBufferRequestSize = len;
if (len > EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_bufferEnd)
|| parser->m_buffer == NULL) {
-#if XML_CONTEXT_BYTES > 0
- int keep;
-#endif /* XML_CONTEXT_BYTES > 0 */
/* Do not invoke signed arithmetic overflow: */
int neededSize = (int)((unsigned)len
+ (unsigned)EXPAT_SAFE_PTR_DIFF(
@@ -2572,7 +2476,9 @@ XML_GetBuffer(XML_Parser parser, int len
return NULL;
}
#if XML_CONTEXT_BYTES > 0
- keep = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer);
+ const int parsed
+ = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer);
+ int keep = parsed;
if (keep > XML_CONTEXT_BYTES)
keep = XML_CONTEXT_BYTES;
/* Detect and prevent integer overflow */
@@ -2580,16 +2486,16 @@ XML_GetBuffer(XML_Parser parser, int len
parser->m_errorCode = XML_ERROR_NO_MEMORY;
return NULL;
}
- neededSize += keep;
+#else
+ int keep = 0;
#endif /* XML_CONTEXT_BYTES > 0 */
+ neededSize += keep;
if (parser->m_buffer && parser->m_bufferPtr
&& neededSize
<= EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_buffer)) {
#if XML_CONTEXT_BYTES > 0
- if (keep < EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer)) {
- int offset
- = (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferPtr, parser->m_buffer)
- - keep;
+ if (keep < parsed) {
+ int offset = parsed - keep;
/* The buffer pointers cannot be NULL here; we have at least some bytes
* in the buffer */
memmove(parser->m_buffer, &parser->m_buffer[offset],
@@ -2606,7 +2512,6 @@ XML_GetBuffer(XML_Parser parser, int len
parser->m_bufferPtr = parser->m_buffer;
#endif /* XML_CONTEXT_BYTES > 0 */
} else {
- char *newBuf;
int bufferSize
= (int)EXPAT_SAFE_PTR_DIFF(parser->m_bufferLim, parser->m_buffer);
if (bufferSize == 0)
@@ -2621,49 +2526,12 @@ XML_GetBuffer(XML_Parser parser, int len
}
// NOTE: We are avoiding MALLOC(..) here to leave limiting
// the input size to the application using Expat.
- newBuf = parser->m_mem.malloc_fcn(bufferSize);
+ char *const newBuf = parser->m_mem.malloc_fcn(bufferSize);
if (newBuf == NULL) {
parser->m_errorCode = XML_ERROR_NO_MEMORY;
return NULL;
}
- parser->m_bufferLim = newBuf + bufferSize;
-#if XML_CONTEXT_BYTES > 0
- if (parser->m_bufferPtr) {
- memcpy(newBuf, &parser->m_bufferPtr[-keep],
- EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr)
- + keep);
- // NOTE: We are avoiding FREE(..) here because parser->m_buffer
- // is not being allocated with MALLOC(..) but with plain
- // .malloc_fcn(..).
- parser->m_mem.free_fcn(parser->m_buffer);
- parser->m_buffer = newBuf;
- parser->m_bufferEnd
- = parser->m_buffer
- + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr)
- + keep;
- parser->m_bufferPtr = parser->m_buffer + keep;
- } else {
- /* This must be a brand new buffer with no data in it yet */
- parser->m_bufferEnd = newBuf;
- parser->m_bufferPtr = parser->m_buffer = newBuf;
- }
-#else
- if (parser->m_bufferPtr) {
- memcpy(newBuf, parser->m_bufferPtr,
- EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr));
- // NOTE: We are avoiding FREE(..) here because parser->m_buffer
- // is not being allocated with MALLOC(..) but with plain
- // .malloc_fcn(..).
- parser->m_mem.free_fcn(parser->m_buffer);
- parser->m_bufferEnd
- = newBuf
- + EXPAT_SAFE_PTR_DIFF(parser->m_bufferEnd, parser->m_bufferPtr);
- } else {
- /* This must be a brand new buffer with no data in it yet */
- parser->m_bufferEnd = newBuf;
- }
- parser->m_bufferPtr = parser->m_buffer = newBuf;
-#endif /* XML_CONTEXT_BYTES > 0 */
+ setParserBuffer(parser, newBuf, bufferSize, keep);
}
parser->m_eventPtr = parser->m_eventEndPtr = NULL;
parser->m_positionPtr = NULL;
@@ -2716,7 +2584,7 @@ enum XML_Status XMLCALL
XML_ResumeParser(XML_Parser parser) {
enum XML_Status result = XML_STATUS_OK;
- if (parser == NULL)
+ if ((parser == NULL) || isCalledFromInsideHandler(parser))
return XML_STATUS_ERROR;
if (parser->m_parsingStatus.parsing != XML_SUSPENDED) {
parser->m_errorCode = XML_ERROR_NOT_SUSPENDED;
@@ -2742,6 +2610,7 @@ XML_ResumeParser(XML_Parser parser) {
parser->m_parsingStatus.parsing = XML_FINISHED;
return result;
}
+ break;
default:;
}
}
@@ -2771,9 +2640,15 @@ XML_Index XMLCALL
XML_GetCurrentByteIndex(XML_Parser parser) {
if (parser == NULL)
return -1;
- if (parser->m_eventPtr)
+ if (parser->m_eventPtr) {
+ // NOTE: XML_Index is known to wrap around for >2 GiB content
+ // on 32bit machines and 64bit Windows, unless (non-default and
+ // uncommon) XML_LARGE_SIZE is defined.
+ // That's a bug and it only lives on because we cannot break
+ // ABI compatibility of public API.
return (XML_Index)(parser->m_parseEndByteIndex
- (parser->m_parseEndPtr - parser->m_eventPtr));
+ }
return -1;
}
@@ -2803,7 +2678,7 @@ XML_GetInputContext(XML_Parser parser, i
(void)offset;
(void)size;
#endif /* XML_CONTEXT_BYTES > 0 */
- return (const char *)0;
+ return NULL;
}
XML_Size XMLCALL
@@ -2815,7 +2690,12 @@ XML_GetCurrentLineNumber(XML_Parser pars
parser->m_eventPtr, &parser->m_position);
parser->m_positionPtr = parser->m_eventPtr;
}
- return parser->m_position.lineNumber + 1;
+ // NOTE: XML_Size is known to wrap around for >2 4iB content
+ // on 32bit machines and 64bit Windows, unless (non-default and
+ // uncommon) XML_LARGE_SIZE is defined.
+ // That's a bug and it only lives on because we cannot break
+ // ABI compatibility of public API.
+ return (XML_Size)(parser->m_position.lineNumber + 1);
}
XML_Size XMLCALL
@@ -2827,7 +2707,12 @@ XML_GetCurrentColumnNumber(XML_Parser pa
parser->m_eventPtr, &parser->m_position);
parser->m_positionPtr = parser->m_eventPtr;
}
- return parser->m_position.columnNumber;
+ // NOTE: XML_Size is known to wrap around for >2 4iB content
+ // on 32bit machines and 64bit Windows, unless (non-default and
+ // uncommon) XML_LARGE_SIZE is defined.
+ // That's a bug and it only lives on because we cannot break
+ // ABI compatibility of public API.
+ return (XML_Size)parser->m_position.columnNumber;
}
void XMLCALL
@@ -3162,7 +3047,7 @@ storeRawNames(XML_Parser parser) {
*/
rawNameLen = ROUND_UP(tag->rawNameLength, sizeof(XML_Char));
/* Detect and prevent integer overflow. */
- if (rawNameLen > (size_t)INT_MAX - nameLen)
+ if (rawNameLen > SIZE_MAX - nameLen)
return XML_FALSE;
bufSize = nameLen + rawNameLen;
if (bufSize > (size_t)(tag->bufEnd - tag->buf.raw)) {
@@ -3289,7 +3174,7 @@ externalEntityInitProcessor3(XML_Parser
if (parser->m_reenter) {
return XML_ERROR_UNEXPECTED_STATE; // LCOV_EXCL_LINE
}
- /* Fall through */
+ EXPAT_FALLTHROUGH;
default:
start = next;
}
@@ -3368,7 +3253,9 @@ doContent(XML_Parser parser, int startTa
*eventEndPP = end;
if (parser->m_characterDataHandler) {
XML_Char c = 0xA;
+ beforeHandler(parser);
parser->m_characterDataHandler(parser->m_handlerArg, &c, 1);
+ afterHandler(parser);
} else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, end);
/* We are at the end of the final buffer, should we check for
@@ -3421,9 +3308,11 @@ doContent(XML_Parser parser, int startTa
((char *)&ch) + sizeof(XML_Char), __LINE__,
XML_ACCOUNT_ENTITY_EXPANSION);
#endif /* XML_GE == 1 */
- if (parser->m_characterDataHandler)
+ if (parser->m_characterDataHandler) {
+ beforeHandler(parser);
parser->m_characterDataHandler(parser->m_handlerArg, &ch, 1);
- else if (parser->m_defaultHandler)
+ afterHandler(parser);
+ } else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
break;
}
@@ -3443,9 +3332,11 @@ doContent(XML_Parser parser, int startTa
else if (! entity->is_internal)
return XML_ERROR_ENTITY_DECLARED_IN_PE;
} else if (! entity) {
- if (parser->m_skippedEntityHandler)
+ if (parser->m_skippedEntityHandler) {
+ beforeHandler(parser);
parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0);
- else if (parser->m_defaultHandler)
+ afterHandler(parser);
+ } else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
break;
}
@@ -3456,10 +3347,12 @@ doContent(XML_Parser parser, int startTa
if (entity->textPtr) {
enum XML_Error result;
if (! parser->m_defaultExpandInternalEntities) {
- if (parser->m_skippedEntityHandler)
+ if (parser->m_skippedEntityHandler) {
+ beforeHandler(parser);
parser->m_skippedEntityHandler(parser->m_handlerArg, entity->name,
0);
- else if (parser->m_defaultHandler)
+ afterHandler(parser);
+ } else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
break;
}
@@ -3473,9 +3366,12 @@ doContent(XML_Parser parser, int startTa
entity->open = XML_FALSE;
if (! context)
return XML_ERROR_NO_MEMORY;
- if (! parser->m_externalEntityRefHandler(
- parser->m_externalEntityRefHandlerArg, context, entity->base,
- entity->systemId, entity->publicId))
+ beforeHandler(parser);
+ const int status = parser->m_externalEntityRefHandler(
+ parser->m_externalEntityRefHandlerArg, context, entity->base,
+ entity->systemId, entity->publicId);
+ afterHandler(parser);
+ if (! status)
return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
poolDiscard(&parser->m_tempPool);
} else if (parser->m_defaultHandler)
@@ -3483,7 +3379,6 @@ doContent(XML_Parser parser, int startTa
break;
}
case XML_TOK_START_TAG_NO_ATTS:
- /* fall through */
case XML_TOK_START_TAG_WITH_ATTS: {
TAG *tag;
enum XML_Error result;
@@ -3515,11 +3410,10 @@ doContent(XML_Parser parser, int startTa
const char *fromPtr = tag->rawName;
toPtr = tag->buf.str;
for (;;) {
- int convLen;
const enum XML_Convert_Result convert_res
= XmlConvert(enc, &fromPtr, rawNameEnd, (ICHAR **)&toPtr,
(ICHAR *)tag->bufEnd - 1);
- convLen = (int)(toPtr - tag->buf.str);
+ const size_t convLen = (size_t)(toPtr - tag->buf.str);
if ((fromPtr >= rawNameEnd)
|| (convert_res == XML_CONVERT_INPUT_INCOMPLETE)) {
tag->name.strLen = convLen;
@@ -3544,16 +3438,17 @@ doContent(XML_Parser parser, int startTa
= storeAtts(parser, enc, s, &(tag->name), &(tag->bindings), account);
if (result)
return result;
- if (parser->m_startElementHandler)
+ if (parser->m_startElementHandler) {
+ beforeHandler(parser);
parser->m_startElementHandler(parser->m_handlerArg, tag->name.str,
(const XML_Char **)parser->m_atts);
- else if (parser->m_defaultHandler)
+ afterHandler(parser);
+ } else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
poolClear(&parser->m_tempPool);
break;
}
case XML_TOK_EMPTY_ELEMENT_NO_ATTS:
- /* fall through */
case XML_TOK_EMPTY_ELEMENT_WITH_ATTS: {
const char *rawName = s + enc->minBytesPerChar;
enum XML_Error result;
@@ -3573,14 +3468,18 @@ doContent(XML_Parser parser, int startTa
}
poolFinish(&parser->m_tempPool);
if (parser->m_startElementHandler) {
+ beforeHandler(parser);
parser->m_startElementHandler(parser->m_handlerArg, name.str,
(const XML_Char **)parser->m_atts);
+ afterHandler(parser);
noElmHandlers = XML_FALSE;
}
if (parser->m_endElementHandler) {
if (parser->m_startElementHandler)
*eventPP = *eventEndPP;
+ beforeHandler(parser);
parser->m_endElementHandler(parser->m_handlerArg, name.str);
+ afterHandler(parser);
noElmHandlers = XML_FALSE;
}
if (noElmHandlers && parser->m_defaultHandler)
@@ -3638,14 +3537,19 @@ doContent(XML_Parser parser, int startTa
}
*uri = XML_T('\0');
}
+ beforeHandler(parser);
parser->m_endElementHandler(parser->m_handlerArg, tag->name.str);
+ afterHandler(parser);
} else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
while (tag->bindings) {
BINDING *b = tag->bindings;
- if (parser->m_endNamespaceDeclHandler)
+ if (parser->m_endNamespaceDeclHandler) {
+ beforeHandler(parser);
parser->m_endNamespaceDeclHandler(parser->m_handlerArg,
b->prefix->name);
+ afterHandler(parser);
+ }
tag->bindings = tag->bindings->nextTagBinding;
b->nextTagBinding = parser->m_freeBindingList;
parser->m_freeBindingList = b;
@@ -3668,8 +3572,10 @@ doContent(XML_Parser parser, int startTa
return XML_ERROR_BAD_CHAR_REF;
if (parser->m_characterDataHandler) {
XML_Char buf[XML_ENCODE_MAX];
+ beforeHandler(parser);
parser->m_characterDataHandler(parser->m_handlerArg, buf,
XmlEncode(n, (ICHAR *)buf));
+ afterHandler(parser);
} else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
} break;
@@ -3678,32 +3584,38 @@ doContent(XML_Parser parser, int startTa
case XML_TOK_DATA_NEWLINE:
if (parser->m_characterDataHandler) {
XML_Char c = 0xA;
+ beforeHandler(parser);
parser->m_characterDataHandler(parser->m_handlerArg, &c, 1);
+ afterHandler(parser);
} else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
break;
case XML_TOK_CDATA_SECT_OPEN: {
enum XML_Error result;
- if (parser->m_startCdataSectionHandler)
+ if (parser->m_startCdataSectionHandler) {
+ beforeHandler(parser);
parser->m_startCdataSectionHandler(parser->m_handlerArg);
- /* BEGIN disabled code */
- /* Suppose you doing a transformation on a document that involves
- changing only the character data. You set up a defaultHandler
- and a characterDataHandler. The defaultHandler simply copies
- characters through. The characterDataHandler does the
- transformation and writes the characters out escaping them as
- necessary. This case will fail to work if we leave out the
- following two lines (because & and < inside CDATA sections will
- be incorrectly escaped).
+ afterHandler(parser);
+ /* BEGIN disabled code */
+ /* Suppose you doing a transformation on a document that involves
+ changing only the character data. You set up a defaultHandler
+ and a characterDataHandler. The defaultHandler simply copies
+ characters through. The characterDataHandler does the
+ transformation and writes the characters out escaping them as
+ necessary. This case will fail to work if we leave out the
+ following two lines (because & and < inside CDATA sections will
+ be incorrectly escaped).
- However, now we have a start/endCdataSectionHandler, so it seems
- easier to let the user deal with this.
- */
- else if ((0) && parser->m_characterDataHandler)
+ However, now we have a start/endCdataSectionHandler, so it seems
+ easier to let the user deal with this.
+ */
+ } else if ((0) && parser->m_characterDataHandler) {
+ beforeHandler(parser);
parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf,
0);
- /* END disabled code */
- else if (parser->m_defaultHandler)
+ afterHandler(parser);
+ /* END disabled code */
+ } else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
result
= doCdataSection(parser, enc, &next, end, nextPtr, haveMore, account);
@@ -3723,13 +3635,18 @@ doContent(XML_Parser parser, int startTa
if (MUST_CONVERT(enc, s)) {
ICHAR *dataPtr = (ICHAR *)parser->m_dataBuf;
XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)parser->m_dataBufEnd);
+ beforeHandler(parser);
parser->m_characterDataHandler(
parser->m_handlerArg, parser->m_dataBuf,
(int)(dataPtr - (ICHAR *)parser->m_dataBuf));
- } else
+ afterHandler(parser);
+ } else {
+ beforeHandler(parser);
parser->m_characterDataHandler(
parser->m_handlerArg, (const XML_Char *)s,
(int)((const XML_Char *)end - (const XML_Char *)s));
+ afterHandler(parser);
+ }
} else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, end);
/* We are at the end of the final buffer, should we check for
@@ -3754,16 +3671,21 @@ doContent(XML_Parser parser, int startTa
const enum XML_Convert_Result convert_res = XmlConvert(
enc, &s, next, &dataPtr, (ICHAR *)parser->m_dataBufEnd);
*eventEndPP = s;
+ beforeHandler(parser);
charDataHandler(parser->m_handlerArg, parser->m_dataBuf,
(int)(dataPtr - (ICHAR *)parser->m_dataBuf));
+ afterHandler(parser);
if ((convert_res == XML_CONVERT_COMPLETED)
|| (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
break;
*eventPP = s;
}
- } else
+ } else {
+ beforeHandler(parser);
charDataHandler(parser->m_handlerArg, (const XML_Char *)s,
(int)((const XML_Char *)next - (const XML_Char *)s));
+ afterHandler(parser);
+ }
} else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
} break;
@@ -3801,7 +3723,7 @@ doContent(XML_Parser parser, int startTa
*nextPtr = next;
return XML_ERROR_NONE;
}
- /* Fall through */
+ EXPAT_FALLTHROUGH;
default:;
*eventPP = s = next;
}
@@ -3821,8 +3743,11 @@ freeBindings(XML_Parser parser, BINDING
/* m_startNamespaceDeclHandler will have been called for this
* binding in addBindings(), so call the end handler now.
*/
- if (parser->m_endNamespaceDeclHandler)
+ if (parser->m_endNamespaceDeclHandler) {
+ beforeHandler(parser);
parser->m_endNamespaceDeclHandler(parser->m_handlerArg, b->prefix->name);
+ afterHandler(parser);
+ }
bindings = bindings->nextTagBinding;
b->nextTagBinding = parser->m_freeBindingList;
@@ -3846,20 +3771,14 @@ storeAtts(XML_Parser parser, const ENCOD
TAG_NAME *tagNamePtr, BINDING **bindingsPtr,
enum XML_Account account) {
DTD *const dtd = parser->m_dtd; /* save one level of indirection */
- ELEMENT_TYPE *elementType;
- int nDefaultAtts;
- const XML_Char **appAtts; /* the attribute list for the application */
int attIndex = 0;
- int prefixLen;
- int i;
- int n;
XML_Char *uri;
int nPrefixes = 0;
BINDING *binding;
const XML_Char *localPart;
/* lookup the element type name */
- elementType
+ ELEMENT_TYPE *elementType
= (ELEMENT_TYPE *)lookup(parser, &dtd->elementTypes, tagNamePtr->str, 0);
if (! elementType) {
const XML_Char *name = poolCopyString(&dtd->pool, tagNamePtr->str);
@@ -3869,78 +3788,76 @@ storeAtts(XML_Parser parser, const ENCOD
sizeof(ELEMENT_TYPE));
if (! elementType)
return XML_ERROR_NO_MEMORY;
+ if (! elementType->defaultAttsNames.parser)
+ hashTableInit(&(elementType->defaultAttsNames), parser);
if (parser->m_ns && ! setElementTypePrefix(parser, elementType))
return XML_ERROR_NO_MEMORY;
}
- nDefaultAtts = elementType->nDefaultAtts;
+ const size_t nDefaultAtts = elementType->nDefaultAtts;
+
+ /* Detect and prevent integer overflow. */
+ if (parser->m_attsSize > (size_t)INT_MAX)
+ return XML_ERROR_NO_MEMORY;
/* get the attributes from the tokenizer */
- n = XmlGetAttributes(enc, attStr, parser->m_attsSize, parser->m_atts);
+ size_t n = (size_t)XmlGetAttributes(enc, attStr, (int)parser->m_attsSize,
+ parser->m_atts);
/* Detect and prevent integer overflow */
- if (n > INT_MAX - nDefaultAtts) {
+ if (n > SIZE_MAX - nDefaultAtts) {
return XML_ERROR_NO_MEMORY;
}
if (n + nDefaultAtts > parser->m_attsSize) {
- int oldAttsSize = parser->m_attsSize;
- ATTRIBUTE *temp;
-#ifdef XML_ATTR_INFO
- XML_AttrInfo *temp2;
-#endif
+ size_t oldAttsSize = parser->m_attsSize;
/* Detect and prevent integer overflow */
- if ((nDefaultAtts > INT_MAX - INIT_ATTS_SIZE)
- || (n > INT_MAX - (nDefaultAtts + INIT_ATTS_SIZE))) {
+ if ((nDefaultAtts > SIZE_MAX - INIT_ATTS_SIZE)
+ || (n > SIZE_MAX - (nDefaultAtts + INIT_ATTS_SIZE))) {
return XML_ERROR_NO_MEMORY;
}
parser->m_attsSize = n + nDefaultAtts + INIT_ATTS_SIZE;
- /* Detect and prevent integer overflow.
- * The preprocessor guard addresses the "always false" warning
- * from -Wtype-limits on platforms where
- * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
-#if UINT_MAX >= SIZE_MAX
- if ((unsigned)parser->m_attsSize > SIZE_MAX / sizeof(ATTRIBUTE)) {
+ /* Detect and prevent integer overflow. */
+ if (parser->m_attsSize > SIZE_MAX / sizeof(ATTRIBUTE)) {
parser->m_attsSize = oldAttsSize;
return XML_ERROR_NO_MEMORY;
}
-#endif
- temp = REALLOC(parser, parser->m_atts,
- parser->m_attsSize * sizeof(ATTRIBUTE));
+ ATTRIBUTE *const temp = REALLOC(parser, parser->m_atts,
+ parser->m_attsSize * sizeof(ATTRIBUTE));
if (temp == NULL) {
parser->m_attsSize = oldAttsSize;
return XML_ERROR_NO_MEMORY;
}
parser->m_atts = temp;
#ifdef XML_ATTR_INFO
- /* Detect and prevent integer overflow.
- * The preprocessor guard addresses the "always false" warning
- * from -Wtype-limits on platforms where
- * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
-# if UINT_MAX >= SIZE_MAX
- if ((unsigned)parser->m_attsSize > SIZE_MAX / sizeof(XML_AttrInfo)) {
+ /* Detect and prevent integer overflow. */
+ if (parser->m_attsSize > SIZE_MAX / sizeof(XML_AttrInfo)) {
parser->m_attsSize = oldAttsSize;
return XML_ERROR_NO_MEMORY;
}
-# endif
- temp2 = REALLOC(parser, parser->m_attInfo,
- parser->m_attsSize * sizeof(XML_AttrInfo));
+ XML_AttrInfo *const temp2 = REALLOC(
+ parser, parser->m_attInfo, parser->m_attsSize * sizeof(XML_AttrInfo));
if (temp2 == NULL) {
parser->m_attsSize = oldAttsSize;
return XML_ERROR_NO_MEMORY;
}
parser->m_attInfo = temp2;
#endif
- if (n > oldAttsSize)
- XmlGetAttributes(enc, attStr, n, parser->m_atts);
+ if (n > oldAttsSize) {
+ /* Detect and prevent integer overflow. */
+ if (n > (size_t)INT_MAX)
+ return XML_ERROR_NO_MEMORY;
+ XmlGetAttributes(enc, attStr, (int)n, parser->m_atts);
+ }
}
- appAtts = (const XML_Char **)parser->m_atts;
- for (i = 0; i < n; i++) {
+ /* the attribute list for the application */
+ const XML_Char **const appAtts = (const XML_Char **)parser->m_atts;
+ for (size_t i = 0; i < n; i++) {
ATTRIBUTE *currAtt = &parser->m_atts[i];
#ifdef XML_ATTR_INFO
XML_AttrInfo *currAttInfo = &parser->m_attInfo[i];
@@ -3952,14 +3869,22 @@ storeAtts(XML_Parser parser, const ENCOD
if (! attId)
return XML_ERROR_NO_MEMORY;
#ifdef XML_ATTR_INFO
+ // NOTE: XML_Index is known to wrap around for >2 GiB content
+ // on 32bit machines and 64bit Windows, unless (non-default and
+ // uncommon) XML_LARGE_SIZE is defined.
+ // That's a bug and it only lives on because we cannot break
+ // ABI compatibility of public API.
currAttInfo->nameStart
- = parser->m_parseEndByteIndex - (parser->m_parseEndPtr - currAtt->name);
+ = (XML_Index)(parser->m_parseEndByteIndex
+ - (parser->m_parseEndPtr - currAtt->name));
currAttInfo->nameEnd
= currAttInfo->nameStart + XmlNameLength(enc, currAtt->name);
- currAttInfo->valueStart = parser->m_parseEndByteIndex
- - (parser->m_parseEndPtr - currAtt->valuePtr);
- currAttInfo->valueEnd = parser->m_parseEndByteIndex
- - (parser->m_parseEndPtr - currAtt->valueEnd);
+ currAttInfo->valueStart
+ = (XML_Index)(parser->m_parseEndByteIndex
+ - (parser->m_parseEndPtr - currAtt->valuePtr));
+ currAttInfo->valueEnd
+ = (XML_Index)(parser->m_parseEndByteIndex
+ - (parser->m_parseEndPtr - currAtt->valueEnd));
#endif
/* Detect duplicate attributes by their QNames. This does not work when
namespace processing is turned on and different prefixes for the same
@@ -3973,13 +3898,11 @@ storeAtts(XML_Parser parser, const ENCOD
(attId->name)[-1] = 1;
appAtts[attIndex++] = attId->name;
if (! parser->m_atts[i].normalized) {
- enum XML_Error result;
XML_Bool isCdata = XML_TRUE;
/* figure out whether declared as other than CDATA */
if (attId->maybeTokenized) {
- int j;
- for (j = 0; j < nDefaultAtts; j++) {
+ for (size_t j = 0; j < nDefaultAtts; j++) {
if (attId == elementType->defaultAtts[j].id) {
isCdata = elementType->defaultAtts[j].isCdata;
break;
@@ -3988,7 +3911,7 @@ storeAtts(XML_Parser parser, const ENCOD
}
/* normalize the attribute value */
- result = storeAttributeValue(
+ const enum XML_Error result = storeAttributeValue(
parser, enc, isCdata, parser->m_atts[i].valuePtr,
parser->m_atts[i].valueEnd, &parser->m_tempPool, account);
if (result)
@@ -4026,7 +3949,7 @@ storeAtts(XML_Parser parser, const ENCOD
/* set-up for XML_GetSpecifiedAttributeCount and XML_GetIdAttributeIndex */
parser->m_nSpecifiedAtts = attIndex;
if (elementType->idAtt && (elementType->idAtt->name)[-1]) {
- for (i = 0; i < attIndex; i += 2)
+ for (int i = 0; i < attIndex; i += 2)
if (appAtts[i] == elementType->idAtt->name) {
parser->m_idAttIndex = i;
break;
@@ -4035,7 +3958,7 @@ storeAtts(XML_Parser parser, const ENCOD
parser->m_idAttIndex = -1;
/* do attribute defaulting */
- for (i = 0; i < nDefaultAtts; i++) {
+ for (size_t i = 0; i < nDefaultAtts; i++) {
const DEFAULT_ATTRIBUTE *da = elementType->defaultAtts + i;
if (! (da->id->name)[-1] && da->value) {
if (da->id->prefix) {
@@ -4061,7 +3984,7 @@ storeAtts(XML_Parser parser, const ENCOD
/* expand prefixed attribute names, check for duplicates,
and clear flags that say whether attributes were specified */
- i = 0;
+ int i = 0;
if (nPrefixes) {
unsigned int j; /* hash table index */
unsigned long version = parser->m_nsAttsVersion;
@@ -4076,7 +3999,6 @@ storeAtts(XML_Parser parser, const ENCOD
/* size of hash table must be at least 2 * (# of prefixed attributes) */
if ((nPrefixes << 1)
>> parser->m_nsAttsPower) { /* true for m_nsAttsPower = 0 */
- NS_ATT *temp;
/* hash table size must also be a power of 2 and >= 8 */
while (nPrefixes >> parser->m_nsAttsPower++)
;
@@ -4104,7 +4026,8 @@ storeAtts(XML_Parser parser, const ENCOD
}
#endif
- temp = REALLOC(parser, parser->m_nsAtts, nsAttsSize * sizeof(NS_ATT));
+ NS_ATT *const temp
+ = REALLOC(parser, parser->m_nsAtts, nsAttsSize * sizeof(NS_ATT));
if (! temp) {
/* Restore actual size of memory in m_nsAtts */
parser->m_nsAttsPower = oldNsAttsPower;
@@ -4125,9 +4048,6 @@ storeAtts(XML_Parser parser, const ENCOD
for (; i < attIndex; i += 2) {
const XML_Char *s = appAtts[i];
if (s[-1] == 2) { /* prefixed */
- ATTRIBUTE_ID *id;
- const BINDING *b;
- unsigned long uriHash;
struct siphash sip_state;
struct sipkey sip_key;
@@ -4135,7 +4055,8 @@ storeAtts(XML_Parser parser, const ENCOD
sip24_init(&sip_state, &sip_key);
((XML_Char *)s)[-1] = 0; /* clear flag */
- id = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0);
+ ATTRIBUTE_ID *const id
+ = (ATTRIBUTE_ID *)lookup(parser, &dtd->attributeIds, s, 0);
if (! id || ! id->prefix) {
/* This code is walking through the appAtts array, dealing
* with (in this case) a prefixed attribute name. To be in
@@ -4143,7 +4064,7 @@ storeAtts(XML_Parser parser, const ENCOD
* has to have passed through the hash table lookup once
* already. That implies that an entry for it already
* exists, so the lookup above will return a pointer to
- * already allocated memory. There is no opportunaity for
+ * already allocated memory. There is no opportunity for
* the allocator to fail, so the condition above cannot be
* fulfilled.
*
@@ -4153,15 +4074,12 @@ storeAtts(XML_Parser parser, const ENCOD
*/
return XML_ERROR_NO_MEMORY; /* LCOV_EXCL_LINE */
}
- b = id->prefix->binding;
+ const BINDING *const b = id->prefix->binding;
if (! b)
return XML_ERROR_UNBOUND_PREFIX;
- for (j = 0; j < (unsigned int)b->uriLen; j++) {
- const XML_Char c = b->uri[j];
- if (! poolAppendChar(&parser->m_tempPool, c))
- return XML_ERROR_NO_MEMORY;
- }
+ if (! poolAppendChars(&parser->m_tempPool, b->uri, b->uriLen))
+ return XML_ERROR_NO_MEMORY;
sip24_update(&sip_state, b->uri, b->uriLen * sizeof(XML_Char));
@@ -4170,12 +4088,13 @@ storeAtts(XML_Parser parser, const ENCOD
sip24_update(&sip_state, s, keylen(s) * sizeof(XML_Char));
- do { /* copies null terminator */
- if (! poolAppendChar(&parser->m_tempPool, *s))
+ {
+ const size_t len = xcslen(s) + /*null terminator*/ 1;
+ if (! poolAppendChars(&parser->m_tempPool, s, len))
return XML_ERROR_NO_MEMORY;
- } while (*s++);
+ }
- uriHash = (unsigned long)sip24_final(&sip_state);
+ const unsigned long uriHash = (unsigned long)sip24_final(&sip_state);
{ /* Check hash table for duplicate of expanded name (uriName).
Derived from code in lookup(parser, HASH_TABLE *table, ...).
@@ -4203,10 +4122,9 @@ storeAtts(XML_Parser parser, const ENCOD
if (parser->m_ns_triplets) { /* append namespace separator and prefix */
parser->m_tempPool.ptr[-1] = parser->m_namespaceSeparator;
s = b->prefix->name;
- do {
- if (! poolAppendChar(&parser->m_tempPool, *s))
- return XML_ERROR_NO_MEMORY;
- } while (*s++);
+ const size_t len = xcslen(s) + /*null terminator*/ 1;
+ if (! poolAppendChars(&parser->m_tempPool, s, len))
+ return XML_ERROR_NO_MEMORY;
}
/* store expanded name in attribute list */
@@ -4249,48 +4167,36 @@ storeAtts(XML_Parser parser, const ENCOD
localPart = tagNamePtr->str;
} else
return XML_ERROR_NONE;
- prefixLen = 0;
- if (parser->m_ns_triplets && binding->prefix->name) {
- while (binding->prefix->name[prefixLen++])
- ; /* prefixLen includes null terminator */
- }
+ size_t prefixLen = 0;
+ if (parser->m_ns_triplets && binding->prefix->name)
+ prefixLen = xcslen(binding->prefix->name) + /*null terminator*/ 1;
tagNamePtr->localPart = localPart;
tagNamePtr->uriLen = binding->uriLen;
tagNamePtr->prefix = binding->prefix->name;
tagNamePtr->prefixLen = prefixLen;
- for (i = 0; localPart[i++];)
- ; /* i includes null terminator */
+
+ const size_t localPartLen = xcslen(localPart) + /*null terminator*/ 1;
/* Detect and prevent integer overflow */
- if (binding->uriLen > INT_MAX - prefixLen
- || i > INT_MAX - (binding->uriLen + prefixLen)) {
+ if (binding->uriLen > SIZE_MAX - prefixLen
+ || localPartLen > SIZE_MAX - (binding->uriLen + prefixLen)) {
return XML_ERROR_NO_MEMORY;
}
- n = i + binding->uriLen + prefixLen;
- if (n > binding->uriAlloc) {
- TAG *p;
-
+ const size_t totalLen = localPartLen + binding->uriLen + prefixLen;
+ if (totalLen > binding->uriAlloc) {
/* Detect and prevent integer overflow */
- if (n > INT_MAX - EXPAND_SPARE) {
+ if (totalLen > SIZE_MAX - EXPAND_SPARE
+ || totalLen + EXPAND_SPARE > SIZE_MAX / sizeof(XML_Char)) {
return XML_ERROR_NO_MEMORY;
}
- /* Detect and prevent integer overflow.
- * The preprocessor guard addresses the "always false" warning
- * from -Wtype-limits on platforms where
- * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
-#if UINT_MAX >= SIZE_MAX
- if ((unsigned)(n + EXPAND_SPARE) > SIZE_MAX / sizeof(XML_Char)) {
- return XML_ERROR_NO_MEMORY;
- }
-#endif
- uri = MALLOC(parser, (n + EXPAND_SPARE) * sizeof(XML_Char));
+ uri = MALLOC(parser, (totalLen + EXPAND_SPARE) * sizeof(XML_Char));
if (! uri)
return XML_ERROR_NO_MEMORY;
- binding->uriAlloc = n + EXPAND_SPARE;
+ binding->uriAlloc = totalLen + EXPAND_SPARE;
memcpy(uri, binding->uri, binding->uriLen * sizeof(XML_Char));
- for (p = parser->m_tagStack; p; p = p->parent)
+ for (TAG *p = parser->m_tagStack; p; p = p->parent)
if (p->name.str == binding->uri)
p->name.str = uri;
FREE(parser, binding->uri);
@@ -4298,10 +4204,14 @@ storeAtts(XML_Parser parser, const ENCOD
}
/* if m_namespaceSeparator != '\0' then uri includes it already */
uri = binding->uri + binding->uriLen;
- memcpy(uri, localPart, i * sizeof(XML_Char));
+ /* Detect and prevent integer overflow */
+ if (localPartLen > SIZE_MAX / sizeof(XML_Char)) {
+ return XML_ERROR_NO_MEMORY;
+ }
+ memcpy(uri, localPart, localPartLen * sizeof(XML_Char));
/* we always have a namespace separator between localPart and prefix */
if (prefixLen) {
- uri += i - 1;
+ uri += localPartLen - 1;
*uri = parser->m_namespaceSeparator; /* replace null terminator */
memcpy(uri + 1, binding->prefix->name, prefixLen * sizeof(XML_Char));
}
@@ -4436,7 +4346,7 @@ addBinding(XML_Parser parser, PREFIX *pr
ASCII_8, ASCII_SLASH, ASCII_n, ASCII_a, ASCII_m,
ASCII_e, ASCII_s, ASCII_p, ASCII_a, ASCII_c,
ASCII_e, '\0'};
- static const int xmlLen = (int)sizeof(xmlNamespace) / sizeof(XML_Char) - 1;
+ static const size_t xmlLen = sizeof(xmlNamespace) / sizeof(XML_Char) - 1;
// "http://www.w3.org/2000/xmlns/"
static const XML_Char xmlnsNamespace[]
= {ASCII_h, ASCII_t, ASCII_t, ASCII_p, ASCII_COLON, ASCII_SLASH,
@@ -4444,15 +4354,14 @@ addBinding(XML_Parser parser, PREFIX *pr
ASCII_3, ASCII_PERIOD, ASCII_o, ASCII_r, ASCII_g, ASCII_SLASH,
ASCII_2, ASCII_0, ASCII_0, ASCII_0, ASCII_SLASH, ASCII_x,
ASCII_m, ASCII_l, ASCII_n, ASCII_s, ASCII_SLASH, '\0'};
- static const int xmlnsLen
- = (int)sizeof(xmlnsNamespace) / sizeof(XML_Char) - 1;
+ static const size_t xmlnsLen = sizeof(xmlnsNamespace) / sizeof(XML_Char) - 1;
XML_Bool mustBeXML = XML_FALSE;
XML_Bool isXML = XML_TRUE;
XML_Bool isXMLNS = XML_TRUE;
BINDING *b;
- int len;
+ size_t len;
/* empty URI is only valid for default namespace per XML NS 1.0 (not 1.1) */
if (*uri == XML_T('\0') && prefix->name)
@@ -4471,6 +4380,10 @@ addBinding(XML_Parser parser, PREFIX *pr
}
for (len = 0; uri[len]; len++) {
+ /* Detect and prevent integer overflow */
+ if (len == SIZE_MAX) {
+ return XML_ERROR_NO_MEMORY;
+ }
if (isXML && (len > xmlLen || uri[len] != xmlNamespace[len]))
isXML = XML_FALSE;
@@ -4511,26 +4424,22 @@ addBinding(XML_Parser parser, PREFIX *pr
if (isXMLNS)
return XML_ERROR_RESERVED_NAMESPACE_URI;
- if (parser->m_namespaceSeparator)
+ if (parser->m_namespaceSeparator) {
+ /* Detect and prevent integer overflow */
+ if (len == SIZE_MAX) {
+ return XML_ERROR_NO_MEMORY;
+ }
len++;
+ }
if (parser->m_freeBindingList) {
b = parser->m_freeBindingList;
if (len > b->uriAlloc) {
/* Detect and prevent integer overflow */
- if (len > INT_MAX - EXPAND_SPARE) {
+ if (len > SIZE_MAX - EXPAND_SPARE
+ || len + EXPAND_SPARE > SIZE_MAX / sizeof(XML_Char)) {
return XML_ERROR_NO_MEMORY;
}
- /* Detect and prevent integer overflow.
- * The preprocessor guard addresses the "always false" warning
- * from -Wtype-limits on platforms where
- * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
-#if UINT_MAX >= SIZE_MAX
- if ((unsigned)(len + EXPAND_SPARE) > SIZE_MAX / sizeof(XML_Char)) {
- return XML_ERROR_NO_MEMORY;
- }
-#endif
-
XML_Char *temp
= REALLOC(parser, b->uri, sizeof(XML_Char) * (len + EXPAND_SPARE));
if (temp == NULL)
@@ -4545,18 +4454,10 @@ addBinding(XML_Parser parser, PREFIX *pr
return XML_ERROR_NO_MEMORY;
/* Detect and prevent integer overflow */
- if (len > INT_MAX - EXPAND_SPARE) {
- return XML_ERROR_NO_MEMORY;
- }
- /* Detect and prevent integer overflow.
- * The preprocessor guard addresses the "always false" warning
- * from -Wtype-limits on platforms where
- * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
-#if UINT_MAX >= SIZE_MAX
- if ((unsigned)(len + EXPAND_SPARE) > SIZE_MAX / sizeof(XML_Char)) {
+ if (len > SIZE_MAX - EXPAND_SPARE
+ || len + EXPAND_SPARE > SIZE_MAX / sizeof(XML_Char)) {
return XML_ERROR_NO_MEMORY;
}
-#endif
b->uri = MALLOC(parser, sizeof(XML_Char) * (len + EXPAND_SPARE));
if (! b->uri) {
@@ -4580,9 +4481,12 @@ addBinding(XML_Parser parser, PREFIX *pr
b->nextTagBinding = *bindingsPtr;
*bindingsPtr = b;
/* if attId == NULL then we are not starting a namespace scope */
- if (attId && parser->m_startNamespaceDeclHandler)
+ if (attId && parser->m_startNamespaceDeclHandler) {
+ beforeHandler(parser);
parser->m_startNamespaceDeclHandler(parser->m_handlerArg, prefix->name,
prefix->binding ? uri : 0);
+ afterHandler(parser);
+ }
return XML_ERROR_NONE;
}
@@ -4644,15 +4548,20 @@ doCdataSection(XML_Parser parser, const
*eventEndPP = next;
switch (tok) {
case XML_TOK_CDATA_SECT_CLOSE:
- if (parser->m_endCdataSectionHandler)
+ if (parser->m_endCdataSectionHandler) {
+ beforeHandler(parser);
parser->m_endCdataSectionHandler(parser->m_handlerArg);
+ afterHandler(parser);
+ }
/* BEGIN disabled code */
/* see comment under XML_TOK_CDATA_SECT_OPEN */
- else if ((0) && parser->m_characterDataHandler)
+ else if ((0) && parser->m_characterDataHandler) {
+ beforeHandler(parser);
parser->m_characterDataHandler(parser->m_handlerArg, parser->m_dataBuf,
0);
- /* END disabled code */
- else if (parser->m_defaultHandler)
+ afterHandler(parser);
+ /* END disabled code */
+ } else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
*startPtr = next;
*nextPtr = next;
@@ -4663,7 +4572,9 @@ doCdataSection(XML_Parser parser, const
case XML_TOK_DATA_NEWLINE:
if (parser->m_characterDataHandler) {
XML_Char c = 0xA;
+ beforeHandler(parser);
parser->m_characterDataHandler(parser->m_handlerArg, &c, 1);
+ afterHandler(parser);
} else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
break;
@@ -4676,16 +4587,21 @@ doCdataSection(XML_Parser parser, const
const enum XML_Convert_Result convert_res = XmlConvert(
enc, &s, next, &dataPtr, (ICHAR *)parser->m_dataBufEnd);
*eventEndPP = next;
+ beforeHandler(parser);
charDataHandler(parser->m_handlerArg, parser->m_dataBuf,
(int)(dataPtr - (ICHAR *)parser->m_dataBuf));
+ afterHandler(parser);
if ((convert_res == XML_CONVERT_COMPLETED)
|| (convert_res == XML_CONVERT_INPUT_INCOMPLETE))
break;
*eventPP = s;
}
- } else
+ } else {
+ beforeHandler(parser);
charDataHandler(parser->m_handlerArg, (const XML_Char *)s,
(int)((const XML_Char *)next - (const XML_Char *)s));
+ afterHandler(parser);
+ }
} else if (parser->m_defaultHandler)
reportDefault(parser, enc, s, next);
} break;
@@ -4730,7 +4646,7 @@ doCdataSection(XML_Parser parser, const
if (parser->m_reenter) {
return XML_ERROR_UNEXPECTED_STATE; // LCOV_EXCL_LINE
}
- /* Fall through */
+ EXPAT_FALLTHROUGH;
default:;
*eventPP = s = next;
}
@@ -4924,8 +4840,10 @@ processXmlDecl(XML_Parser parser, int is
if (! storedversion)
return XML_ERROR_NO_MEMORY;
}
+ beforeHandler(parser);
parser->m_xmlDeclHandler(parser->m_handlerArg, storedversion, storedEncName,
standalone);
+ afterHandler(parser);
} else if (parser->m_defaultHandler)
reportDefault(parser, parser->m_encoding, s, next);
if (parser->m_protocolEncodingName == NULL) {
@@ -4975,8 +4893,11 @@ handleUnknownEncoding(XML_Parser parser,
info.convert = NULL;
info.data = NULL;
info.release = NULL;
- if (parser->m_unknownEncodingHandler(parser->m_unknownEncodingHandlerData,
- encodingName, &info)) {
+ beforeHandler(parser);
+ const int status = parser->m_unknownEncodingHandler(
+ parser->m_unknownEncodingHandlerData, encodingName, &info);
+ afterHandler(parser);
+ if (status) {
ENCODING *enc;
parser->m_unknownEncodingMem = MALLOC(parser, XmlSizeOfUnknownEncoding());
if (! parser->m_unknownEncodingMem) {
@@ -5353,9 +5274,11 @@ doProlog(XML_Parser parser, const ENCODI
break;
case XML_ROLE_DOCTYPE_INTERNAL_SUBSET:
if (parser->m_startDoctypeDeclHandler) {
+ beforeHandler(parser);
parser->m_startDoctypeDeclHandler(
parser->m_handlerArg, parser->m_doctypeName, parser->m_doctypeSysid,
parser->m_doctypePubid, 1);
+ afterHandler(parser);
parser->m_doctypeName = NULL;
poolClear(&parser->m_tempPool);
handleDefault = XML_FALSE;
@@ -5394,7 +5317,7 @@ doProlog(XML_Parser parser, const ENCODI
handleDefault = XML_FALSE;
goto alreadyChecked;
}
- /* fall through */
+ EXPAT_FALLTHROUGH;
case XML_ROLE_ENTITY_PUBLIC_ID:
if (! XmlIsPublicId(enc, s, next, eventPP))
return XML_ERROR_PUBLICID;
@@ -5422,9 +5345,11 @@ doProlog(XML_Parser parser, const ENCODI
}
if (parser->m_doctypeName) {
+ beforeHandler(parser);
parser->m_startDoctypeDeclHandler(
parser->m_handlerArg, parser->m_doctypeName, parser->m_doctypeSysid,
parser->m_doctypePubid, 0);
+ afterHandler(parser);
poolClear(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
@@ -5451,14 +5376,22 @@ doProlog(XML_Parser parser, const ENCODI
if (parser->m_useForeignDTD)
entity->base = parser->m_curBase;
dtd->paramEntityRead = XML_FALSE;
- if (! parser->m_externalEntityRefHandler(
- parser->m_externalEntityRefHandlerArg, 0, entity->base,
- entity->systemId, entity->publicId))
+ beforeHandler(parser);
+ const int status = parser->m_externalEntityRefHandler(
+ parser->m_externalEntityRefHandlerArg, 0, entity->base,
+ entity->systemId, entity->publicId);
+ afterHandler(parser);
+ if (! status)
return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
if (dtd->paramEntityRead) {
- if (! dtd->standalone && parser->m_notStandaloneHandler
- && ! parser->m_notStandaloneHandler(parser->m_handlerArg))
- return XML_ERROR_NOT_STANDALONE;
+ if (! dtd->standalone && parser->m_notStandaloneHandler) {
+ beforeHandler(parser);
+ const int handlerStatus
+ = parser->m_notStandaloneHandler(parser->m_handlerArg);
+ afterHandler(parser);
+ if (! handlerStatus)
+ return XML_ERROR_NOT_STANDALONE;
+ }
}
/* if we didn't read the foreign DTD then this means that there
is no external subset and we must reset dtd->hasParamEntityRefs
@@ -5471,7 +5404,9 @@ doProlog(XML_Parser parser, const ENCODI
}
#endif /* XML_DTD */
if (parser->m_endDoctypeDeclHandler) {
+ beforeHandler(parser);
parser->m_endDoctypeDeclHandler(parser->m_handlerArg);
+ afterHandler(parser);
handleDefault = XML_FALSE;
}
break;
@@ -5491,14 +5426,22 @@ doProlog(XML_Parser parser, const ENCODI
return XML_ERROR_NO_MEMORY;
entity->base = parser->m_curBase;
dtd->paramEntityRead = XML_FALSE;
- if (! parser->m_externalEntityRefHandler(
- parser->m_externalEntityRefHandlerArg, 0, entity->base,
- entity->systemId, entity->publicId))
+ beforeHandler(parser);
+ const int status = parser->m_externalEntityRefHandler(
+ parser->m_externalEntityRefHandlerArg, 0, entity->base,
+ entity->systemId, entity->publicId);
+ afterHandler(parser);
+ if (! status)
return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
if (dtd->paramEntityRead) {
- if (! dtd->standalone && parser->m_notStandaloneHandler
- && ! parser->m_notStandaloneHandler(parser->m_handlerArg))
- return XML_ERROR_NOT_STANDALONE;
+ if (! dtd->standalone && parser->m_notStandaloneHandler) {
+ beforeHandler(parser);
+ const int handlerStatus
+ = parser->m_notStandaloneHandler(parser->m_handlerArg);
+ afterHandler(parser);
+ if (! handlerStatus)
+ return XML_ERROR_NOT_STANDALONE;
+ }
}
/* if we didn't read the foreign DTD then this means that there
is no external subset and we must reset dtd->hasParamEntityRefs
@@ -5591,10 +5534,12 @@ doProlog(XML_Parser parser, const ENCODI
poolFinish(&parser->m_tempPool);
}
*eventEndPP = s;
+ beforeHandler(parser);
parser->m_attlistDeclHandler(
parser->m_handlerArg, parser->m_declElementType->name,
parser->m_declAttributeId->name, parser->m_declAttributeType, 0,
role == XML_ROLE_REQUIRED_ATTRIBUTE_VALUE);
+ afterHandler(parser);
handleDefault = XML_FALSE;
}
}
@@ -5629,10 +5574,12 @@ doProlog(XML_Parser parser, const ENCODI
poolFinish(&parser->m_tempPool);
}
*eventEndPP = s;
+ beforeHandler(parser);
parser->m_attlistDeclHandler(
parser->m_handlerArg, parser->m_declElementType->name,
parser->m_declAttributeId->name, parser->m_declAttributeType,
attVal, role == XML_ROLE_FIXED_ATTRIBUTE_VALUE);
+ afterHandler(parser);
poolClear(&parser->m_tempPool);
handleDefault = XML_FALSE;
}
@@ -5647,16 +5594,22 @@ doProlog(XML_Parser parser, const ENCODI
parser, enc, s + enc->minBytesPerChar, next - enc->minBytesPerChar,
XML_ACCOUNT_NONE);
if (parser->m_declEntity) {
+ /* Detect and prevent signed integer overflow */
+ if ((size_t)poolLength(&dtd->entityValuePool) > (size_t)INT_MAX) {
+ return XML_ERROR_NO_MEMORY;
+ }
parser->m_declEntity->textPtr = poolStart(&dtd->entityValuePool);
parser->m_declEntity->textLen
= (int)(poolLength(&dtd->entityValuePool));
poolFinish(&dtd->entityValuePool);
if (parser->m_entityDeclHandler) {
*eventEndPP = s;
+ beforeHandler(parser);
parser->m_entityDeclHandler(
parser->m_handlerArg, parser->m_declEntity->name,
parser->m_declEntity->is_param, parser->m_declEntity->textPtr,
parser->m_declEntity->textLen, parser->m_curBase, 0, 0, 0);
+ afterHandler(parser);
handleDefault = XML_FALSE;
}
} else
@@ -5674,10 +5627,12 @@ doProlog(XML_Parser parser, const ENCODI
if (parser->m_entityDeclHandler) {
*eventEndPP = s;
+ beforeHandler(parser);
parser->m_entityDeclHandler(
parser->m_handlerArg, parser->m_declEntity->name,
parser->m_declEntity->is_param, parser->m_declEntity->textPtr,
parser->m_declEntity->textLen, parser->m_curBase, 0, 0, 0);
+ afterHandler(parser);
handleDefault = XML_FALSE;
}
}
@@ -5708,9 +5663,13 @@ doProlog(XML_Parser parser, const ENCODI
#ifdef XML_DTD
&& ! parser->m_paramEntityParsing
#endif /* XML_DTD */
- && parser->m_notStandaloneHandler
- && ! parser->m_notStandaloneHandler(parser->m_handlerArg))
- return XML_ERROR_NOT_STANDALONE;
+ && parser->m_notStandaloneHandler) {
+ beforeHandler(parser);
+ const int status = parser->m_notStandaloneHandler(parser->m_handlerArg);
+ afterHandler(parser);
+ if (! status)
+ return XML_ERROR_NOT_STANDALONE;
+ }
#ifndef XML_DTD
break;
#else /* XML_DTD */
@@ -5722,7 +5681,7 @@ doProlog(XML_Parser parser, const ENCODI
parser->m_declEntity->publicId = NULL;
}
#endif /* XML_DTD */
- /* fall through */
+ EXPAT_FALLTHROUGH;
case XML_ROLE_ENTITY_SYSTEM_ID:
if (dtd->keepProcessing && parser->m_declEntity) {
parser->m_declEntity->systemId
@@ -5753,10 +5712,12 @@ doProlog(XML_Parser parser, const ENCODI
if (dtd->keepProcessing && parser->m_declEntity
&& parser->m_entityDeclHandler) {
*eventEndPP = s;
+ beforeHandler(parser);
parser->m_entityDeclHandler(
parser->m_handlerArg, parser->m_declEntity->name,
parser->m_declEntity->is_param, 0, 0, parser->m_declEntity->base,
parser->m_declEntity->systemId, parser->m_declEntity->publicId, 0);
+ afterHandler(parser);
handleDefault = XML_FALSE;
}
break;
@@ -5769,17 +5730,21 @@ doProlog(XML_Parser parser, const ENCODI
poolFinish(&dtd->pool);
if (parser->m_unparsedEntityDeclHandler) {
*eventEndPP = s;
+ beforeHandler(parser);
parser->m_unparsedEntityDeclHandler(
parser->m_handlerArg, parser->m_declEntity->name,
parser->m_declEntity->base, parser->m_declEntity->systemId,
parser->m_declEntity->publicId, parser->m_declEntity->notation);
+ afterHandler(parser);
handleDefault = XML_FALSE;
} else if (parser->m_entityDeclHandler) {
*eventEndPP = s;
+ beforeHandler(parser);
parser->m_entityDeclHandler(
parser->m_handlerArg, parser->m_declEntity->name, 0, 0, 0,
parser->m_declEntity->base, parser->m_declEntity->systemId,
parser->m_declEntity->publicId, parser->m_declEntity->notation);
+ afterHandler(parser);
handleDefault = XML_FALSE;
}
}
@@ -5886,9 +5851,11 @@ doProlog(XML_Parser parser, const ENCODI
if (! systemId)
return XML_ERROR_NO_MEMORY;
*eventEndPP = s;
+ beforeHandler(parser);
parser->m_notationDeclHandler(
parser->m_handlerArg, parser->m_declNotationName, parser->m_curBase,
systemId, parser->m_declNotationPublicId);
+ afterHandler(parser);
handleDefault = XML_FALSE;
}
poolClear(&parser->m_tempPool);
@@ -5896,9 +5863,11 @@ doProlog(XML_Parser parser, const ENCODI
case XML_ROLE_NOTATION_NO_SYSTEM_ID:
if (parser->m_declNotationPublicId && parser->m_notationDeclHandler) {
*eventEndPP = s;
+ beforeHandler(parser);
parser->m_notationDeclHandler(
parser->m_handlerArg, parser->m_declNotationName, parser->m_curBase,
0, parser->m_declNotationPublicId);
+ afterHandler(parser);
handleDefault = XML_FALSE;
}
poolClear(&parser->m_tempPool);
@@ -5932,41 +5901,18 @@ doProlog(XML_Parser parser, const ENCODI
case XML_ROLE_GROUP_OPEN:
if (parser->m_prologState.level >= parser->m_groupSize) {
if (parser->m_groupSize) {
- {
- /* Detect and prevent integer overflow */
- if (parser->m_groupSize > (unsigned int)(-1) / 2u) {
- return XML_ERROR_NO_MEMORY;
- }
-
- char *const new_connector = REALLOC(
- parser, parser->m_groupConnector, parser->m_groupSize *= 2);
- if (new_connector == NULL) {
- parser->m_groupSize /= 2;
- return XML_ERROR_NO_MEMORY;
- }
- parser->m_groupConnector = new_connector;
+ /* Detect and prevent integer overflow */
+ if (parser->m_groupSize > SIZE_MAX / 2) {
+ return XML_ERROR_NO_MEMORY;
}
- if (dtd->scaffIndex) {
- /* Detect and prevent integer overflow.
- * The preprocessor guard addresses the "always false" warning
- * from -Wtype-limits on platforms where
- * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
-#if UINT_MAX >= SIZE_MAX
- if (parser->m_groupSize > SIZE_MAX / sizeof(int)) {
- parser->m_groupSize /= 2;
- return XML_ERROR_NO_MEMORY;
- }
-#endif
-
- int *const new_scaff_index = REALLOC(
- parser, dtd->scaffIndex, parser->m_groupSize * sizeof(int));
- if (new_scaff_index == NULL) {
- parser->m_groupSize /= 2;
- return XML_ERROR_NO_MEMORY;
- }
- dtd->scaffIndex = new_scaff_index;
+ char *const new_connector = REALLOC(parser, parser->m_groupConnector,
+ parser->m_groupSize *= 2);
+ if (new_connector == NULL) {
+ parser->m_groupSize /= 2;
+ return XML_ERROR_NO_MEMORY;
}
+ parser->m_groupConnector = new_connector;
} else {
parser->m_groupConnector = MALLOC(parser, parser->m_groupSize = 32);
if (! parser->m_groupConnector) {
@@ -5981,6 +5927,21 @@ doProlog(XML_Parser parser, const ENCODI
if (myindex < 0)
return XML_ERROR_NO_MEMORY;
assert(dtd->scaffIndex != NULL);
+ if ((size_t)dtd->scaffLevel >= dtd->scaffIndexSize) {
+ /* Detect and prevent integer overflow */
+ if (dtd->scaffIndexSize > SIZE_MAX / 2 / sizeof(int)) {
+ return XML_ERROR_NO_MEMORY;
+ }
+ assert(dtd->scaffIndexSize > 0);
+ const size_t new_size = dtd->scaffIndexSize * 2;
+ int *const new_scaff_index
+ = REALLOC(parser, dtd->scaffIndex, new_size * sizeof(int));
+ if (new_scaff_index == NULL) {
+ return XML_ERROR_NO_MEMORY;
+ }
+ dtd->scaffIndex = new_scaff_index;
+ dtd->scaffIndexSize = new_size;
+ }
dtd->scaffIndex[dtd->scaffLevel] = myindex;
dtd->scaffLevel++;
dtd->scaffold[myindex].type = XML_CTYPE_SEQ;
@@ -6061,7 +6022,9 @@ doProlog(XML_Parser parser, const ENCODI
/* cannot report skipped entities in declarations */
if ((role == XML_ROLE_PARAM_ENTITY_REF)
&& parser->m_skippedEntityHandler) {
+ beforeHandler(parser);
parser->m_skippedEntityHandler(parser->m_handlerArg, name, 1);
+ afterHandler(parser);
handleDefault = XML_FALSE;
}
break;
@@ -6082,9 +6045,12 @@ doProlog(XML_Parser parser, const ENCODI
dtd->paramEntityRead = XML_FALSE;
entity->open = XML_TRUE;
entityTrackingOnOpen(parser, entity, __LINE__);
- if (! parser->m_externalEntityRefHandler(
- parser->m_externalEntityRefHandlerArg, 0, entity->base,
- entity->systemId, entity->publicId)) {
+ beforeHandler(parser);
+ const int status = parser->m_externalEntityRefHandler(
+ parser->m_externalEntityRefHandlerArg, 0, entity->base,
+ entity->systemId, entity->publicId);
+ afterHandler(parser);
+ if (! status) {
entityTrackingOnClose(parser, entity, __LINE__);
entity->open = XML_FALSE;
return XML_ERROR_EXTERNAL_ENTITY_HANDLING;
@@ -6102,9 +6068,13 @@ doProlog(XML_Parser parser, const ENCODI
}
}
#endif /* XML_DTD */
- if (! dtd->standalone && parser->m_notStandaloneHandler
- && ! parser->m_notStandaloneHandler(parser->m_handlerArg))
- return XML_ERROR_NOT_STANDALONE;
+ if (! dtd->standalone && parser->m_notStandaloneHandler) {
+ beforeHandler(parser);
+ const int status = parser->m_notStandaloneHandler(parser->m_handlerArg);
+ afterHandler(parser);
+ if (! status)
+ return XML_ERROR_NOT_STANDALONE;
+ }
break;
/* Element declaration stuff */
@@ -6139,8 +6109,10 @@ doProlog(XML_Parser parser, const ENCODI
content->type = ((role == XML_ROLE_CONTENT_ANY) ? XML_CTYPE_ANY
: XML_CTYPE_EMPTY);
*eventEndPP = s;
+ beforeHandler(parser);
parser->m_elementDeclHandler(
parser->m_handlerArg, parser->m_declElementType->name, content);
+ afterHandler(parser);
handleDefault = XML_FALSE;
}
dtd->in_eldecl = XML_FALSE;
@@ -6184,9 +6156,7 @@ doProlog(XML_Parser parser, const ENCODI
return XML_ERROR_NO_MEMORY;
name = el->name;
dtd->scaffold[myindex].name = name;
- nameLen = 0;
- while (name[nameLen++])
- ;
+ nameLen = xcslen(name) + /*null terminator*/ 1;
/* Detect and prevent integer overflow */
if (nameLen > UINT_MAX - dtd->contentStringLen) {
@@ -6222,8 +6192,10 @@ doProlog(XML_Parser parser, const ENCODI
if (! model)
return XML_ERROR_NO_MEMORY;
*eventEndPP = s;
+ beforeHandler(parser);
parser->m_elementDeclHandler(
parser->m_handlerArg, parser->m_declElementType->name, model);
+ afterHandler(parser);
}
dtd->in_eldecl = XML_FALSE;
dtd->contentStringLen = 0;
@@ -6285,7 +6257,7 @@ doProlog(XML_Parser parser, const ENCODI
*nextPtr = next;
return XML_ERROR_NONE;
}
- /* Fall through */
+ EXPAT_FALLTHROUGH;
default:
s = next;
tok = XmlPrologTok(enc, s, end, &next);
@@ -6365,7 +6337,7 @@ epilogProcessor(XML_Parser parser, const
if (parser->m_reenter) {
return XML_ERROR_UNEXPECTED_STATE; // LCOV_EXCL_LINE
}
- /* Fall through */
+ EXPAT_FALLTHROUGH;
default:;
parser->m_eventPtr = s = next;
}
@@ -6375,20 +6347,18 @@ epilogProcessor(XML_Parser parser, const
static enum XML_Error
processEntity(XML_Parser parser, ENTITY *entity, XML_Bool betweenDecl,
enum EntityType type) {
- OPEN_INTERNAL_ENTITY *openEntity, **openEntityList, **freeEntityList;
+ OPEN_INTERNAL_ENTITY *openEntity, **openEntityList;
+ OPEN_INTERNAL_ENTITY **const freeEntityList = &parser->m_freeEntities;
switch (type) {
case ENTITY_INTERNAL:
parser->m_processor = internalEntityProcessor;
openEntityList = &parser->m_openInternalEntities;
- freeEntityList = &parser->m_freeInternalEntities;
break;
case ENTITY_ATTRIBUTE:
openEntityList = &parser->m_openAttributeEntities;
- freeEntityList = &parser->m_freeAttributeEntities;
break;
case ENTITY_VALUE:
openEntityList = &parser->m_openValueEntities;
- freeEntityList = &parser->m_freeValueEntities;
break;
/* default case serves merely as a safety net in case of a
* wrong entityType. Therefore we exclude the following lines
@@ -6505,8 +6475,8 @@ internalEntityProcessor(XML_Parser parse
parser->m_openInternalEntities = parser->m_openInternalEntities->next;
/* put openEntity back in list of free instances */
- openEntity->next = parser->m_freeInternalEntities;
- parser->m_freeInternalEntities = openEntity;
+ openEntity->next = parser->m_freeEntities;
+ parser->m_freeEntities = openEntity;
if (parser->m_openInternalEntities == NULL) {
parser->m_processor = entity->is_param ? prologProcessor : contentProcessor;
@@ -6556,11 +6526,12 @@ storeAttributeValue(XML_Parser parser, c
// Check if entity is complete, if not, mark down how much of it is
// processed. A XML_SUSPENDED check here is not required as
// appendAttributeValue will never suspend the parser.
- if (textEnd != nextInEntity) {
+ if (nextInEntity < textEnd) {
entity->processed
= (int)(nextInEntity - (const char *)entity->textPtr);
continue;
}
+ assert(nextInEntity == textEnd);
// Entity is complete. We cannot close it here since we need to first
// process its possible inner entities (which are added to the
@@ -6582,8 +6553,8 @@ storeAttributeValue(XML_Parser parser, c
parser->m_openAttributeEntities = parser->m_openAttributeEntities->next;
/* put openEntity back in list of free instances */
- openEntity->next = parser->m_freeAttributeEntities;
- parser->m_freeAttributeEntities = openEntity;
+ openEntity->next = parser->m_freeEntities;
+ parser->m_freeEntities = openEntity;
}
// Break if an error occurred or there is nothing left to process
@@ -6636,7 +6607,6 @@ appendAttributeValue(XML_Parser parser,
return XML_ERROR_INVALID_TOKEN;
case XML_TOK_CHAR_REF: {
XML_Char buf[XML_ENCODE_MAX];
- int i;
int n = XmlCharRefNumber(enc, ptr);
if (n < 0) {
if (enc == parser->m_encoding)
@@ -6656,10 +6626,9 @@ appendAttributeValue(XML_Parser parser,
* XmlEncode() is never passed a value it might return an
* error for.
*/
- for (i = 0; i < n; i++) {
- if (! poolAppendChar(pool, buf[i]))
- return XML_ERROR_NO_MEMORY;
- }
+
+ if (! poolAppendChars(pool, buf, n))
+ return XML_ERROR_NO_MEMORY;
} break;
case XML_TOK_DATA_CHARS:
if (! poolAppend(pool, enc, ptr, next))
@@ -6667,7 +6636,7 @@ appendAttributeValue(XML_Parser parser,
break;
case XML_TOK_TRAILING_CR:
next = ptr + enc->minBytesPerChar;
- /* fall through */
+ EXPAT_FALLTHROUGH;
case XML_TOK_ATTRIBUTE_VALUE_S:
case XML_TOK_DATA_NEWLINE:
if (! isCdata && (poolLength(pool) == 0 || poolLastChar(pool) == 0x20))
@@ -6721,8 +6690,11 @@ appendAttributeValue(XML_Parser parser,
} else if (! entity) {
/* Cannot report skipped entity here - see comments on
parser->m_skippedEntityHandler.
- if (parser->m_skippedEntityHandler)
+ if (parser->m_skippedEntityHandler) {
+ beforeHandler(parser);
parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0);
+ afterHandler(parser);
+ }
*/
/* Cannot call the default handler because this would be
out of sync with the call to the startElementHandler.
@@ -6855,8 +6827,11 @@ storeEntityValue(XML_Parser parser, cons
/* not a well-formedness error - see XML 1.0: WFC Entity Declared */
/* cannot report skipped entity here - see comments on
parser->m_skippedEntityHandler
- if (parser->m_skippedEntityHandler)
+ if (parser->m_skippedEntityHandler) {
+ beforeHandler(parser);
parser->m_skippedEntityHandler(parser->m_handlerArg, name, 0);
+ afterHandler(parser);
+ }
*/
dtd->keepProcessing = dtd->standalone;
goto endEntityValue;
@@ -6872,9 +6847,12 @@ storeEntityValue(XML_Parser parser, cons
dtd->paramEntityRead = XML_FALSE;
entity->open = XML_TRUE;
entityTrackingOnOpen(parser, entity, __LINE__);
- if (! parser->m_externalEntityRefHandler(
- parser->m_externalEntityRefHandlerArg, 0, entity->base,
- entity->systemId, entity->publicId)) {
+ beforeHandler(parser);
+ const int status = parser->m_externalEntityRefHandler(
+ parser->m_externalEntityRefHandlerArg, 0, entity->base,
+ entity->systemId, entity->publicId);
+ afterHandler(parser);
+ if (! status) {
entityTrackingOnClose(parser, entity, __LINE__);
entity->open = XML_FALSE;
result = XML_ERROR_EXTERNAL_ENTITY_HANDLING;
@@ -6910,17 +6888,15 @@ storeEntityValue(XML_Parser parser, cons
break;
case XML_TOK_TRAILING_CR:
next = entityTextPtr + enc->minBytesPerChar;
- /* fall through */
+ EXPAT_FALLTHROUGH;
case XML_TOK_DATA_NEWLINE:
- if (pool->end == pool->ptr && ! poolGrow(pool)) {
+ if (! poolAppendChar(pool, 0xA)) {
result = XML_ERROR_NO_MEMORY;
goto endEntityValue;
}
- *(pool->ptr)++ = 0xA;
break;
case XML_TOK_CHAR_REF: {
XML_Char buf[XML_ENCODE_MAX];
- int i;
int n = XmlCharRefNumber(enc, entityTextPtr);
if (n < 0) {
if (enc == parser->m_encoding)
@@ -6938,12 +6914,9 @@ storeEntityValue(XML_Parser parser, cons
* XmlEncode() is never passed a value it might return an
* error for.
*/
- for (i = 0; i < n; i++) {
- if (pool->end == pool->ptr && ! poolGrow(pool)) {
- result = XML_ERROR_NO_MEMORY;
- goto endEntityValue;
- }
- *(pool->ptr)++ = buf[i];
+ if (! poolAppendChars(pool, buf, n)) {
+ result = XML_ERROR_NO_MEMORY;
+ goto endEntityValue;
}
} break;
case XML_TOK_PARTIAL:
@@ -7040,8 +7013,8 @@ callStoreEntityValue(XML_Parser parser,
parser->m_openValueEntities = parser->m_openValueEntities->next;
/* put openEntity back in list of free instances */
- openEntity->next = parser->m_freeValueEntities;
- parser->m_freeValueEntities = openEntity;
+ openEntity->next = parser->m_freeEntities;
+ parser->m_freeEntities = openEntity;
}
// Break if an error occurred or there is nothing left to process
@@ -7071,6 +7044,11 @@ storeSelfEntityValue(XML_Parser parser,
return XML_ERROR_NO_MEMORY;
}
+ /* Detect and prevent signed integer overflow */
+ if ((size_t)poolLength(pool) > (size_t)INT_MAX) {
+ poolDiscard(pool);
+ return XML_ERROR_NO_MEMORY;
+ }
entity->textPtr = poolStart(pool);
entity->textLen = (int)(poolLength(pool));
poolFinish(pool);
@@ -7123,7 +7101,9 @@ reportProcessingInstruction(XML_Parser p
if (! data)
return 0;
normalizeLines(data);
+ beforeHandler(parser);
parser->m_processingInstructionHandler(parser->m_handlerArg, target, data);
+ afterHandler(parser);
poolClear(&parser->m_tempPool);
return 1;
}
@@ -7143,7 +7123,9 @@ reportComment(XML_Parser parser, const E
if (! data)
return 0;
normalizeLines(data);
+ beforeHandler(parser);
parser->m_commentHandler(parser->m_handlerArg, data);
+ afterHandler(parser);
poolClear(&parser->m_tempPool);
return 1;
}
@@ -7184,15 +7166,20 @@ reportDefault(XML_Parser parser, const E
convert_res
= XmlConvert(enc, &s, end, &dataPtr, (ICHAR *)parser->m_dataBufEnd);
*eventEndPP = s;
+ beforeHandler(parser);
parser->m_defaultHandler(parser->m_handlerArg, parser->m_dataBuf,
(int)(dataPtr - (ICHAR *)parser->m_dataBuf));
+ afterHandler(parser);
*eventPP = s;
} while ((convert_res != XML_CONVERT_COMPLETED)
&& (convert_res != XML_CONVERT_INPUT_INCOMPLETE));
- } else
+ } else {
+ beforeHandler(parser);
parser->m_defaultHandler(
parser->m_handlerArg, (const XML_Char *)s,
(int)((const XML_Char *)end - (const XML_Char *)s));
+ afterHandler(parser);
+ }
}
static int
@@ -7202,49 +7189,35 @@ defineAttribute(ELEMENT_TYPE *type, ATTR
if (value || isId) {
/* The handling of default attributes gets messed up if we have
a default which duplicates a non-default. */
- int i;
- for (i = 0; i < type->nDefaultAtts; i++)
- if (attId == type->defaultAtts[i].id)
- return 1;
+ NAMED *const nameFound
+ = lookup(parser, &(type->defaultAttsNames), attId->name, 0);
+ if (nameFound)
+ return 1;
if (isId && ! type->idAtt && ! attId->xmlns)
type->idAtt = attId;
}
if (type->nDefaultAtts == type->allocDefaultAtts) {
- if (type->allocDefaultAtts == 0) {
- type->allocDefaultAtts = 8;
- type->defaultAtts
- = MALLOC(parser, type->allocDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
- if (! type->defaultAtts) {
- type->allocDefaultAtts = 0;
- return 0;
- }
- } else {
- DEFAULT_ATTRIBUTE *temp;
-
- /* Detect and prevent integer overflow */
- if (type->allocDefaultAtts > INT_MAX / 2) {
- return 0;
- }
-
- int count = type->allocDefaultAtts * 2;
+ /* Detect and prevent integer overflow */
+ if (type->allocDefaultAtts > SIZE_MAX / 2) {
+ return 0;
+ }
- /* Detect and prevent integer overflow.
- * The preprocessor guard addresses the "always false" warning
- * from -Wtype-limits on platforms where
- * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
-#if UINT_MAX >= SIZE_MAX
- if ((unsigned)count > SIZE_MAX / sizeof(DEFAULT_ATTRIBUTE)) {
- return 0;
- }
-#endif
+ size_t count = type->allocDefaultAtts * 2;
+ if (count == 0) {
+ count = 8;
+ }
- temp = REALLOC(parser, type->defaultAtts,
- (count * sizeof(DEFAULT_ATTRIBUTE)));
- if (temp == NULL)
- return 0;
- type->allocDefaultAtts = count;
- type->defaultAtts = temp;
+ /* Detect and prevent integer overflow. */
+ if (count > SIZE_MAX / sizeof(DEFAULT_ATTRIBUTE)) {
+ return 0;
}
+
+ DEFAULT_ATTRIBUTE *const temp = REALLOC(
+ parser, type->defaultAtts, (count * sizeof(DEFAULT_ATTRIBUTE)));
+ if (temp == NULL)
+ return 0;
+ type->allocDefaultAtts = count;
+ type->defaultAtts = temp;
}
att = type->defaultAtts + type->nDefaultAtts;
att->id = attId;
@@ -7252,6 +7225,12 @@ defineAttribute(ELEMENT_TYPE *type, ATTR
att->isCdata = isCdata;
if (! isCdata)
attId->maybeTokenized = XML_TRUE;
+
+ NAMED *const nameAddedOrFound
+ = lookup(parser, &(type->defaultAttsNames), attId->name, sizeof(NAMED));
+ if (! nameAddedOrFound)
+ return 0;
+
type->nDefaultAtts += 1;
return 1;
}
@@ -7321,13 +7300,14 @@ getAttributeId(XML_Parser parser, const
} else {
int i;
for (i = 0; name[i]; i++) {
+ /* Detect and prevent signed integer overflow */
+ if (i == INT_MAX) {
+ return NULL;
+ }
/* attributes without prefix are *not* in the default namespace */
if (name[i] == XML_T(ASCII_COLON)) {
- int j;
- for (j = 0; j < i; j++) {
- if (! poolAppendChar(&dtd->pool, name[j]))
- return NULL;
- }
+ if (! poolAppendChars(&dtd->pool, name, i))
+ return NULL;
if (! poolAppendChar(&dtd->pool, XML_T('\0')))
return NULL;
id->prefix = (PREFIX *)lookup(parser, &dtd->prefixes,
@@ -7355,46 +7335,39 @@ getContext(XML_Parser parser) {
XML_Bool needSep = XML_FALSE;
if (dtd->defaultPrefix.binding) {
- int i;
- int len;
if (! poolAppendChar(&parser->m_tempPool, XML_T(ASCII_EQUALS)))
return NULL;
- len = dtd->defaultPrefix.binding->uriLen;
+ size_t len = dtd->defaultPrefix.binding->uriLen;
if (parser->m_namespaceSeparator)
len--;
- for (i = 0; i < len; i++) {
- if (! poolAppendChar(&parser->m_tempPool,
- dtd->defaultPrefix.binding->uri[i])) {
- /* Because of memory caching, I don't believe this line can be
- * executed.
- *
- * This is part of a loop copying the default prefix binding
- * URI into the parser's temporary string pool. Previously,
- * that URI was copied into the same string pool, with a
- * terminating NUL character, as part of setContext(). When
- * the pool was cleared, that leaves a block definitely big
- * enough to hold the URI on the free block list of the pool.
- * The URI copy in getContext() therefore cannot run out of
- * memory.
- *
- * If the pool is used between the setContext() and
- * getContext() calls, the worst it can do is leave a bigger
- * block on the front of the free list. Given that this is
- * all somewhat inobvious and program logic can be changed, we
- * don't delete the line but we do exclude it from the test
- * coverage statistics.
- */
- return NULL; /* LCOV_EXCL_LINE */
- }
+ if (! poolAppendChars(&parser->m_tempPool, dtd->defaultPrefix.binding->uri,
+ len)) {
+ /* Because of memory caching, I don't believe this line can be
+ * executed.
+ *
+ * This is part of a loop copying the default prefix binding
+ * URI into the parser's temporary string pool. Previously,
+ * that URI was copied into the same string pool, with a
+ * terminating NUL character, as part of setContext(). When
+ * the pool was cleared, that leaves a block definitely big
+ * enough to hold the URI on the free block list of the pool.
+ * The URI copy in getContext() therefore cannot run out of
+ * memory.
+ *
+ * If the pool is used between the setContext() and
+ * getContext() calls, the worst it can do is leave a bigger
+ * block on the front of the free list. Given that this is
+ * all somewhat inobvious and program logic can be changed, we
+ * don't delete the line but we do exclude it from the test
+ * coverage statistics.
+ */
+ return NULL; /* LCOV_EXCL_LINE */
}
needSep = XML_TRUE;
}
hashTableIterInit(&iter, &(dtd->prefixes));
for (;;) {
- int i;
- int len;
- const XML_Char *s;
PREFIX *prefix = (PREFIX *)hashTableIterNext(&iter);
if (! prefix)
break;
@@ -7409,23 +7382,21 @@ getContext(XML_Parser parser) {
}
if (needSep && ! poolAppendChar(&parser->m_tempPool, CONTEXT_SEP))
return NULL;
- for (s = prefix->name; *s; s++)
- if (! poolAppendChar(&parser->m_tempPool, *s))
- return NULL;
+ if (! poolAppendChars(&parser->m_tempPool, prefix->name,
+ xcslen(prefix->name)))
+ return NULL;
if (! poolAppendChar(&parser->m_tempPool, XML_T(ASCII_EQUALS)))
return NULL;
- len = prefix->binding->uriLen;
+ size_t len = prefix->binding->uriLen;
if (parser->m_namespaceSeparator)
len--;
- for (i = 0; i < len; i++)
- if (! poolAppendChar(&parser->m_tempPool, prefix->binding->uri[i]))
- return NULL;
+ if (! poolAppendChars(&parser->m_tempPool, prefix->binding->uri, len))
+ return NULL;
needSep = XML_TRUE;
}
hashTableIterInit(&iter, &(dtd->generalEntities));
for (;;) {
- const XML_Char *s;
ENTITY *e = (ENTITY *)hashTableIterNext(&iter);
if (! e)
break;
@@ -7433,9 +7404,8 @@ getContext(XML_Parser parser) {
continue;
if (needSep && ! poolAppendChar(&parser->m_tempPool, CONTEXT_SEP))
return NULL;
- for (s = e->name; *s; s++)
- if (! poolAppendChar(&parser->m_tempPool, *s))
- return 0;
+ if (! poolAppendChars(&parser->m_tempPool, e->name, xcslen(e->name)))
+ return NULL;
needSep = XML_TRUE;
}
@@ -7557,6 +7527,7 @@ dtdCreate(XML_Parser parser) {
p->in_eldecl = XML_FALSE;
p->scaffIndex = NULL;
+ p->scaffIndexSize = 0;
p->scaffold = NULL;
p->scaffLevel = 0;
p->scaffSize = 0;
@@ -7577,8 +7548,8 @@ dtdReset(DTD *p, XML_Parser parser) {
ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
if (! e)
break;
- if (e->allocDefaultAtts != 0)
- FREE(parser, e->defaultAtts);
+ hashTableDestroy(&(e->defaultAttsNames));
+ FREE(parser, e->defaultAtts);
}
hashTableClear(&(p->generalEntities));
#ifdef XML_DTD
@@ -7597,6 +7568,7 @@ dtdReset(DTD *p, XML_Parser parser) {
FREE(parser, p->scaffIndex);
p->scaffIndex = NULL;
+ p->scaffIndexSize = 0;
FREE(parser, p->scaffold);
p->scaffold = NULL;
@@ -7618,8 +7590,8 @@ dtdDestroy(DTD *p, XML_Bool isDocEntity,
ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter);
if (! e)
break;
- if (e->allocDefaultAtts != 0)
- FREE(parser, e->defaultAtts);
+ hashTableDestroy(&(e->defaultAttsNames));
+ FREE(parser, e->defaultAtts);
}
hashTableDestroy(&(p->generalEntities));
#ifdef XML_DTD
@@ -7698,7 +7670,6 @@ dtdCopy(XML_Parser oldParser, DTD *newDt
hashTableIterInit(&iter, &(oldDtd->elementTypes));
for (;;) {
- int i;
ELEMENT_TYPE *newE;
const XML_Char *name;
const ELEMENT_TYPE *oldE = (ELEMENT_TYPE *)hashTableIterNext(&iter);
@@ -7711,16 +7682,15 @@ dtdCopy(XML_Parser oldParser, DTD *newDt
sizeof(ELEMENT_TYPE));
if (! newE)
return 0;
+
+ if (! newE->defaultAttsNames.parser)
+ hashTableInit(&(newE->defaultAttsNames), parser);
+
if (oldE->nDefaultAtts) {
- /* Detect and prevent integer overflow.
- * The preprocessor guard addresses the "always false" warning
- * from -Wtype-limits on platforms where
- * sizeof(int) < sizeof(size_t), e.g. on x86_64. */
-#if UINT_MAX >= SIZE_MAX
- if ((size_t)oldE->nDefaultAtts > SIZE_MAX / sizeof(DEFAULT_ATTRIBUTE)) {
+ /* Detect and prevent integer overflow. */
+ if (oldE->nDefaultAtts > SIZE_MAX / sizeof(DEFAULT_ATTRIBUTE)) {
return 0;
}
-#endif
newE->defaultAtts
= MALLOC(parser, oldE->nDefaultAtts * sizeof(DEFAULT_ATTRIBUTE));
if (! newE->defaultAtts) {
@@ -7734,9 +7704,10 @@ dtdCopy(XML_Parser oldParser, DTD *newDt
if (oldE->prefix)
newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes),
oldE->prefix->name, 0);
- for (i = 0; i < newE->nDefaultAtts; i++) {
+ for (size_t i = 0; i < newE->nDefaultAtts; i++) {
+ const XML_Char *const attributeName = oldE->defaultAtts[i].id->name;
newE->defaultAtts[i].id = (ATTRIBUTE_ID *)lookup(
- oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0);
+ oldParser, &(newDtd->attributeIds), attributeName, 0);
newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata;
if (oldE->defaultAtts[i].value) {
newE->defaultAtts[i].value
@@ -7745,6 +7716,12 @@ dtdCopy(XML_Parser oldParser, DTD *newDt
return 0;
} else
newE->defaultAtts[i].value = NULL;
+
+ NAMED *const nameAddedOrFound = lookup(parser, &(newE->defaultAttsNames),
+ attributeName, sizeof(NAMED));
+ if (! nameAddedOrFound) {
+ return 0;
+ }
}
}
@@ -7771,6 +7748,7 @@ dtdCopy(XML_Parser oldParser, DTD *newDt
newDtd->scaffSize = oldDtd->scaffSize;
newDtd->scaffLevel = oldDtd->scaffLevel;
newDtd->scaffIndex = oldDtd->scaffIndex;
+ newDtd->scaffIndexSize = oldDtd->scaffIndexSize;
return 1;
} /* End dtdCopy */
@@ -7842,18 +7820,23 @@ copyEntityTable(XML_Parser oldParser, HA
static XML_Bool FASTCALL
keyeq(KEY s1, KEY s2) {
+#ifdef XML_UNICODE
+# ifdef XML_UNICODE_WCHAR_T
+ return (wcscmp(s1, s2) == 0) ? XML_TRUE : XML_FALSE;
+# else
for (; *s1 == *s2; s1++, s2++)
if (*s1 == 0)
return XML_TRUE;
return XML_FALSE;
+# endif
+#else
+ return (strcmp(s1, s2) == 0) ? XML_TRUE : XML_FALSE;
+#endif
}
static size_t
keylen(KEY s) {
- size_t len = 0;
- for (; *s; s++, len++)
- ;
- return len;
+ return xcslen(s);
}
static void
@@ -8071,10 +8054,8 @@ poolAppend(STRING_POOL *pool, const ENCO
static const XML_Char *FASTCALL
poolCopyString(STRING_POOL *pool, const XML_Char *s) {
- do {
- if (! poolAppendChar(pool, *s))
- return NULL;
- } while (*s++);
+ if (! poolAppendChars(pool, s, xcslen(s) + /*null terminator*/ 1))
+ return NULL;
s = pool->start;
poolFinish(pool);
return s;
@@ -8113,10 +8094,8 @@ poolCopyStringN(STRING_POOL *pool, const
*/
return NULL; /* LCOV_EXCL_LINE */
}
- for (; n > 0; --n, s++) {
- if (! poolAppendChar(pool, *s))
- return NULL;
- }
+ if (n > 0 && ! poolAppendChars(pool, s, n))
+ return NULL;
s = pool->start;
poolFinish(pool);
return s;
@@ -8124,11 +8103,8 @@ poolCopyStringN(STRING_POOL *pool, const
static const XML_Char *FASTCALL
poolAppendString(STRING_POOL *pool, const XML_Char *s) {
- while (*s) {
- if (! poolAppendChar(pool, *s))
- return NULL;
- s++;
- }
+ if (! poolAppendChars(pool, s, xcslen(s)))
+ return NULL;
return pool->start;
}
@@ -8137,9 +8113,8 @@ poolStoreString(STRING_POOL *pool, const
const char *end) {
if (! poolAppend(pool, enc, ptr, end))
return NULL;
- if (pool->ptr == pool->end && ! poolGrow(pool))
+ if (! poolAppendChar(pool, 0))
return NULL;
- *(pool->ptr)++ = 0;
return pool->start;
}
@@ -8190,7 +8165,7 @@ poolGrow(STRING_POOL *pool) {
pool->freeBlocks = tem;
memcpy(pool->blocks->s, pool->start,
(pool->end - pool->start) * sizeof(XML_Char));
- pool->ptr = pool->blocks->s + (pool->ptr - pool->start);
+ pool->ptr = pool->blocks->s + EXPAT_SAFE_PTR_DIFF(pool->ptr, pool->start);
pool->start = pool->blocks->s;
pool->end = pool->start + pool->blocks->size;
return XML_TRUE;
@@ -8203,7 +8178,8 @@ poolGrow(STRING_POOL *pool) {
/* NOTE: Needs to be calculated prior to calling `realloc`
to avoid dangling pointers: */
- const ptrdiff_t offsetInsideBlock = pool->ptr - pool->start;
+ const ptrdiff_t offsetInsideBlock
+ = EXPAT_SAFE_PTR_DIFF(pool->ptr, pool->start);
if (blockSize < 0) {
/* This condition traps a situation where either more than
@@ -8266,14 +8242,28 @@ poolGrow(STRING_POOL *pool) {
tem->next = pool->blocks;
pool->blocks = tem;
if (pool->ptr != pool->start)
- memcpy(tem->s, pool->start, (pool->ptr - pool->start) * sizeof(XML_Char));
- pool->ptr = tem->s + (pool->ptr - pool->start);
+ memcpy(tem->s, pool->start,
+ EXPAT_SAFE_PTR_DIFF(pool->ptr, pool->start) * sizeof(XML_Char));
+ pool->ptr = tem->s + EXPAT_SAFE_PTR_DIFF(pool->ptr, pool->start);
pool->start = tem->s;
pool->end = tem->s + blockSize;
}
return XML_TRUE;
}
+static bool FASTCALL
+poolGrowUntil(STRING_POOL *pool, size_t needed) {
+ for (;;) {
+ const size_t available = pool->end - pool->ptr;
+ if (available >= needed) {
+ return true;
+ }
+ if (! poolGrow(pool)) {
+ return false;
+ }
+ }
+}
+
static int FASTCALL
nextScaffoldPart(XML_Parser parser) {
DTD *const dtd = parser->m_dtd; /* save one level of indirection */
@@ -8281,18 +8271,14 @@ nextScaffoldPart(XML_Parser parser) {
int next;
if (! dtd->scaffIndex) {
- /* Detect and prevent integer overflow.
- * The preprocessor guard addresses the "always false" warning
- * from -Wtype-limits on platforms where
- * sizeof(unsigned int) < sizeof(size_t), e.g. on x86_64. */
-#if UINT_MAX >= SIZE_MAX
+ /* Detect and prevent integer overflow. */
if (parser->m_groupSize > SIZE_MAX / sizeof(int)) {
return -1;
}
-#endif
dtd->scaffIndex = MALLOC(parser, parser->m_groupSize * sizeof(int));
if (! dtd->scaffIndex)
return -1;
+ dtd->scaffIndexSize = parser->m_groupSize;
dtd->scaffIndex[0] = 0;
}
@@ -8453,12 +8439,21 @@ build_model(XML_Parser parser) {
const XML_Char *src;
dest->name = str;
src = dtd->scaffold[src_node].name;
- for (;;) {
- *str++ = *src;
- if (! *src)
- break;
- src++;
+
+ const size_t nameLen = xcslen(src) + /* null terminator*/ 1;
+
+ // Detect and prevent integer overflow
+ if (nameLen > SIZE_MAX / sizeof(XML_Char)) {
+ // NOTE: We are avoiding FREE(..) here because the model
+ // is not being allocated with MALLOC(..) but with plain
+ // .malloc_fcn(..).
+ parser->m_mem.free_fcn(ret);
+ return NULL;
}
+
+ memcpy(str, src, nameLen * sizeof(XML_Char));
+ str += nameLen;
+
dest->numchildren = 0;
dest->children = NULL;
} else {
@@ -8491,6 +8486,8 @@ getElementType(XML_Parser parser, const
sizeof(ELEMENT_TYPE));
if (! ret)
return NULL;
+ if (! ret->defaultAttsNames.parser)
+ hashTableInit(&(ret->defaultAttsNames), getRootParserOf(parser, NULL));
if (ret->name != name)
poolDiscard(&dtd->pool);
else {
@@ -8503,22 +8500,24 @@ getElementType(XML_Parser parser, const
static XML_Char *
copyString(const XML_Char *s, XML_Parser parser) {
- size_t charsRequired = 0;
- XML_Char *result;
-
/* First determine how long the string is */
- while (s[charsRequired] != 0) {
- charsRequired++;
- }
- /* Include the terminator */
- charsRequired++;
+ const size_t charsRequired = xcslen(s) + /*null terminator*/ 1;
+
+ /* Detect and prevent integer overflow */
+ if (charsRequired > SIZE_MAX / sizeof(XML_Char))
+ return NULL;
+
+ const size_t bytesRequired = charsRequired * sizeof(XML_Char);
/* Now allocate space for the copy */
- result = MALLOC(parser, charsRequired * sizeof(XML_Char));
+ XML_Char *const result = MALLOC(parser, bytesRequired);
+
if (result == NULL)
return NULL;
+
/* Copy the original into place */
- memcpy(result, s, charsRequired * sizeof(XML_Char));
+ memcpy(result, s, bytesRequired);
+
return result;
}
@@ -8685,15 +8684,25 @@ entityTrackingReportStats(XML_Parser roo
const char *const entityName = entity->name;
# endif
+ const bool limitingWanted = rootParser->m_entity_stats.debugLevel < 2;
+ const int maxLimitedDepth = 10; // somewhat arbitrary
+ const int candidateIndentDepth
+ = (int)rootParser->m_entity_stats.currentDepth - 1;
+ const bool limitingNeeded
+ = limitingWanted && (candidateIndentDepth > maxLimitedDepth);
+ const char *const ellipisOrEmpty = limitingNeeded ? " [..] " : "";
+ const int indentDepth
+ = limitingNeeded ? (maxLimitedDepth - /* make space for ellipis */ 2)
+ : candidateIndentDepth;
+
fprintf(
stderr,
- "expat: Entities(%p): Count %9u, depth %2u/%2u %*s%s%s; %s length %d (xmlparse.c:%d)\n",
+ "expat: Entities(%p): Count %9u, depth %2u/%2u %*s%s%s%s; %s length %d (xmlparse.c:%d)\n",
(void *)rootParser, rootParser->m_entity_stats.countEverOpened,
rootParser->m_entity_stats.currentDepth,
- rootParser->m_entity_stats.maximumDepthSeen,
- ((int)rootParser->m_entity_stats.currentDepth - 1) * 2, "",
- entity->is_param ? "%" : "&", entityName, action, entity->textLen,
- sourceLine);
+ rootParser->m_entity_stats.maximumDepthSeen, indentDepth * 2, "",
+ ellipisOrEmpty, entity->is_param ? "%" : "&", entityName, action,
+ entity->textLen, sourceLine);
}
static void
Index: lib/libexpat/lib/xmlrole.c
===================================================================
RCS file: /cvs/src/lib/libexpat/lib/xmlrole.c,v
diff -u -p -r1.15 xmlrole.c
--- lib/libexpat/lib/xmlrole.c 18 Mar 2026 11:50:19 -0000 1.15
+++ lib/libexpat/lib/xmlrole.c 14 Aug 2026 17:31:11 -0000
@@ -12,7 +12,7 @@
Copyright (c) 2002-2006 Karl Waclawek
Copyright (c) 2002-2003 Fred L. Drake, Jr.
Copyright (c) 2005-2009 Steven Solie
- Copyright (c) 2016-2026 Sebastian Pipping
+ Copyright (c) 2016-2023 Sebastian Pipping
Copyright (c) 2017 Rhodri James
Copyright (c) 2019 David Loffredo
Copyright (c) 2021 Donghee Na
@@ -37,6 +37,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#include "expat_config.h"
Index: lib/libexpat/lib/xmlrole.h
===================================================================
RCS file: /cvs/src/lib/libexpat/lib/xmlrole.h,v
diff -u -p -r1.7 xmlrole.h
--- lib/libexpat/lib/xmlrole.h 25 Sep 2025 19:05:10 -0000 1.7
+++ lib/libexpat/lib/xmlrole.h 14 Aug 2026 17:31:11 -0000
@@ -31,6 +31,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#ifndef XmlRole_INCLUDED
Index: lib/libexpat/lib/xmltok.c
===================================================================
RCS file: /cvs/src/lib/libexpat/lib/xmltok.c,v
diff -u -p -r1.20 xmltok.c
--- lib/libexpat/lib/xmltok.c 18 Mar 2026 11:50:19 -0000 1.20
+++ lib/libexpat/lib/xmltok.c 14 Aug 2026 17:31:11 -0000
@@ -25,6 +25,8 @@
Copyright (c) 2022 Sean McBride
Copyright (c) 2023 Hanno Böck
Copyright (c) 2025 Alfonso Gregory
+ Copyright (c) 2026 Nick Begg
+ Copyright (c) 2026 Kartik Kenchi
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -45,6 +47,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#include "expat_config.h"
@@ -58,6 +62,7 @@
#endif
#include "internal.h"
+#define EXPAT_FALLTHROUGH do {} while(0)
#include "xmltok.h"
#include "nametab.h"
@@ -641,7 +646,7 @@ unicode_byte_type(char hi, char lo) {
*(*toP)++ = lo; \
break; \
} \
- /* fall through */ \
+ EXPAT_FALLTHROUGH; \
case 0x1: \
case 0x2: \
case 0x3: \
@@ -703,9 +708,10 @@ unicode_byte_type(char hi, char lo) {
enum XML_Convert_Result res = XML_CONVERT_COMPLETED; \
UNUSED_P(enc); \
fromLim = *fromP + (((fromLim - *fromP) >> 1) << 1); /* shrink to even */ \
- /* Avoid copying first half only of surrogate */ \
+ /* Avoid copying the first half (2 bytes) of surrogate pairs (4 bytes) */ \
if (fromLim - *fromP > ((toLim - *toP) << 1) \
- && (GET_HI(fromLim - 2) & 0xF8) == 0xD8) { \
+ && /* are the last two bytes a high surrogate (0xD800-0xDBFF)? */ \
+ (GET_HI(fromLim - 2) & 0xFC) == 0xD8) { \
fromLim -= 2; \
res = XML_CONVERT_INPUT_INCOMPLETE; \
} \
@@ -1175,6 +1181,13 @@ doParseXmlDecl(const ENCODING *(*encodin
*versionPtr = val;
if (versionEndPtr)
*versionEndPtr = ptr;
+ /* The version number must not be empty; VersionNum requires at least
+ one character. The encoding and standalone pseudo-attributes below
+ already reject an empty value, so keep version consistent. */
+ if (val == ptr - enc->minBytesPerChar) {
+ *badPtr = val;
+ return 0;
+ }
if (! parsePseudoAttribute(enc, ptr, end, &name, &nameEnd, &val, &ptr)) {
*badPtr = ptr;
return 0;
@@ -1557,7 +1570,7 @@ initScan(const ENCODING *const *encoding
case 0xEF: /* possibly first byte of UTF-8 BOM */
if (INIT_ENC_INDEX(enc) == ISO_8859_1_ENC && state == XML_CONTENT_STATE)
break;
- /* fall through */
+ EXPAT_FALLTHROUGH;
case 0x00:
case 0x3C:
return XML_TOK_PARTIAL;
Index: lib/libexpat/lib/xmltok.h
===================================================================
RCS file: /cvs/src/lib/libexpat/lib/xmltok.h,v
diff -u -p -r1.9 xmltok.h
--- lib/libexpat/lib/xmltok.h 17 Sep 2025 17:23:00 -0000 1.9
+++ lib/libexpat/lib/xmltok.h 14 Aug 2026 17:31:11 -0000
@@ -10,7 +10,7 @@
Copyright (c) 2000 Clark Cooper
Copyright (c) 2002 Fred L. Drake, Jr.
Copyright (c) 2002-2005 Karl Waclawek
- Copyright (c) 2016-2024 Sebastian Pipping
+ Copyright (c) 2016-2026 Sebastian Pipping
Copyright (c) 2017 Rhodri James
Licensed under the MIT license:
@@ -32,11 +32,15 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#ifndef XmlTok_INCLUDED
# define XmlTok_INCLUDED 1
+# include // uint64_t
+
# ifdef __cplusplus
extern "C" {
# endif
@@ -145,8 +149,8 @@ extern "C" {
typedef struct position {
/* first line and first column are 0 not 1 */
- XML_Size lineNumber;
- XML_Size columnNumber;
+ uint64_t lineNumber;
+ uint64_t columnNumber;
} POSITION;
typedef struct {
Index: lib/libexpat/lib/xmltok_impl.c
===================================================================
RCS file: /cvs/src/lib/libexpat/lib/xmltok_impl.c,v
diff -u -p -r1.18 xmltok_impl.c
--- lib/libexpat/lib/xmltok_impl.c 11 Feb 2024 00:56:28 -0000 1.18
+++ lib/libexpat/lib/xmltok_impl.c 14 Aug 2026 17:31:11 -0000
@@ -17,6 +17,7 @@
Copyright (c) 2019 David Loffredo
Copyright (c) 2020 Boris Kolpackov
Copyright (c) 2022 Martin Ettl
+ Copyright (c) 2026 Nick Begg
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -37,6 +38,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#ifdef XML_TOK_IMPL_C
@@ -83,7 +86,7 @@
*nextTokPtr = ptr; \
return XML_TOK_INVALID; \
} \
- /* fall through */ \
+ EXPAT_FALLTHROUGH; \
case BT_NMSTRT: \
case BT_HEX: \
case BT_DIGIT: \
@@ -112,7 +115,7 @@
*nextTokPtr = ptr; \
return XML_TOK_INVALID; \
} \
- /* fall through */ \
+ EXPAT_FALLTHROUGH; \
case BT_NMSTRT: \
case BT_HEX: \
ptr += MINBPC(enc); \
@@ -209,7 +212,7 @@ PREFIX(scanDecl)(const ENCODING *enc, co
*nextTokPtr = ptr;
return XML_TOK_INVALID;
}
- /* fall through */
+ EXPAT_FALLTHROUGH;
case BT_S:
case BT_CR:
case BT_LF:
@@ -323,7 +326,7 @@ PREFIX(scanPi)(const ENCODING *enc, cons
*nextTokPtr = ptr + MINBPC(enc);
return tok;
}
- /* fall through */
+ EXPAT_FALLTHROUGH;
default:
*nextTokPtr = ptr;
return XML_TOK_INVALID;
@@ -615,7 +618,7 @@ PREFIX(scanAtts)(const ENCODING *enc, co
return XML_TOK_INVALID;
}
}
- /* fall through */
+ EXPAT_FALLTHROUGH;
case BT_EQUALS: {
int open;
# ifdef XML_NS
@@ -898,7 +901,7 @@ PREFIX(contentTok)(const ENCODING *enc,
return XML_TOK_INVALID;
}
}
- /* fall through */
+ EXPAT_FALLTHROUGH;
case BT_AMP:
case BT_LT:
case BT_NONXML:
@@ -1059,7 +1062,7 @@ PREFIX(prologTok)(const ENCODING *enc, c
/* indicate that this might be part of a CR/LF pair */
return -XML_TOK_PROLOG_S;
}
- /* fall through */
+ EXPAT_FALLTHROUGH;
case BT_S:
case BT_LF:
for (;;) {
@@ -1074,7 +1077,7 @@ PREFIX(prologTok)(const ENCODING *enc, c
/* don't split CR/LF pair */
if (ptr + MINBPC(enc) != end)
break;
- /* fall through */
+ EXPAT_FALLTHROUGH;
default:
*nextTokPtr = ptr;
return XML_TOK_PROLOG_S;
@@ -1189,7 +1192,7 @@ PREFIX(prologTok)(const ENCODING *enc, c
tok = XML_TOK_NMTOKEN;
break;
}
- /* fall through */
+ EXPAT_FALLTHROUGH;
default:
*nextTokPtr = ptr;
return XML_TOK_INVALID;
@@ -1484,7 +1487,7 @@ PREFIX(isPublicId)(const ENCODING *enc,
case BT_NMSTRT:
if (! (BYTE_TO_ASCII(enc, ptr) & ~0x7f))
break;
- /* fall through */
+ EXPAT_FALLTHROUGH;
default:
switch (BYTE_TO_ASCII(enc, ptr)) {
case 0x24: /* $ */
Index: lib/libexpat/lib/xmltok_impl.h
===================================================================
RCS file: /cvs/src/lib/libexpat/lib/xmltok_impl.h,v
diff -u -p -r1.5 xmltok_impl.h
--- lib/libexpat/lib/xmltok_impl.h 27 Oct 2022 12:58:37 -0000 1.5
+++ lib/libexpat/lib/xmltok_impl.h 14 Aug 2026 17:31:11 -0000
@@ -29,6 +29,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
enum {
Index: lib/libexpat/lib/xmltok_ns.c
===================================================================
RCS file: /cvs/src/lib/libexpat/lib/xmltok_ns.c,v
diff -u -p -r1.9 xmltok_ns.c
--- lib/libexpat/lib/xmltok_ns.c 18 Mar 2026 11:50:19 -0000 1.9
+++ lib/libexpat/lib/xmltok_ns.c 14 Aug 2026 17:31:11 -0000
@@ -11,7 +11,7 @@
Copyright (c) 2002 Greg Stein
Copyright (c) 2002 Fred L. Drake, Jr.
Copyright (c) 2002-2006 Karl Waclawek
- Copyright (c) 2017-2026 Sebastian Pipping
+ Copyright (c) 2017-2021 Sebastian Pipping
Copyright (c) 2025 Alfonso Gregory
Licensed under the MIT license:
@@ -33,6 +33,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#ifdef XML_TOK_NS_C
Index: lib/libexpat/tests/acc_tests.c
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/acc_tests.c,v
diff -u -p -r1.3 acc_tests.c
--- lib/libexpat/tests/acc_tests.c 14 Mar 2025 20:20:30 -0000 1.3
+++ lib/libexpat/tests/acc_tests.c 14 Aug 2026 17:31:11 -0000
@@ -10,7 +10,7 @@
Copyright (c) 2003 Greg Stein
Copyright (c) 2005-2007 Steven Solie
Copyright (c) 2005-2012 Karl Waclawek
- Copyright (c) 2016-2024 Sebastian Pipping
+ Copyright (c) 2016-2026 Sebastian Pipping
Copyright (c) 2017-2022 Rhodri James
Copyright (c) 2017 Joe Orton
Copyright (c) 2017 José Gutiérrez de la Concha
@@ -39,13 +39,15 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
+#include "expat_config.h"
+
#include /* NAN, INFINITY */
#include
#include
-
-#include "expat_config.h"
#include "expat.h"
#include "internal.h"
Index: lib/libexpat/tests/acc_tests.h
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/acc_tests.h,v
diff -u -p -r1.1 acc_tests.h
--- lib/libexpat/tests/acc_tests.h 11 Feb 2024 00:56:28 -0000 1.1
+++ lib/libexpat/tests/acc_tests.h 14 Aug 2026 17:31:11 -0000
@@ -38,6 +38,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#ifdef __cplusplus
Index: lib/libexpat/tests/alloc_tests.c
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/alloc_tests.c,v
diff -u -p -r1.4 alloc_tests.c
--- lib/libexpat/tests/alloc_tests.c 25 Sep 2025 19:05:10 -0000 1.4
+++ lib/libexpat/tests/alloc_tests.c 14 Aug 2026 17:31:12 -0000
@@ -10,7 +10,7 @@
Copyright (c) 2003 Greg Stein
Copyright (c) 2005-2007 Steven Solie
Copyright (c) 2005-2012 Karl Waclawek
- Copyright (c) 2016-2025 Sebastian Pipping
+ Copyright (c) 2016-2026 Sebastian Pipping
Copyright (c) 2017-2022 Rhodri James
Copyright (c) 2017 Joe Orton
Copyright (c) 2017 José Gutiérrez de la Concha
@@ -20,6 +20,7 @@
Copyright (c) 2021 Donghee Na
Copyright (c) 2023 Sony Corporation / Snild Dolkow
Copyright (c) 2025 Berkay Eren Ürün
+ Copyright (c) 2026 Matthew Fernandez
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -40,20 +41,22 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#if defined(NDEBUG)
# undef NDEBUG /* because test suite relies on assert(...) at the moment */
#endif
+#include "expat_config.h"
+
#include /* NAN, INFINITY */
#include
#include /* for SIZE_MAX */
#include
#include
-#include "expat_config.h"
-
#include "expat.h"
#include "internal.h"
#include "common.h"
@@ -2137,8 +2140,7 @@ START_TEST(test_alloc_tracker_pointer_al
XML_Parser parser = XML_ParserCreate(NULL);
#if XML_GE == 1
assert_true(sizeof(long long) >= sizeof(size_t)); // self-test
- long long *const ptr
- = (long long *)expat_malloc(parser, 4 * sizeof(long long), -1);
+ long long *const ptr = expat_malloc(parser, 4 * sizeof(long long), -1);
ptr[0] = 0LL;
ptr[1] = 1LL;
ptr[2] = 2LL;
Index: lib/libexpat/tests/alloc_tests.h
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/alloc_tests.h,v
diff -u -p -r1.1 alloc_tests.h
--- lib/libexpat/tests/alloc_tests.h 11 Feb 2024 00:56:28 -0000 1.1
+++ lib/libexpat/tests/alloc_tests.h 14 Aug 2026 17:31:12 -0000
@@ -38,6 +38,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#ifdef __cplusplus
Index: lib/libexpat/tests/basic_tests.c
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/basic_tests.c,v
diff -u -p -r1.9 basic_tests.c
--- lib/libexpat/tests/basic_tests.c 18 Mar 2026 11:50:19 -0000 1.9
+++ lib/libexpat/tests/basic_tests.c 14 Aug 2026 17:31:12 -0000
@@ -19,7 +19,10 @@
Copyright (c) 2020 Tim Gates
Copyright (c) 2021 Donghee Na
Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow
- Copyright (c) 2024-2025 Berkay Eren Ürün
+ Copyright (c) 2024-2026 Berkay Eren Ürün
+ Copyright (c) 2026 Francesco Bertolaccini
+ Copyright (c) 2026 Matthew Fernandez
+ Copyright (c) 2026 Kartik Kenchi
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -40,24 +43,23 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#if defined(NDEBUG)
# undef NDEBUG /* because test suite relies on assert(...) at the moment */
#endif
-#include
+#include "expat_config.h"
+#include
+#include // ULONG_MAX
+#include
#include
#include
#include
-#if ! defined(__cplusplus)
-# include
-#endif
-
-#include "expat_config.h"
-
#include "expat.h"
#include "internal.h"
#include "minicheck.h"
@@ -68,6 +70,21 @@
#include "siphash.h"
#include "basic_tests.h"
+#define EXPAT_TESTS_ASAN 1
+
+#if defined(__has_feature)
+# if ! __has_feature(address_sanitizer)
+# undef EXPAT_TESTS_ASAN
+# define EXPAT_TESTS_ASAN 0
+# endif
+#endif
+
+#if ULONG_MAX == 18446744073709551615u // 2^64-1
+# define EXPAT_TESTS_64BIT 1
+#else
+# define EXPAT_TESTS_64BIT 0
+#endif
+
static void
basic_setup(void) {
g_parser = XML_ParserCreate(NULL);
@@ -948,6 +965,14 @@ START_TEST(test_xmldecl_missing_value) {
}
END_TEST
+START_TEST(test_xmldecl_empty_version) {
+ expect_failure("\n"
+ "",
+ XML_ERROR_XML_DECL,
+ "Failed to report empty version in XML declaration");
+}
+END_TEST
+
/* Regression test for SF bug #584832. */
START_TEST(test_unknown_encoding_internal_entity) {
const char *text = "\n"
@@ -2466,11 +2491,9 @@ START_TEST(test_attributes) {
{XCS("id"), XCS("one")},
{NULL, NULL}};
AttrInfo tag_info[] = {{XCS("c"), XCS("3")}, {NULL, NULL}};
- ElementInfo info[] = {{XCS("doc"), 3, XCS("id"), NULL},
- {XCS("tag"), 1, NULL, NULL},
- {NULL, 0, NULL, NULL}};
- info[0].attributes = doc_info;
- info[1].attributes = tag_info;
+ ElementInfo info[] = {{XCS("doc"), 3, 0, XCS("id"), doc_info},
+ {XCS("tag"), 1, 0, NULL, tag_info},
+ {NULL, 0, 0, NULL, NULL}};
XML_Parser parser = XML_ParserCreate(NULL);
assert_true(parser != NULL);
@@ -2489,6 +2512,279 @@ START_TEST(test_attributes) {
}
END_TEST
+START_TEST(test_duplicate_cdata_attribute) {
+ /*
+ https://www.w3.org/TR/xml/#attdecls
+
+ Test the following statement from the linked specification:
+ When more than one definition is provided for the same attribute of a given
+ element type, the first declaration is binding and later declarations are
+ ignored.
+ */
+
+ const char *text
+ = "\n"
+ "]>\n"
+ "\n";
+ AttrInfo doc_info[] = {{XCS("attribute"), XCS("expected")}, {NULL, NULL}};
+ ElementInfo info[]
+ = {{XCS("doc"), 0, 1, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}};
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ ParserAndElementInfo parserAndElementInfos = {
+ parser,
+ info,
+ };
+
+ XML_SetStartElementHandler(parser, counting_start_element_handler);
+ XML_SetUserData(parser, &parserAndElementInfos);
+
+ if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(parser);
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_duplicate_id_attribute_1) {
+ /*
+ https://www.w3.org/TR/xml/#attdecls
+
+ Test the following statement from the linked specification:
+ When more than one definition is provided for the same attribute of a given
+ element type, the first declaration is binding and later declarations are
+ ignored.
+ */
+
+ const char *text
+ = "\n"
+ "]>\n"
+ "\n";
+ AttrInfo doc_info[] = {{XCS("identifier"), XCS("expected")}, {NULL, NULL}};
+ ElementInfo info[]
+ = {{XCS("doc"), 0, 1, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}};
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ ParserAndElementInfo parserAndElementInfos = {
+ parser,
+ info,
+ };
+
+ XML_SetStartElementHandler(parser, counting_start_element_handler);
+ XML_SetUserData(parser, &parserAndElementInfos);
+
+ if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(parser);
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_duplicate_id_attribute_2) {
+ /*
+ https://www.w3.org/TR/xml/#attdecls
+
+ Test the following statement from the linked specification:
+ When more than one definition is provided for the same attribute of a given
+ element type, the first declaration is binding and later declarations are
+ ignored.
+ */
+
+ const char *text
+ = "\n"
+ "]>\n"
+ "\n";
+ AttrInfo doc_info[] = {{NULL, NULL}};
+
+ ElementInfo info[]
+ = {{XCS("doc"), 0, 0, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}};
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ ParserAndElementInfo parserAndElementInfos = {
+ parser,
+ info,
+ };
+
+ XML_SetStartElementHandler(parser, counting_start_element_handler);
+ XML_SetUserData(parser, &parserAndElementInfos);
+
+ if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(parser);
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_duplicate_cdata_attribute_multiple_attlistdecl) {
+ /*
+ https://www.w3.org/TR/xml/#attdecls
+
+ Test the following statement from the linked specification:
+ When more than one AttlistDecl is provided for a given element type,
+ the contents of all those provided are merged.
+ */
+ const char *text = "\n"
+ " \n"
+ "]>\n"
+ "\n";
+ AttrInfo doc_info[] = {{XCS("attribute"), XCS("expected")}, {NULL, NULL}};
+ ElementInfo info[]
+ = {{XCS("doc"), 0, 1, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}};
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ ParserAndElementInfo parserAndElementInfos = {
+ parser,
+ info,
+ };
+
+ XML_SetStartElementHandler(parser, counting_start_element_handler);
+ XML_SetUserData(parser, &parserAndElementInfos);
+
+ if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(parser);
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_duplicate_cdata_attribute_multiple_attlistdecl_2) {
+ /*
+ https://www.w3.org/TR/xml/#attdecls
+
+ Test the following statement from the linked specification:
+ When more than one AttlistDecl is provided for a given element type,
+ the contents of all those provided are merged.
+ */
+ const char *text = "\n"
+ " \n"
+ " \n"
+ "]>\n"
+ "\n";
+ AttrInfo doc_info[] = {{XCS("attribute"), XCS("expected_doc")}, {NULL, NULL}};
+ AttrInfo tag_info[] = {{XCS("attribute"), XCS("expected_tag")}, {NULL, NULL}};
+ ElementInfo info[] = {{XCS("doc"), 0, 1, NULL, doc_info},
+ {XCS("tag"), 0, 1, NULL, tag_info},
+ {NULL, 0, 0, NULL, NULL}};
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ ParserAndElementInfo parserAndElementInfos = {
+ parser,
+ info,
+ };
+
+ XML_SetStartElementHandler(parser, counting_start_element_handler);
+ XML_SetUserData(parser, &parserAndElementInfos);
+
+ if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(parser);
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_duplicate_cdata_attribute_multiple_attlistdecl_3) {
+ /*
+ https://www.w3.org/TR/xml/#attdecls
+
+ Test the following statement from the linked specification:
+ When more than one AttlistDecl is provided for a given element type,
+ the contents of all those provided are merged.
+ */
+ const char *text
+ = "\n"
+ " \n"
+ " \n"
+ "]>\n"
+ "\n";
+ AttrInfo doc_info[] = {{XCS("attribute"), XCS("expected_doc")},
+ {XCS("second_attribute"), XCS("second_expected_doc")},
+ {NULL, NULL}};
+ AttrInfo tag_info[] = {{XCS("attribute"), XCS("expected_tag")}, {NULL, NULL}};
+ ElementInfo info[] = {{XCS("doc"), 0, 2, NULL, doc_info},
+ {XCS("tag"), 0, 1, NULL, tag_info},
+ {NULL, 0, 0, NULL, NULL}};
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ ParserAndElementInfo parserAndElementInfos = {
+ parser,
+ info,
+ };
+
+ XML_SetStartElementHandler(parser, counting_start_element_handler);
+ XML_SetUserData(parser, &parserAndElementInfos);
+
+ if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(parser);
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_duplicate_id_attribute_multiple_attlistdecl) {
+ /*
+ https://www.w3.org/TR/xml/#attdecls
+
+ Test the following statement from the linked specification:
+ When more than one AttlistDecl is provided for a given element type,
+ the contents of all those provided are merged.
+ */
+ const char *text = "\n"
+ " \n"
+ " \n"
+ "]>\n"
+ "\n";
+ AttrInfo doc_info[]
+ = {{XCS("identifier"), XCS("doc_identity")}, {NULL, NULL}};
+ AttrInfo tag_info[]
+ = {{XCS("identifier"), XCS("identifier_tag")}, {NULL, NULL}};
+ ElementInfo info[] = {{XCS("doc"), 1, 0, XCS("identifier"), doc_info},
+ {XCS("tag"), 0, 1, NULL, tag_info},
+ {NULL, 0, 0, NULL, NULL}};
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ ParserAndElementInfo parserAndElementInfos = {
+ parser,
+ info,
+ };
+
+ XML_SetStartElementHandler(parser, counting_start_element_handler);
+ XML_SetUserData(parser, &parserAndElementInfos);
+
+ if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
+ != XML_STATUS_OK)
+ xml_failure(parser);
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
/* Test reset works correctly in the middle of processing an internal
* entity. Exercises some obscure code in XML_ParserReset().
*/
@@ -3009,7 +3305,6 @@ get_feature(enum XML_FeatureEnum feature
/* Test odd corners of the XML_GetBuffer interface */
START_TEST(test_get_buffer_1) {
const char *text = get_buffer_test_text;
- void *buffer;
long context_bytes;
/* Attempt to allocate a negative length buffer */
@@ -3017,7 +3312,7 @@ START_TEST(test_get_buffer_1) {
fail("Negative length buffer not failed");
/* Now get a small buffer and extend it past valid length */
- buffer = XML_GetBuffer(g_parser, 1536);
+ void *const buffer = XML_GetBuffer(g_parser, 1536);
if (buffer == NULL)
fail("1.5K buffer failed");
assert(buffer != NULL);
@@ -3052,10 +3347,9 @@ END_TEST
/* Test more corners of the XML_GetBuffer interface */
START_TEST(test_get_buffer_2) {
const char *text = get_buffer_test_text;
- void *buffer;
/* Now get a decent buffer */
- buffer = XML_GetBuffer(g_parser, 1536);
+ void *const buffer = XML_GetBuffer(g_parser, 1536);
if (buffer == NULL)
fail("1.5K buffer failed");
assert(buffer != NULL);
@@ -3137,12 +3431,16 @@ START_TEST(test_buffer_can_grow_to_max)
if (s != XML_STATUS_OK)
xml_failure(parser);
+// Avoid running into "AddressSanitizer: out of memory" on 32bit Windows
+#if ! defined(_WIN32) || EXPAT_TESTS_ASAN == 0 || EXPAT_TESTS_64BIT == 1
// XML_CONTEXT_BYTES of the prefix may remain in the buffer;
// subtracting the whole prefix is easiest, and close enough.
assert_true(XML_GetBuffer(parser, maxbuf - prefix_len) != NULL);
// The limit should be consistent; no prefix should allow us to
// reach above the max buffer size.
assert_true(XML_GetBuffer(parser, maxbuf + 1) == NULL);
+#endif
+
XML_ParserFree(parser);
}
}
@@ -3410,8 +3708,7 @@ external_bom_checker(XML_Parser parser,
fail("Could not create external entity parser");
if (! xcstrcmp(systemId, XCS("004-2.ent"))) {
- struct bom_testdata *const testdata
- = (struct bom_testdata *)XML_GetUserData(parser);
+ struct bom_testdata *const testdata = XML_GetUserData(parser);
const char *const external = testdata->external;
const int split = testdata->split;
testdata->nested_callback_happened = XML_TRUE;
@@ -4091,6 +4388,37 @@ START_TEST(test_skipped_external_entity)
}
END_TEST
+START_TEST(test_scaff_index_shared_across_external_entity_parser) {
+ const char text[]
+ = "\n"
+ "\n"
+ "%e;\n"
+ "\n"
+ "]>\n"
+ "";
+ ExtOption options[]
+ = {{XCS("ext"),
+ ""},
+ {NULL, NULL}};
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ XML_SetParamEntityParsing(parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
+ XML_SetUserData(parser, options);
+ XML_SetExternalEntityRefHandler(parser, external_entity_optioner);
+ XML_SetElementDeclHandler(parser, dummy_element_decl_handler);
+
+ if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE)
+ == XML_STATUS_ERROR)
+ xml_failure(parser);
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
/* Test a different form of unknown external entity */
START_TEST(test_skipped_null_loaded_ext_entity) {
const char *text = "\n"
@@ -5476,7 +5804,7 @@ START_TEST(test_deep_nested_entity) {
const size_t N_LINES = 60000;
const size_t SIZE_PER_LINE = 50;
- char *const text = (char *)malloc((N_LINES + 4) * SIZE_PER_LINE);
+ char *const text = malloc((N_LINES + 4) * SIZE_PER_LINE);
if (text == NULL) {
fail("malloc failed");
}
@@ -5522,7 +5850,7 @@ START_TEST(test_deep_nested_attribute_en
const size_t N_LINES = 60000;
const size_t SIZE_PER_LINE = 100;
- char *const text = (char *)malloc((N_LINES + 4) * SIZE_PER_LINE);
+ char *const text = malloc((N_LINES + 4) * SIZE_PER_LINE);
if (text == NULL) {
fail("malloc failed");
}
@@ -5543,8 +5871,8 @@ START_TEST(test_deep_nested_attribute_en
(long unsigned)(N_LINES - 1));
AttrInfo doc_info[] = {{XCS("name"), XCS("deepText")}, {NULL, NULL}};
- ElementInfo info[] = {{XCS("foo"), 1, NULL, NULL}, {NULL, 0, NULL, NULL}};
- info[0].attributes = doc_info;
+ ElementInfo info[]
+ = {{XCS("foo"), 1, 0, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}};
XML_Parser parser = XML_ParserCreate(NULL);
ParserAndElementInfo parserPlusElemenInfo = {parser, info};
@@ -5565,7 +5893,7 @@ START_TEST(test_deep_nested_entity_delay
const size_t N_LINES = 70000;
const size_t SIZE_PER_LINE = 100;
- char *const text = (char *)malloc((N_LINES + 4) * SIZE_PER_LINE);
+ char *const text = malloc((N_LINES + 4) * SIZE_PER_LINE);
if (text == NULL) {
fail("malloc failed");
}
@@ -6046,7 +6374,7 @@ START_TEST(test_bypass_heuristic_when_cl
}
const int document_length = 65536;
- char *const document = (char *)malloc(document_length);
+ char *const document = malloc(document_length);
assert_true(document != NULL);
const XML_Memory_Handling_Suite memfuncs = {
@@ -6158,7 +6486,7 @@ START_TEST(test_varying_buffer_fills) {
return; // this test is slow, and doesn't use _XML_Parse_SINGLE_BYTES().
}
- char *const document = (char *)malloc(document_length);
+ char *const document = malloc(document_length);
assert_true(document != NULL);
memset(document, 'x', document_length);
document[0] = '<';
@@ -6328,6 +6656,7 @@ make_basic_test_case(Suite *s) {
tcase_add_test(tc_basic, test_xmldecl_invalid);
tcase_add_test(tc_basic, test_xmldecl_missing_attr);
tcase_add_test(tc_basic, test_xmldecl_missing_value);
+ tcase_add_test(tc_basic, test_xmldecl_empty_version);
tcase_add_test__if_xml_ge(tc_basic, test_unknown_encoding_internal_entity);
tcase_add_test(tc_basic, test_unrecognised_encoding_internal_entity);
tcase_add_test__ifdef_xml_dtd(tc_basic, test_ext_entity_set_encoding);
@@ -6378,6 +6707,15 @@ make_basic_test_case(Suite *s) {
tcase_add_test__ifdef_xml_dtd(tc_basic, test_empty_foreign_dtd);
tcase_add_test(tc_basic, test_set_base);
tcase_add_test(tc_basic, test_attributes);
+ tcase_add_test(tc_basic, test_duplicate_cdata_attribute);
+ tcase_add_test(tc_basic, test_duplicate_id_attribute_1);
+ tcase_add_test(tc_basic, test_duplicate_id_attribute_2);
+ tcase_add_test(tc_basic, test_duplicate_cdata_attribute_multiple_attlistdecl);
+ tcase_add_test(tc_basic,
+ test_duplicate_cdata_attribute_multiple_attlistdecl_2);
+ tcase_add_test(tc_basic,
+ test_duplicate_cdata_attribute_multiple_attlistdecl_3);
+ tcase_add_test(tc_basic, test_duplicate_id_attribute_multiple_attlistdecl);
tcase_add_test__if_xml_ge(tc_basic, test_reset_in_entity);
tcase_add_test(tc_basic, test_resume_invalid_parse);
tcase_add_test(tc_basic, test_resume_resuspended);
@@ -6452,6 +6790,8 @@ make_basic_test_case(Suite *s) {
tcase_add_test(tc_basic, test_trailing_cr_in_att_value);
tcase_add_test(tc_basic, test_standalone_internal_entity);
tcase_add_test(tc_basic, test_skipped_external_entity);
+ tcase_add_test__ifdef_xml_dtd(
+ tc_basic, test_scaff_index_shared_across_external_entity_parser);
tcase_add_test(tc_basic, test_skipped_null_loaded_ext_entity);
tcase_add_test(tc_basic, test_skipped_unloaded_ext_entity);
tcase_add_test__ifdef_xml_dtd(tc_basic, test_param_entity_with_trailing_cr);
Index: lib/libexpat/tests/basic_tests.h
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/basic_tests.h,v
diff -u -p -r1.1 basic_tests.h
--- lib/libexpat/tests/basic_tests.h 11 Feb 2024 00:56:28 -0000 1.1
+++ lib/libexpat/tests/basic_tests.h 14 Aug 2026 17:31:12 -0000
@@ -38,6 +38,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#ifdef __cplusplus
Index: lib/libexpat/tests/chardata.c
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/chardata.c,v
diff -u -p -r1.7 chardata.c
--- lib/libexpat/tests/chardata.c 11 Feb 2024 00:56:28 -0000 1.7
+++ lib/libexpat/tests/chardata.c 14 Aug 2026 17:31:12 -0000
@@ -33,6 +33,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#if defined(NDEBUG)
@@ -47,15 +49,7 @@
#include
#include "chardata.h"
-
-static int
-xmlstrlen(const XML_Char *s) {
- int len = 0;
- assert(s != NULL);
- while (s[len] != 0)
- ++len;
- return len;
-}
+#define xcslen(s) (strlen(s))
void
CharData_Init(CharData *storage) {
@@ -73,7 +67,7 @@ CharData_AppendXMLChars(CharData *storag
if (storage->count < 0)
storage->count = 0;
if (len < 0)
- len = xmlstrlen(s);
+ len = (int)xcslen(s);
if ((len + storage->count) > maxchars) {
len = (maxchars - storage->count);
}
@@ -85,7 +79,7 @@ CharData_AppendXMLChars(CharData *storag
int
CharData_CheckXMLChars(CharData *storage, const XML_Char *expected) {
- int len = xmlstrlen(expected);
+ int len = (int)xcslen(expected);
int count;
assert(storage != NULL);
Index: lib/libexpat/tests/chardata.h
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/chardata.h,v
diff -u -p -r1.6 chardata.h
--- lib/libexpat/tests/chardata.h 26 May 2021 19:14:32 -0000 1.6
+++ lib/libexpat/tests/chardata.h 14 Aug 2026 17:31:12 -0000
@@ -30,6 +30,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#ifdef __cplusplus
Index: lib/libexpat/tests/common.c
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/common.c,v
diff -u -p -r1.6 common.c
--- lib/libexpat/tests/common.c 17 Sep 2025 17:23:00 -0000 1.6
+++ lib/libexpat/tests/common.c 14 Aug 2026 17:31:12 -0000
@@ -10,7 +10,7 @@
Copyright (c) 2003 Greg Stein
Copyright (c) 2005-2007 Steven Solie
Copyright (c) 2005-2012 Karl Waclawek
- Copyright (c) 2016-2025 Sebastian Pipping
+ Copyright (c) 2016-2026 Sebastian Pipping
Copyright (c) 2017-2022 Rhodri James
Copyright (c) 2017 Joe Orton
Copyright (c) 2017 José Gutiérrez de la Concha
@@ -19,6 +19,7 @@
Copyright (c) 2020 Tim Gates
Copyright (c) 2021 Donghee Na
Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow
+ Copyright (c) 2026 Matthew Fernandez
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -39,15 +40,18 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
+#include "expat_config.h"
+
#include
#include
#include // for SIZE_MAX
#include
#include
-#include "expat_config.h"
#include "expat.h"
#include "internal.h"
#include "chardata.h"
@@ -261,7 +265,7 @@ _run_attribute_check(const char *text, c
void
_run_ext_character_check(const char *text, ExtTest *test_data,
const XML_Char *expected, const char *file, int line) {
- CharData *const storage = (CharData *)malloc(sizeof(CharData));
+ CharData *const storage = malloc(sizeof(CharData));
CharData_Init(storage);
test_data->storage = storage;
@@ -320,7 +324,7 @@ portable_strndup(const char *s, size_t n
n = portable_strnlen(s, n);
- char *const buffer = (char *)malloc(n + 1);
+ char *const buffer = malloc(n + 1);
if (buffer == NULL) {
errno = ENOMEM;
return NULL;
Index: lib/libexpat/tests/common.h
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/common.h,v
diff -u -p -r1.3 common.h
--- lib/libexpat/tests/common.h 29 Mar 2025 19:10:43 -0000 1.3
+++ lib/libexpat/tests/common.h 14 Aug 2026 17:31:12 -0000
@@ -39,6 +39,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#ifdef __cplusplus
Index: lib/libexpat/tests/dummy.c
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/dummy.c,v
diff -u -p -r1.1 dummy.c
--- lib/libexpat/tests/dummy.c 11 Feb 2024 00:56:28 -0000 1.1
+++ lib/libexpat/tests/dummy.c 14 Aug 2026 17:31:12 -0000
@@ -38,6 +38,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#include "expat.h"
Index: lib/libexpat/tests/dummy.h
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/dummy.h,v
diff -u -p -r1.1 dummy.h
--- lib/libexpat/tests/dummy.h 11 Feb 2024 00:56:28 -0000 1.1
+++ lib/libexpat/tests/dummy.h 14 Aug 2026 17:31:12 -0000
@@ -38,6 +38,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#ifdef __cplusplus
Index: lib/libexpat/tests/handlers.c
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/handlers.c,v
diff -u -p -r1.5 handlers.c
--- lib/libexpat/tests/handlers.c 3 Feb 2026 08:49:46 -0000 1.5
+++ lib/libexpat/tests/handlers.c 14 Aug 2026 17:31:12 -0000
@@ -19,6 +19,9 @@
Copyright (c) 2020 Tim Gates
Copyright (c) 2021 Donghee Na
Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow
+ Copyright (c) 2026 Matthew Fernandez
+ Copyright (c) 2026 Berkay Eren Ürün
+ Copyright (c) 2026 Kartik Kenchi
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -39,19 +42,21 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#if defined(NDEBUG)
# undef NDEBUG /* because test suite relies on assert(...) at the moment */
#endif
+#include "expat_config.h"
+
#include
#include
#include
#include
-#include "expat_config.h"
-
#include "expat.h"
#include "internal.h"
#include "chardata.h"
@@ -137,7 +142,7 @@ counting_start_element_handler(void *use
fail("ID does not have the correct name");
return;
}
- for (i = 0; i < info->attr_count; i++) {
+ for (i = 0; i < info->attr_count + info->default_attr_count; i++) {
attr = info->attributes;
while (attr->name != NULL) {
if (! xcstrcmp(atts[0], attr->name))
@@ -155,6 +160,9 @@ counting_start_element_handler(void *use
/* Remember, two entries in atts per attribute (see above) */
atts += 2;
}
+
+ // Self-test that the test case's list of expected attributes is complete
+ assert_true(atts[0] == NULL);
}
void XMLCALL
@@ -423,7 +431,7 @@ int XMLCALL
external_entity_optioner(XML_Parser parser, const XML_Char *context,
const XML_Char *base, const XML_Char *systemId,
const XML_Char *publicId) {
- ExtOption *options = (ExtOption *)XML_GetUserData(parser);
+ ExtOption *options = XML_GetUserData(parser);
XML_Parser ext_parser;
UNUSED_P(base);
@@ -449,7 +457,7 @@ int XMLCALL
external_entity_loader(XML_Parser parser, const XML_Char *context,
const XML_Char *base, const XML_Char *systemId,
const XML_Char *publicId) {
- ExtTest *test_data = (ExtTest *)XML_GetUserData(parser);
+ ExtTest *test_data = XML_GetUserData(parser);
XML_Parser extparser;
UNUSED_P(base);
@@ -477,7 +485,7 @@ external_entity_faulter(XML_Parser parse
const XML_Char *base, const XML_Char *systemId,
const XML_Char *publicId) {
XML_Parser ext_parser;
- ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser);
+ ExtFaults *fault = XML_GetUserData(parser);
UNUSED_P(base);
UNUSED_P(systemId);
@@ -650,7 +658,7 @@ external_entity_suspending_faulter(XML_P
const XML_Char *systemId,
const XML_Char *publicId) {
XML_Parser ext_parser;
- ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser);
+ ExtFaults *fault = XML_GetUserData(parser);
void *buffer;
int parse_len = (int)strlen(fault->parse_text);
@@ -981,7 +989,7 @@ external_entity_valuer(XML_Parser parser
== XML_STATUS_ERROR)
xml_failure(ext_parser);
} else if (! xcstrcmp(systemId, XCS("004-2.ent"))) {
- ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser);
+ ExtFaults *fault = XML_GetUserData(parser);
enum XML_Status status;
enum XML_Error error;
@@ -1083,7 +1091,7 @@ int XMLCALL
external_entity_public(XML_Parser parser, const XML_Char *context,
const XML_Char *base, const XML_Char *systemId,
const XML_Char *publicId) {
- const char *text1 = (const char *)XML_GetUserData(parser);
+ const char *text1 = XML_GetUserData(parser);
const char *text2 = "";
const char *text = NULL;
XML_Parser ext_parser;
@@ -1139,7 +1147,7 @@ int XMLCALL
external_entity_oneshot_loader(XML_Parser parser, const XML_Char *context,
const XML_Char *base, const XML_Char *systemId,
const XML_Char *publicId) {
- ExtHdlrData *test_data = (ExtHdlrData *)XML_GetUserData(parser);
+ ExtHdlrData *test_data = XML_GetUserData(parser);
XML_Parser ext_parser;
UNUSED_P(base);
@@ -1164,7 +1172,7 @@ int XMLCALL
external_entity_loader2(XML_Parser parser, const XML_Char *context,
const XML_Char *base, const XML_Char *systemId,
const XML_Char *publicId) {
- ExtTest2 *test_data = (ExtTest2 *)XML_GetUserData(parser);
+ ExtTest2 *test_data = XML_GetUserData(parser);
XML_Parser extparser;
UNUSED_P(base);
@@ -1191,7 +1199,7 @@ int XMLCALL
external_entity_faulter2(XML_Parser parser, const XML_Char *context,
const XML_Char *base, const XML_Char *systemId,
const XML_Char *publicId) {
- ExtFaults2 *test_data = (ExtFaults2 *)XML_GetUserData(parser);
+ ExtFaults2 *test_data = XML_GetUserData(parser);
XML_Parser extparser;
UNUSED_P(base);
@@ -1309,7 +1317,7 @@ int XMLCALL
external_entity_dbl_handler(XML_Parser parser, const XML_Char *context,
const XML_Char *base, const XML_Char *systemId,
const XML_Char *publicId) {
- int *pcallno = (int *)XML_GetUserData(parser);
+ int *pcallno = XML_GetUserData(parser);
int callno = *pcallno;
const char *text;
XML_Parser new_parser = NULL;
@@ -1366,7 +1374,7 @@ int XMLCALL
external_entity_dbl_handler_2(XML_Parser parser, const XML_Char *context,
const XML_Char *base, const XML_Char *systemId,
const XML_Char *publicId) {
- int *pcallno = (int *)XML_GetUserData(parser);
+ int *pcallno = XML_GetUserData(parser);
int callno = *pcallno;
const char *text;
XML_Parser new_parser;
@@ -1461,7 +1469,7 @@ int XMLCALL
external_entity_alloc(XML_Parser parser, const XML_Char *context,
const XML_Char *base, const XML_Char *systemId,
const XML_Char *publicId) {
- const char *text = (const char *)XML_GetUserData(parser);
+ const char *text = XML_GetUserData(parser);
XML_Parser ext_parser;
int parse_res;
@@ -1516,8 +1524,7 @@ accounting_external_entity_ref_handler(X
UNUSED_P(base);
UNUSED_P(publicId);
- const struct AccountingTestCase *const testCase
- = (const struct AccountingTestCase *)XML_GetUserData(parser);
+ const struct AccountingTestCase *const testCase = XML_GetUserData(parser);
const char *externalText = NULL;
if (xcstrcmp(systemId, XCS("first.ent")) == 0) {
@@ -1987,4 +1994,52 @@ accumulate_and_suspend_comment_handler(v
ParserPlusStorage *const parserPlusStorage = (ParserPlusStorage *)userData;
accumulate_comment(parserPlusStorage->storage, data);
XML_StopParser(parserPlusStorage->parser, XML_TRUE);
+}
+
+void XMLCALL
+forbidden_calls_character_handler(void *userData, const XML_Char *s, int len) {
+ UNUSED_P(s);
+ UNUSED_P(len);
+ XML_Parser parser = userData;
+
+ assert_true(parser != NULL); // self-test
+
+ assert_true(XML_GetBuffer(parser, 123) == NULL); // i.e. rejected
+
+ assert_true(XML_Parse(parser, "", 0, /*isFinal=*/XML_FALSE)
+ == XML_STATUS_ERROR); // i.e. rejected
+
+ assert_true(XML_ParseBuffer(parser, 0, /*isFinal=*/XML_FALSE)
+ == XML_STATUS_ERROR); // i.e. rejected
+
+ XML_ParserFree(parser); // rejected
+
+ assert_true(XML_ParserReset(parser, /*encodingName=*/NULL)
+ == XML_FALSE); // i.e. rejected
+
+ assert_true(XML_GetErrorCode(parser) == XML_ERROR_NONE);
+}
+
+void XMLCALL
+suspend_then_resume_character_handler(void *userData, const XML_Char *s,
+ int len) {
+ UNUSED_P(s);
+ UNUSED_P(len);
+ ResumeFromHandlerData *const data = (ResumeFromHandlerData *)userData;
+
+ data->callCount++;
+ if (data->callCount > 1) {
+ // Reached only if the guard under test is missing: XML_ResumeParser would
+ // then have driven the parser re-entrantly and called us again. Bail out
+ // so the test fails by assertion below rather than recursing without bound.
+ return;
+ }
+
+ // Put the parser into XML_SUSPENDED so that, without the guard,
+ // XML_ResumeParser would proceed into a re-entrant parse.
+ assert_true(XML_StopParser(data->parser, /*resumable=*/XML_TRUE)
+ == XML_STATUS_OK);
+
+ // Resuming the parser from inside a handler must be rejected.
+ assert_true(XML_ResumeParser(data->parser) == XML_STATUS_ERROR);
}
Index: lib/libexpat/tests/handlers.h
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/handlers.h,v
diff -u -p -r1.4 handlers.h
--- lib/libexpat/tests/handlers.h 3 Feb 2026 08:49:46 -0000 1.4
+++ lib/libexpat/tests/handlers.h 14 Aug 2026 17:31:12 -0000
@@ -19,6 +19,8 @@
Copyright (c) 2020 Tim Gates
Copyright (c) 2021 Donghee Na
Copyright (c) 2023 Sony Corporation / Snild Dolkow
+ Copyright (c) 2026 Berkay Eren Ürün
+ Copyright (c) 2026 Kartik Kenchi
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -39,6 +41,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#ifdef __cplusplus
@@ -88,6 +92,7 @@ typedef struct attrInfo {
typedef struct elementInfo {
const XML_Char *name;
int attr_count;
+ int default_attr_count;
const XML_Char *id_name;
AttrInfo *attributes;
} ElementInfo;
@@ -610,6 +615,19 @@ typedef struct {
extern void XMLCALL
accumulate_and_suspend_comment_handler(void *userData, const XML_Char *data);
+
+extern void XMLCALL forbidden_calls_character_handler(void *userData,
+ const XML_Char *s,
+ int len);
+
+typedef struct {
+ XML_Parser parser;
+ int callCount;
+} ResumeFromHandlerData;
+
+extern void XMLCALL suspend_then_resume_character_handler(void *userData,
+ const XML_Char *s,
+ int len);
#endif /* XML_HANDLERS_H */
Index: lib/libexpat/tests/memcheck.c
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/memcheck.c,v
diff -u -p -r1.6 memcheck.c
--- lib/libexpat/tests/memcheck.c 11 Feb 2024 00:56:28 -0000 1.6
+++ lib/libexpat/tests/memcheck.c 14 Aug 2026 17:31:12 -0000
@@ -9,6 +9,7 @@
Copyright (c) 2017 Rhodri James
Copyright (c) 2017-2023 Sebastian Pipping
Copyright (c) 2022 Sean McBride
+ Copyright (c) 2026 Matthew Fernandez
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -29,6 +30,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#include
@@ -55,8 +58,7 @@ static AllocationEntry *find_allocation(
/* Allocate some memory and keep track of it. */
void *
tracking_malloc(size_t size) {
- AllocationEntry *const entry
- = (AllocationEntry *)malloc(sizeof(AllocationEntry));
+ AllocationEntry *const entry = malloc(sizeof(AllocationEntry));
if (entry == NULL) {
printf("Allocator failure\n");
@@ -142,7 +144,7 @@ tracking_realloc(void *ptr, size_t size)
entry = find_allocation(ptr);
if (entry == NULL) {
printf("Attempting to realloc unallocated memory at %p\n", ptr);
- entry = (AllocationEntry *)malloc(sizeof(AllocationEntry));
+ entry = malloc(sizeof(AllocationEntry));
if (entry == NULL) {
printf("Reallocator failure\n");
return NULL;
Index: lib/libexpat/tests/memcheck.h
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/memcheck.h,v
diff -u -p -r1.4 memcheck.h
--- lib/libexpat/tests/memcheck.h 26 May 2021 19:14:32 -0000 1.4
+++ lib/libexpat/tests/memcheck.h 14 Aug 2026 17:31:12 -0000
@@ -29,6 +29,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#ifdef __cplusplus
Index: lib/libexpat/tests/minicheck.c
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/minicheck.c,v
diff -u -p -r1.7 minicheck.c
--- lib/libexpat/tests/minicheck.c 11 Feb 2024 00:56:28 -0000 1.7
+++ lib/libexpat/tests/minicheck.c 14 Aug 2026 17:31:12 -0000
@@ -16,6 +16,7 @@
Copyright (c) 2018 Marco Maggi
Copyright (c) 2019 David Loffredo
Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow
+ Copyright (c) 2026 Matthew Fernandez
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -36,6 +37,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#if defined(NDEBUG)
@@ -54,7 +57,7 @@
Suite *
suite_create(const char *name) {
- Suite *suite = (Suite *)calloc(1, sizeof(Suite));
+ Suite *suite = calloc(1, sizeof(Suite));
if (suite != NULL) {
suite->name = name;
}
@@ -63,7 +66,7 @@ suite_create(const char *name) {
TCase *
tcase_create(const char *name) {
- TCase *tc = (TCase *)calloc(1, sizeof(TCase));
+ TCase *tc = calloc(1, sizeof(TCase));
if (tc != NULL) {
tc->name = name;
}
@@ -94,8 +97,7 @@ tcase_add_test(TCase *tc, tcase_test_fun
if (tc->allocated == tc->ntests) {
int nalloc = tc->allocated + 100;
size_t new_size = sizeof(tcase_test_function) * nalloc;
- tcase_test_function *const new_tests
- = (tcase_test_function *)realloc(tc->tests, new_size);
+ tcase_test_function *const new_tests = realloc(tc->tests, new_size);
assert(new_tests != NULL);
tc->tests = new_tests;
tc->allocated = nalloc;
@@ -130,7 +132,7 @@ suite_free(Suite *suite) {
SRunner *
srunner_create(Suite *suite) {
- SRunner *const runner = (SRunner *)calloc(1, sizeof(SRunner));
+ SRunner *const runner = calloc(1, sizeof(SRunner));
if (runner != NULL) {
runner->suite = suite;
}
Index: lib/libexpat/tests/minicheck.h
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/minicheck.h,v
diff -u -p -r1.8 minicheck.h
--- lib/libexpat/tests/minicheck.h 17 Sep 2025 17:23:00 -0000 1.8
+++ lib/libexpat/tests/minicheck.h 14 Aug 2026 17:31:12 -0000
@@ -37,6 +37,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#ifdef __cplusplus
Index: lib/libexpat/tests/misc_tests.c
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/misc_tests.c,v
diff -u -p -r1.10 misc_tests.c
--- lib/libexpat/tests/misc_tests.c 18 Mar 2026 11:50:19 -0000 1.10
+++ lib/libexpat/tests/misc_tests.c 14 Aug 2026 17:31:12 -0000
@@ -20,6 +20,9 @@
Copyright (c) 2021 Donghee Na
Copyright (c) 2023 Sony Corporation / Snild Dolkow
Copyright (c) 2025 Berkay Eren Ürün
+ Copyright (c) 2026 Matthew Fernandez
+ Copyright (c) 2026 Kartik Kenchi
+ Copyright (c) 2026 Evgeny Kotkov
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -40,17 +43,19 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#if defined(NDEBUG)
# undef NDEBUG /* because test suite relies on assert(...) at the moment */
#endif
+#include "expat_config.h"
+
#include
#include
-#include "expat_config.h"
-
#include "expat.h"
#include "internal.h"
#include "minicheck.h"
@@ -298,7 +303,7 @@ START_TEST(test_misc_stop_during_end_han
parser = XML_ParserCreate(NULL);
XML_SetElementHandler(parser, start_element_issue_240, end_element_issue_240);
- mydata = (DataIssue240 *)malloc(sizeof(DataIssue240));
+ mydata = malloc(sizeof(DataIssue240));
assert_true(mydata != NULL);
mydata->parser = parser;
mydata->deep = 0;
@@ -320,7 +325,7 @@ START_TEST(test_misc_stop_during_end_han
parser = XML_ParserCreate(NULL);
XML_SetElementHandler(parser, start_element_issue_240, end_element_issue_240);
- mydata = (DataIssue240 *)malloc(sizeof(DataIssue240));
+ mydata = malloc(sizeof(DataIssue240));
assert_true(mydata != NULL);
mydata->parser = parser;
mydata->deep = 0;
@@ -801,6 +806,103 @@ START_TEST(test_misc_no_infinite_loop_is
}
END_TEST
+START_TEST(test_misc_calls_forbidden_from_handlers) {
+ const char *const doc = "Hello world!";
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ XML_UseParserAsHandlerArg(parser);
+ XML_SetCharacterDataHandler(parser, forbidden_calls_character_handler);
+
+ assert_true(XML_Parse(parser, doc, (int)strlen(doc), /*isFinal=*/XML_TRUE)
+ == XML_STATUS_OK);
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+START_TEST(test_misc_resume_parser_forbidden_from_handler) {
+ const char *const doc = "Hello world!";
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ ResumeFromHandlerData data = {parser, 0};
+ XML_SetUserData(parser, &data);
+ XML_SetCharacterDataHandler(parser, suspend_then_resume_character_handler);
+
+ // The handler suspends the parser, so the top-level parse reports suspension
+ // rather than completion. The handler also asserts that resuming from inside
+ // itself is rejected.
+ assert_true(XML_Parse(parser, doc, (int)strlen(doc), /*isFinal=*/XML_TRUE)
+ == XML_STATUS_SUSPENDED);
+ assert_true(data.callCount == 1);
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
+// General attack payload idea by Jason Kratzer of Mozilla
+START_TEST(test_misc_low_surrogate_mozilla_bug_2053153) {
+ const char doc_before[] = "<\0!\0D\0O\0C\0T\0Y\0P\0E\0 \0d\0 \0[\0\n\0"
+ " \0 \0<\0!\0E\0N\0T\0I\0T\0Y\0 \0e\0 \0'\0";
+ const char doc_after[] = "'\0>\0\n\0]\0>\0\n\0"
+ "<\0r\0 \0a\0=\0'\0&\0e\0;\0'\0/\0>\0\n\0";
+
+ for (size_t i = 1021; i <= 1025; i++) {
+ set_subtest("[%d]", (int)i);
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+
+ assert_true(_XML_Parse_SINGLE_BYTES(parser, doc_before,
+ (int)sizeof(doc_before) - 1,
+ /*isFinal=*/XML_FALSE));
+
+ for (size_t j = 0; j < i; j++) {
+ assert_true(
+ _XML_Parse_SINGLE_BYTES(parser, "a\\0", 2, /*isFinal=*/XML_FALSE));
+ }
+
+ // Thinking Python, this is:
+ // ''.join([f'\\x{e:02x}' for e in '😀'.encode('UTF-16-LE')])
+ assert_true(_XML_Parse_SINGLE_BYTES(parser, "\x3d\xd8\x00\xde", 4,
+ /*isFinal=*/XML_FALSE));
+
+ assert_true(_XML_Parse_SINGLE_BYTES(
+ parser, doc_after, (int)sizeof(doc_after) - 1, /*isFinal=*/XML_TRUE));
+
+ XML_ParserFree(parser);
+ }
+}
+END_TEST
+
+START_TEST(test_misc_input_2gb) {
+ XML_Parser parser;
+ const char *const doc = "";
+ unsigned long long offset = 0;
+ char buf[4096];
+
+ if (g_chunkSize != 0) {
+ return; // this test is slow, and doesn't use _XML_Parse_SINGLE_BYTES().
+ }
+
+ memset(buf, ' ', sizeof(buf));
+
+ parser = XML_ParserCreate(NULL);
+
+ assert_true(XML_Parse(parser, doc, (int)strlen(doc), XML_FALSE)
+ == XML_STATUS_OK);
+ offset += strlen(doc);
+
+ while (offset < 2ULL * 1024 * 1024 * 1024) {
+ assert_true(XML_Parse(parser, buf, sizeof(buf), XML_FALSE)
+ == XML_STATUS_OK);
+ offset += sizeof(buf);
+ }
+
+ assert_true(XML_Parse(parser, NULL, 0, XML_TRUE) == XML_STATUS_OK);
+
+ XML_ParserFree(parser);
+}
+END_TEST
+
void
make_miscellaneous_test_case(Suite *s) {
TCase *tc_misc = tcase_create("miscellaneous tests");
@@ -832,4 +934,8 @@ make_miscellaneous_test_case(Suite *s) {
tcase_add_test(tc_misc, test_misc_sync_entity_tolerated);
tcase_add_test(tc_misc, test_misc_async_entity_rejected);
tcase_add_test(tc_misc, test_misc_no_infinite_loop_issue_1161);
+ tcase_add_test(tc_misc, test_misc_calls_forbidden_from_handlers);
+ tcase_add_test(tc_misc, test_misc_resume_parser_forbidden_from_handler);
+ tcase_add_test(tc_misc, test_misc_input_2gb);
+ tcase_add_test(tc_misc, test_misc_low_surrogate_mozilla_bug_2053153);
}
Index: lib/libexpat/tests/misc_tests.h
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/misc_tests.h,v
diff -u -p -r1.1 misc_tests.h
--- lib/libexpat/tests/misc_tests.h 11 Feb 2024 00:56:28 -0000 1.1
+++ lib/libexpat/tests/misc_tests.h 14 Aug 2026 17:31:12 -0000
@@ -38,6 +38,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#ifdef __cplusplus
Index: lib/libexpat/tests/ns_tests.c
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/ns_tests.c,v
diff -u -p -r1.1 ns_tests.c
--- lib/libexpat/tests/ns_tests.c 11 Feb 2024 00:56:28 -0000 1.1
+++ lib/libexpat/tests/ns_tests.c 14 Aug 2026 17:31:12 -0000
@@ -39,6 +39,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#include "expat_config.h"
Index: lib/libexpat/tests/ns_tests.h
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/ns_tests.h,v
diff -u -p -r1.1 ns_tests.h
--- lib/libexpat/tests/ns_tests.h 11 Feb 2024 00:56:28 -0000 1.1
+++ lib/libexpat/tests/ns_tests.h 14 Aug 2026 17:31:12 -0000
@@ -38,6 +38,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#ifdef __cplusplus
Index: lib/libexpat/tests/nsalloc_tests.c
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/nsalloc_tests.c,v
diff -u -p -r1.3 nsalloc_tests.c
--- lib/libexpat/tests/nsalloc_tests.c 18 Mar 2026 11:50:19 -0000 1.3
+++ lib/libexpat/tests/nsalloc_tests.c 14 Aug 2026 17:31:12 -0000
@@ -10,7 +10,7 @@
Copyright (c) 2003 Greg Stein
Copyright (c) 2005-2007 Steven Solie
Copyright (c) 2005-2012 Karl Waclawek
- Copyright (c) 2016-2025 Sebastian Pipping
+ Copyright (c) 2016-2026 Sebastian Pipping
Copyright (c) 2017-2022 Rhodri James
Copyright (c) 2017 Joe Orton
Copyright (c) 2017 José Gutiérrez de la Concha
@@ -18,6 +18,7 @@
Copyright (c) 2019 David Loffredo
Copyright (c) 2020 Tim Gates
Copyright (c) 2021 Donghee Na
+ Copyright (c) 2026 Christian Ng
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -38,6 +39,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#if defined(NDEBUG)
@@ -1507,7 +1510,7 @@ END_TEST
/* Verify that retry after OOM in setContext() does not crash.
*/
-START_TEST(test_nsalloc_setContext_zombie) {
+START_TEST(test_nsalloc_set_context_zombie) {
const char *text = "Hello";
unsigned int i;
const unsigned int max_alloc_count = 30;
@@ -1519,7 +1522,9 @@ START_TEST(test_nsalloc_setContext_zombi
break;
/* Retry on the same parser — must not crash */
g_allocation_count = ALLOC_ALWAYS_SUCCEED;
- XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE);
+ const enum XML_Status status
+ = XML_Parse(g_parser, text, (int)strlen(text), XML_TRUE);
+ (void)status;
nsalloc_teardown();
nsalloc_setup();
@@ -1565,5 +1570,5 @@ make_nsalloc_test_case(Suite *s) {
tcase_add_test__if_xml_ge(tc_nsalloc, test_nsalloc_long_default_in_ext);
tcase_add_test(tc_nsalloc, test_nsalloc_long_systemid_in_ext);
tcase_add_test(tc_nsalloc, test_nsalloc_prefixed_element);
- tcase_add_test(tc_nsalloc, test_nsalloc_setContext_zombie);
+ tcase_add_test(tc_nsalloc, test_nsalloc_set_context_zombie);
}
Index: lib/libexpat/tests/nsalloc_tests.h
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/nsalloc_tests.h,v
diff -u -p -r1.1 nsalloc_tests.h
--- lib/libexpat/tests/nsalloc_tests.h 11 Feb 2024 00:56:28 -0000 1.1
+++ lib/libexpat/tests/nsalloc_tests.h 14 Aug 2026 17:31:12 -0000
@@ -38,6 +38,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#ifdef __cplusplus
Index: lib/libexpat/tests/runtests.c
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/runtests.c,v
diff -u -p -r1.20 runtests.c
--- lib/libexpat/tests/runtests.c 1 Apr 2024 13:46:06 -0000 1.20
+++ lib/libexpat/tests/runtests.c 14 Aug 2026 17:31:12 -0000
@@ -40,6 +40,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#include "expat_config.h"
Index: lib/libexpat/tests/structdata.c
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/structdata.c,v
diff -u -p -r1.5 structdata.c
--- lib/libexpat/tests/structdata.c 11 Feb 2024 00:56:28 -0000 1.5
+++ lib/libexpat/tests/structdata.c 14 Aug 2026 17:31:12 -0000
@@ -9,6 +9,7 @@
Copyright (c) 2017 Rhodri James
Copyright (c) 2017-2023 Sebastian Pipping
Copyright (c) 2022 Sean McBride
+ Copyright (c) 2026 Matthew Fernandez
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -29,6 +30,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#if defined(NDEBUG)
@@ -61,7 +64,7 @@
static XML_Char *
xmlstrdup(const XML_Char *s) {
size_t byte_count = (xcstrlen(s) + 1) * sizeof(XML_Char);
- XML_Char *const dup = (XML_Char *)malloc(byte_count);
+ XML_Char *const dup = malloc(byte_count);
assert(dup != NULL);
memcpy(dup, s, byte_count);
@@ -87,8 +90,8 @@ StructData_AddItem(StructData *storage,
StructDataEntry *new_entries;
storage->max_count += STRUCT_EXTENSION_COUNT;
- new_entries = (StructDataEntry *)realloc(
- storage->entries, storage->max_count * sizeof(StructDataEntry));
+ new_entries = realloc(storage->entries,
+ storage->max_count * sizeof(StructDataEntry));
assert(new_entries != NULL);
storage->entries = new_entries;
}
Index: lib/libexpat/tests/structdata.h
===================================================================
RCS file: /cvs/src/lib/libexpat/tests/structdata.h,v
diff -u -p -r1.3 structdata.h
--- lib/libexpat/tests/structdata.h 26 May 2021 19:14:32 -0000 1.3
+++ lib/libexpat/tests/structdata.h 14 Aug 2026 17:31:12 -0000
@@ -28,6 +28,8 @@
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+ SPDX-License-Identifier: MIT
*/
#ifdef __cplusplus