summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2024-04-30 21:56:46 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2024-04-30 21:56:46 +0000
commit45c0504668cfa9fa4c22ff3fc3730e9b01d41a86 (patch)
tree55d10d69c78c75027876b9f10e1ad0e0eb5642a2
parent65e724d3705cbbcc8b938a479d1a598b720e7b12 (diff)
parent37e7c700593f100552717b32958e9270e64beec6 (diff)
downloadexpat-build-tools-release.tar.gz
Merge "Snap for 11784721 from b5bcb5ba1106e82e6008c36843657ed3f259eb2f to build-tools-release" into build-tools-releasebuild-tools-release
-rw-r--r--.github/workflows/coverage.yml2
-rw-r--r--.github/workflows/fuzzing.yml2
l---------LICENSE1
-rw-r--r--METADATA8
l---------NOTICE1
-rw-r--r--expat/CMake.README12
-rw-r--r--expat/CMakeLists.txt6
-rw-r--r--expat/Changes82
-rw-r--r--expat/README.md2
-rwxr-xr-xexpat/apply-clang-tidy.sh1
-rw-r--r--expat/configure.ac27
-rw-r--r--expat/doc/Makefile.am20
-rw-r--r--expat/doc/reference.html7
-rw-r--r--expat/doc/xmlwf.xml2
-rw-r--r--expat/examples/.gitignore1
-rw-r--r--expat/lib/Makefile.am19
-rw-r--r--expat/lib/expat.h5
-rw-r--r--expat/lib/internal.h17
-rw-r--r--expat/lib/xmlparse.c30
-rw-r--r--expat/tests/Makefile.am8
-rw-r--r--expat/tests/acc_tests.c59
-rw-r--r--expat/tests/basic_tests.c151
-rw-r--r--expat/tests/misc_tests.c2
-rw-r--r--expat/win32/expat.iss2
-rw-r--r--expat_config.h6
25 files changed, 331 insertions, 142 deletions
diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml
index 0f783a80..0d0cfd4e 100644
--- a/.github/workflows/coverage.yml
+++ b/.github/workflows/coverage.yml
@@ -84,7 +84,7 @@ jobs:
exec ./.ci.sh
- name: Store coverage .info and HTML report
- uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
+ uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: coverage
path: expat/coverage__*/
diff --git a/.github/workflows/fuzzing.yml b/.github/workflows/fuzzing.yml
index d6f67dd0..68136006 100644
--- a/.github/workflows/fuzzing.yml
+++ b/.github/workflows/fuzzing.yml
@@ -120,7 +120,7 @@ jobs:
- name: Store crashing test units
if: ${{ failure() }}
- uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
+ uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: expat_fuzzing_trouble_${{ github.sha }}
path: expat/build/*-????????????????????????????????????????
diff --git a/LICENSE b/LICENSE
deleted file mode 120000
index d24842f3..00000000
--- a/LICENSE
+++ /dev/null
@@ -1 +0,0 @@
-COPYING \ No newline at end of file
diff --git a/METADATA b/METADATA
index 3068d134..4d1f8ab0 100644
--- a/METADATA
+++ b/METADATA
@@ -3,7 +3,7 @@
# DEPENDING ON IT IN YOUR PROJECT.
# This project was upgraded with external_updater.
-# Usage: tools/external_updater/updater.sh update external/expat
+# Usage: tools/external_updater/updater.sh update external/<absolute path to project>
# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
name: "expat"
@@ -16,13 +16,13 @@ third_party {
}
last_upgrade_date {
year: 2024
- month: 2
- day: 8
+ month: 4
+ day: 26
}
homepage: "https://github.com/libexpat/libexpat/"
identifier {
type: "Git"
value: "https://github.com/libexpat/libexpat/"
- version: "R_2_6_0"
+ version: "R_2_6_2"
}
}
diff --git a/NOTICE b/NOTICE
deleted file mode 120000
index d24842f3..00000000
--- a/NOTICE
+++ /dev/null
@@ -1 +0,0 @@
-COPYING \ No newline at end of file
diff --git a/expat/CMake.README b/expat/CMake.README
index f712dd7d..5d5f43e8 100644
--- a/expat/CMake.README
+++ b/expat/CMake.README
@@ -3,25 +3,25 @@
The cmake based buildsystem for expat works on Windows (cygwin, mingw, Visual
Studio) and should work on all other platform cmake supports.
-Assuming ~/expat-2.6.0 is the source directory of expat, add a subdirectory
+Assuming ~/expat-2.6.2 is the source directory of expat, add a subdirectory
build and change into that directory:
-~/expat-2.6.0$ mkdir build && cd build
-~/expat-2.6.0/build$
+~/expat-2.6.2$ mkdir build && cd build
+~/expat-2.6.2/build$
From that directory, call cmake first, then call make, make test and
make install in the usual way:
-~/expat-2.6.0/build$ cmake ..
+~/expat-2.6.2/build$ cmake ..
-- The C compiler identification is GNU
-- The CXX compiler identification is GNU
....
-- Configuring done
-- Generating done
--- Build files have been written to: /home/patrick/expat-2.6.0/build
+-- Build files have been written to: /home/patrick/expat-2.6.2/build
If you want to specify the install location for your files, append
-DCMAKE_INSTALL_PREFIX=/your/install/path to the cmake call.
-~/expat-2.6.0/build$ make && make test && make install
+~/expat-2.6.2/build$ make && make test && make install
Scanning dependencies of target expat
[ 5%] Building C object CMakeFiles/expat.dir/lib/xmlparse.c.o
[ 11%] Building C object CMakeFiles/expat.dir/lib/xmlrole.c.o
diff --git a/expat/CMakeLists.txt b/expat/CMakeLists.txt
index dd793188..ff081550 100644
--- a/expat/CMakeLists.txt
+++ b/expat/CMakeLists.txt
@@ -38,7 +38,7 @@ cmake_minimum_required(VERSION 3.5.0)
project(expat
VERSION
- 2.6.0
+ 2.6.2
LANGUAGES
C
)
@@ -466,7 +466,7 @@ foreach(build_type_upper
endforeach()
set(LIBCURRENT 10) # sync
-set(LIBREVISION 0) # with
+set(LIBREVISION 2) # with
set(LIBAGE 9) # configure.ac!
math(EXPR LIBCURRENT_MINUS_AGE "${LIBCURRENT} - ${LIBAGE}")
@@ -676,6 +676,8 @@ if(EXPAT_BUILD_TESTS)
)
foreach(_target ${_EXPAT_TEST_TARGETS})
+ target_compile_definitions(${_target} PRIVATE -DXML_TESTING)
+
set_property(TARGET ${_target} PROPERTY RUNTIME_OUTPUT_DIRECTORY tests)
expat_add_test(${_target} $<TARGET_FILE:${_target}>)
diff --git a/expat/Changes b/expat/Changes
index a7d4caf9..52b366d5 100644
--- a/expat/Changes
+++ b/expat/Changes
@@ -1,6 +1,82 @@
-NOTE: We are looking for help with a few things:
- https://github.com/libexpat/libexpat/labels/help%20wanted
- If you can help, please get in touch. Thanks!
+ __ __ _
+ ___\ \/ /_ __ __ _| |_
+ / _ \\ /| '_ \ / _` | __|
+ | __// \| |_) | (_| | |_
+ \___/_/\_\ .__/ \__,_|\__|
+ |_| XML parser
+
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+!! <blink>Expat is UNDERSTAFFED and WITHOUT FUNDING.</blink> !!
+!! ~~~~~~~~~~~~ !!
+!! The following topics need *additional skilled C developers* to progress !!
+!! in a timely manner or at all (loosely ordered by descending priority): !!
+!! !!
+!! - <blink>fixing a complex non-public security issue</blink>, !!
+!! - 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), !!
+!! - smart ideas on fixing the Autotools CMake files generation issue !!
+!! without breaking CI (needs discussion before pull requests), !!
+!! - the Windows binaries topic (needs requirements engineering first), !!
+!! - pushing migration from `int` to `size_t` further !!
+!! including edge-cases test coverage (needs discussion before anything). !!
+!! !!
+!! 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, 2024-03-09 !!
+!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+
+Release 2.6.2 Wed March 13 2024
+ Security fixes:
+ #839 #842 CVE-2024-28757 -- Prevent billion laughs attacks with
+ isolated use of external parsers. Please see the commit
+ message of commit 1d50b80cf31de87750103656f6eb693746854aa8
+ for details.
+
+ Bug fixes:
+ #839 #841 Reject direct parameter entity recursion
+ and avoid the related undefined behavior
+
+ Other changes:
+ #847 Autotools: Fix build for DOCBOOK_TO_MAN containing spaces
+ #837 Add missing #821 and #824 to 2.6.1 change log
+ #838 #843 Version info bumped from 10:1:9 (libexpat*.so.1.9.1)
+ to 10:2:9 (libexpat*.so.1.9.2); see https://verbump.de/
+ for what these numbers do
+
+ Special thanks to:
+ Philippe Antoine
+ Tomas Korbar
+ and
+ Clang UndefinedBehaviorSanitizer
+ OSS-Fuzz / ClusterFuzz
+
+Release 2.6.1 Thu February 29 2024
+ Bug fixes:
+ #817 Make tests independent of CPU speed, and thus more robust
+ #828 #836 Expose billion laughs API with XML_DTD defined and
+ XML_GE undefined, regression from 2.6.0
+
+ Other changes:
+ #829 Hide test-only code behind new internal macro
+ #833 Autotools: Reject expat_config.h.in defining SIZEOF_VOID_P
+ #821 #824 Autotools: Fix "make clean" for case:
+ ./configure --without-docbook && make clean all
+ #819 Address compiler warnings
+ #832 #834 Version info bumped from 10:0:9 (libexpat*.so.1.9.0)
+ to 10:1:9 (libexpat*.so.1.9.1); see https://verbump.de/
+ for what these numbers do
+
+ Infrastructure:
+ #818 CI: Adapt to breaking changes in clang-format
+
+ Special thanks to:
+ David Hall
+ Snild Dolkow
Release 2.6.0 Tue February 6 2024
Security fixes:
diff --git a/expat/README.md b/expat/README.md
index 43c4f4f3..3c20adbe 100644
--- a/expat/README.md
+++ b/expat/README.md
@@ -5,7 +5,7 @@
[![Downloads GitHub](https://img.shields.io/github/downloads/libexpat/libexpat/total?label=Downloads%20GitHub)](https://github.com/libexpat/libexpat/releases)
-# Expat, Release 2.6.0
+# Expat, Release 2.6.2
This is Expat, a C99 library for parsing
[XML 1.0 Fourth Edition](https://www.w3.org/TR/2006/REC-xml-20060816/), started by
diff --git a/expat/apply-clang-tidy.sh b/expat/apply-clang-tidy.sh
index 2e520bd0..17015f6c 100755
--- a/expat/apply-clang-tidy.sh
+++ b/expat/apply-clang-tidy.sh
@@ -68,6 +68,7 @@ flags=(
-DXML_DTD
-DXML_GE
-DXML_NS
+ -DXML_TESTING
)
if [[ $# -gt 0 ]]; then
diff --git a/expat/configure.ac b/expat/configure.ac
index a5d1ff93..04415e36 100644
--- a/expat/configure.ac
+++ b/expat/configure.ac
@@ -83,7 +83,7 @@ dnl If the API changes incompatibly set LIBAGE back to 0
dnl
LIBCURRENT=10 # sync
-LIBREVISION=0 # with
+LIBREVISION=2 # with
LIBAGE=9 # CMakeLists.txt!
AC_CONFIG_HEADERS([expat_config.h])
@@ -357,11 +357,22 @@ AS_IF([test "x${DOCBOOK_TO_MAN}" != x -a "x$with_docbook" != xno],
page for xmlwf.])])])
dnl This will make sure that a release tarball shipping a pre-rendered xmlwf man page will
-dnl get it installed, independent of whether some flavor of docbook2man is available.
+dnl get it installed, when no working flavor of docbook2man is available (or wanted).
dnl This relies on file xmlwf.1 being at least as recent as its source file xmlwf.xml.
AS_IF([test -f "${srcdir}"/doc/xmlwf.1],
- [AM_CONDITIONAL(WITH_DOCBOOK, [true])],
- [AM_CONDITIONAL(WITH_DOCBOOK, [test "x${DOCBOOK_TO_MAN}" != x])])
+ [AM_CONDITIONAL(WITH_MANPAGE, [true])
+ AS_IF([test "x$with_docbook" = xno -o "x${DOCBOOK_TO_MAN}" = x],
+ [AM_CONDITIONAL(WITH_PREBUILT_MANPAGE, [true])
+ AM_CONDITIONAL(WITH_DISTRIBUTABLE_MANPAGE, [false])],
+ [AM_CONDITIONAL(WITH_PREBUILT_MANPAGE, [false])
+ AM_CONDITIONAL(WITH_DISTRIBUTABLE_MANPAGE, [true])])
+ ],
+ [AS_IF([test "x$with_docbook" != xno -a "x${DOCBOOK_TO_MAN}" != x],
+ [AM_CONDITIONAL(WITH_MANPAGE, [true])
+ AM_CONDITIONAL(WITH_DISTRIBUTABLE_MANPAGE, [true])],
+ [AM_CONDITIONAL(WITH_MANPAGE, [false])
+ AM_CONDITIONAL(WITH_DISTRIBUTABLE_MANPAGE, [false])])
+ AM_CONDITIONAL(WITH_PREBUILT_MANPAGE, [false])])
dnl Configure CMake file templates
dnl NOTE: The *_TRUE variables read here are Automake conditionals
@@ -407,6 +418,14 @@ AC_SUBST([SO_MINOR])
AC_SUBST([SO_PATCH])
AC_SUBST([ac_cv_sizeof_void_p])
+dnl Protect against generating an expat_config.h that would break multilib
+AS_IF([grep -F -q SIZEOF_VOID_P "${srcdir}"/expat_config.h.in],
+ [AC_MSG_ERROR(
+ [Plain autoreconf/autoheader does not cut it,
+ please use ./buildconf.sh or imitate its effect
+ through other means, so that file expat_config.h.in
+ no longer defines macro SIZEOF_VOID_P, as that would
+ break multilib support. Thank you.])])
dnl write the Automake flags we set
AC_SUBST([AM_CPPFLAGS])
diff --git a/expat/doc/Makefile.am b/expat/doc/Makefile.am
index c3a3ce59..9d12923d 100644
--- a/expat/doc/Makefile.am
+++ b/expat/doc/Makefile.am
@@ -6,7 +6,7 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2017-2022 Sebastian Pipping <sebastian@pipping.org>
+# Copyright (c) 2017-2024 Sebastian Pipping <sebastian@pipping.org>
# Copyright (c) 2017 Stephen Groat <stephen@groat.us>
# Copyright (c) 2017 Joe Orton <jorton@redhat.com>
# Licensed under the MIT license:
@@ -32,26 +32,24 @@
.PHONY: dist-hook # not inside conditional to avoid automake warning
-if WITH_DOCBOOK
+if WITH_MANPAGE
dist_man_MANS = xmlwf.1
xmlwf.1: xmlwf.xml
-rm -f $@
- $(DOCBOOK_TO_MAN) $<
+ test "x$(DOCBOOK_TO_MAN)" != x && $(DOCBOOK_TO_MAN) $<
test -f $@ || mv XMLWF.1 $@
-else
+endif
+
+if !WITH_DISTRIBUTABLE_MANPAGE
dist-hook:
@echo 'ERROR: Configure with --with-docbook for "make dist".' 1>&2
@false
endif
-# https://www.gnu.org/software/automake/manual/automake.html#What-Gets-Cleaned
-.PHONY: clean-local
-clean-local: clean-local-check
-
-.PHONY: clean-local-check
-clean-local-check:
- $(RM) xmlwf.1
+if !WITH_PREBUILT_MANPAGE
+CLEANFILES = xmlwf.1
+endif
EXTRA_DIST = \
ok.min.css \
diff --git a/expat/doc/reference.html b/expat/doc/reference.html
index 898f03a3..5614dc34 100644
--- a/expat/doc/reference.html
+++ b/expat/doc/reference.html
@@ -52,7 +52,7 @@
<div>
<h1>
The Expat XML Parser
- <small>Release 2.6.0</small>
+ <small>Release 2.6.2</small>
</h1>
</div>
<div class="content">
@@ -356,10 +356,7 @@ library and header would get installed in
<h3>Configuring Expat Using the Pre-Processor</h3>
<p>Expat's feature set can be configured using a small number of
-pre-processor definitions. The definition of this symbols does not
-affect the set of entry points for Expat, only the behavior of the API
-and the definition of character types in the case of
-<code>XML_UNICODE_WCHAR_T</code>. The symbols are:</p>
+pre-processor definitions. The symbols are:</p>
<dl class="cpp-symbols">
<dt><a name="XML_GE">XML_GE</a></dt>
diff --git a/expat/doc/xmlwf.xml b/expat/doc/xmlwf.xml
index 2b3f1ccd..fd77f844 100644
--- a/expat/doc/xmlwf.xml
+++ b/expat/doc/xmlwf.xml
@@ -21,7 +21,7 @@
"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [
<!ENTITY dhfirstname "<firstname>Scott</firstname>">
<!ENTITY dhsurname "<surname>Bronson</surname>">
- <!ENTITY dhdate "<date>February 6, 2024</date>">
+ <!ENTITY dhdate "<date>March 13, 2024</date>">
<!-- Please adjust this^^ date whenever cutting a new release. -->
<!ENTITY dhsection "<manvolnum>1</manvolnum>">
<!ENTITY dhemail "<email>bronson@rinspin.com</email>">
diff --git a/expat/examples/.gitignore b/expat/examples/.gitignore
index 88a46969..ef5b8d59 100644
--- a/expat/examples/.gitignore
+++ b/expat/examples/.gitignore
@@ -1,6 +1,7 @@
Makefile
elements
elements.plg
+element_declarations
outline
outline.plg
Debug
diff --git a/expat/lib/Makefile.am b/expat/lib/Makefile.am
index 0e0185b5..1958f322 100644
--- a/expat/lib/Makefile.am
+++ b/expat/lib/Makefile.am
@@ -6,7 +6,7 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2017-2022 Sebastian Pipping <sebastian@pipping.org>
+# Copyright (c) 2017-2024 Sebastian Pipping <sebastian@pipping.org>
# Copyright (c) 2017 Tomasz Kłoczko <kloczek@fedoraproject.org>
# Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
# Licensed under the MIT license:
@@ -36,7 +36,9 @@ include_HEADERS = \
expat_external.h
lib_LTLIBRARIES = libexpat.la
-noinst_LTLIBRARIES = libexpatinternal.la
+if WITH_TESTS
+noinst_LTLIBRARIES = libtestpat.la
+endif
libexpat_la_LDFLAGS = \
@AM_LDFLAGS@ \
@@ -44,17 +46,16 @@ libexpat_la_LDFLAGS = \
-no-undefined \
-version-info @LIBCURRENT@:@LIBREVISION@:@LIBAGE@
-libexpat_la_SOURCES =
-
-# This layer of indirection allows
-# the test suite to access internal symbols
-# despite compiling with -fvisibility=hidden
-libexpatinternal_la_SOURCES = \
+libexpat_la_SOURCES = \
xmlparse.c \
xmltok.c \
xmlrole.c
-libexpat_la_LIBADD = libexpatinternal.la
+if WITH_TESTS
+libtestpat_la_CPPFLAGS = -DXML_TESTING
+
+libtestpat_la_SOURCES = $(libexpat_la_SOURCES)
+endif
doc_DATA = \
../AUTHORS \
diff --git a/expat/lib/expat.h b/expat/lib/expat.h
index 95464b0d..c2770be3 100644
--- a/expat/lib/expat.h
+++ b/expat/lib/expat.h
@@ -18,6 +18,7 @@
Copyright (c) 2022 Thijs Schreijer <thijs@thijsschreijer.nl>
Copyright (c) 2023 Hanno Böck <hanno@gentoo.org>
Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
+ Copyright (c) 2024 Taichi Haradaguchi <20001722@ymail.ne.jp>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -1042,7 +1043,7 @@ typedef struct {
XMLPARSEAPI(const XML_Feature *)
XML_GetFeatureList(void);
-#if XML_GE == 1
+#if defined(XML_DTD) || (defined(XML_GE) && XML_GE == 1)
/* Added in Expat 2.4.0 for XML_DTD defined and
* added in Expat 2.6.0 for XML_GE == 1. */
XMLPARSEAPI(XML_Bool)
@@ -1065,7 +1066,7 @@ XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled);
*/
#define XML_MAJOR_VERSION 2
#define XML_MINOR_VERSION 6
-#define XML_MICRO_VERSION 0
+#define XML_MICRO_VERSION 2
#ifdef __cplusplus
}
diff --git a/expat/lib/internal.h b/expat/lib/internal.h
index cce71e4c..167ec368 100644
--- a/expat/lib/internal.h
+++ b/expat/lib/internal.h
@@ -28,10 +28,11 @@
Copyright (c) 2002-2003 Fred L. Drake, Jr. <fdrake@users.sourceforge.net>
Copyright (c) 2002-2006 Karl Waclawek <karl@waclawek.net>
Copyright (c) 2003 Greg Stein <gstein@users.sourceforge.net>
- Copyright (c) 2016-2023 Sebastian Pipping <sebastian@pipping.org>
+ Copyright (c) 2016-2024 Sebastian Pipping <sebastian@pipping.org>
Copyright (c) 2018 Yury Gribov <tetra2005@gmail.com>
Copyright (c) 2019 David Loffredo <loffredo@steptools.com>
- Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
+ Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com>
+ Copyright (c) 2024 Taichi Haradaguchi <20001722@ymail.ne.jp>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -155,14 +156,20 @@ extern "C" {
void _INTERNAL_trim_to_complete_utf8_characters(const char *from,
const char **fromLimRef);
-#if XML_GE == 1
+#if defined(XML_GE) && XML_GE == 1
unsigned long long testingAccountingGetCountBytesDirect(XML_Parser parser);
unsigned long long testingAccountingGetCountBytesIndirect(XML_Parser parser);
const char *unsignedCharToPrintable(unsigned char c);
#endif
-extern XML_Bool g_reparseDeferralEnabledDefault; // written ONLY in runtests.c
-extern unsigned int g_parseAttempts; // used for testing only
+extern
+#if ! defined(XML_TESTING)
+ const
+#endif
+ XML_Bool g_reparseDeferralEnabledDefault; // written ONLY in runtests.c
+#if defined(XML_TESTING)
+extern unsigned int g_bytesScanned; // used for testing only
+#endif
#ifdef __cplusplus
}
diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
index aaf0fa9c..2951fec7 100644
--- a/expat/lib/xmlparse.c
+++ b/expat/lib/xmlparse.c
@@ -1,4 +1,4 @@
-/* 628e24d4966bedbd4800f6ed128d06d29703765b4bce12d3b7f099f90f842fc9 (2.6.0+)
+/* 2a14271ad4d35e82bde8ba210b4edb7998794bcbae54deab114046a300f9639a (2.6.2+)
__ __ _
___\ \/ /_ __ __ _| |_
/ _ \\ /| '_ \ / _` | __|
@@ -38,7 +38,7 @@
Copyright (c) 2022 Jann Horn <jannh@google.com>
Copyright (c) 2022 Sean McBride <sean@rogue-research.com>
Copyright (c) 2023 Owain Davies <owaind@bath.edu>
- Copyright (c) 2023 Sony Corporation / Snild Dolkow <snild@sony.com>
+ Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow <snild@sony.com>
Licensed under the MIT license:
Permission is hereby granted, free of charge, to any person obtaining
@@ -210,7 +210,7 @@ typedef char ICHAR;
#endif
/* Round up n to be a multiple of sz, where sz is a power of 2. */
-#define ROUND_UP(n, sz) (((n) + ((sz)-1)) & ~((sz)-1))
+#define ROUND_UP(n, sz) (((n) + ((sz) - 1)) & ~((sz) - 1))
/* Do safe (NULL-aware) pointer arithmetic */
#define EXPAT_SAFE_PTR_DIFF(p, q) (((p) && (q)) ? ((p) - (q)) : 0)
@@ -248,7 +248,7 @@ static void copy_salt_to_sipkey(XML_Parser parser, struct sipkey *key);
it odd, since odd numbers are always relative prime to a power of 2.
*/
#define SECOND_HASH(hash, mask, power) \
- ((((hash) & ~(mask)) >> ((power)-1)) & ((mask) >> 2))
+ ((((hash) & ~(mask)) >> ((power) - 1)) & ((mask) >> 2))
#define PROBE_STEP(hash, mask, power) \
((unsigned char)((SECOND_HASH(hash, mask, power)) | 1))
@@ -629,8 +629,14 @@ static unsigned long getDebugLevel(const char *variableName,
? 0 \
: ((*((pool)->ptr)++ = c), 1))
-XML_Bool g_reparseDeferralEnabledDefault = XML_TRUE; // write ONLY in runtests.c
-unsigned int g_parseAttempts = 0; // used for testing only
+#if ! defined(XML_TESTING)
+const
+#endif
+ XML_Bool g_reparseDeferralEnabledDefault
+ = XML_TRUE; // write ONLY in runtests.c
+#if defined(XML_TESTING)
+unsigned int g_bytesScanned = 0; // used for testing only
+#endif
struct XML_ParserStruct {
/* The first member must be m_userData so that the XML_GetUserData
@@ -1017,7 +1023,9 @@ callProcessor(XML_Parser parser, const char *start, const char *end,
return XML_ERROR_NONE;
}
}
- g_parseAttempts += 1;
+#if defined(XML_TESTING)
+ g_bytesScanned += (unsigned)have_now;
+#endif
const enum XML_Error ret = parser->m_processor(parser, start, end, endPtr);
if (ret == XML_ERROR_NONE) {
// if we consumed nothing, remember what we had on this parse attempt.
@@ -6232,7 +6240,7 @@ storeEntityValue(XML_Parser parser, const ENCODING *enc,
dtd->keepProcessing = dtd->standalone;
goto endEntityValue;
}
- if (entity->open) {
+ if (entity->open || (entity == parser->m_declEntity)) {
if (enc == parser->m_encoding)
parser->m_eventPtr = entityTextPtr;
result = XML_ERROR_RECURSIVE_ENTITY_REF;
@@ -7779,6 +7787,8 @@ copyString(const XML_Char *s, const XML_Memory_Handling_Suite *memsuite) {
static float
accountingGetCurrentAmplification(XML_Parser rootParser) {
+ // 1.........1.........12 => 22
+ const size_t lenOfShortestInclude = sizeof("<!ENTITY a SYSTEM 'b'>") - 1;
const XmlBigCount countBytesOutput
= rootParser->m_accounting.countBytesDirect
+ rootParser->m_accounting.countBytesIndirect;
@@ -7786,7 +7796,9 @@ accountingGetCurrentAmplification(XML_Parser rootParser) {
= rootParser->m_accounting.countBytesDirect
? (countBytesOutput
/ (float)(rootParser->m_accounting.countBytesDirect))
- : 1.0f;
+ : ((lenOfShortestInclude
+ + rootParser->m_accounting.countBytesIndirect)
+ / (float)lenOfShortestInclude);
assert(! rootParser->m_parentParser);
return amplificationFactor;
}
diff --git a/expat/tests/Makefile.am b/expat/tests/Makefile.am
index f949fe7f..c38c4309 100644
--- a/expat/tests/Makefile.am
+++ b/expat/tests/Makefile.am
@@ -6,7 +6,7 @@
# \___/_/\_\ .__/ \__,_|\__|
# |_| XML parser
#
-# Copyright (c) 2017-2023 Sebastian Pipping <sebastian@pipping.org>
+# Copyright (c) 2017-2024 Sebastian Pipping <sebastian@pipping.org>
# Copyright (c) 2017-2022 Rhodri James <rhodri@wildebeest.org.uk>
# Copyright (c) 2020 Jeffrey Walton <noloader@gmail.com>
# Licensed under the MIT license:
@@ -32,7 +32,7 @@
SUBDIRS = . benchmark
-AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(srcdir)/../lib
+AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(srcdir)/../lib -DXML_TESTING
check_PROGRAMS = runtests runtests_cxx
TESTS = runtests runtests_cxx
@@ -72,8 +72,8 @@ runtests_cxx_SOURCES = \
runtests_cxx.cpp \
structdata_cxx.cpp
-runtests_LDADD = ../lib/libexpatinternal.la
-runtests_cxx_LDADD = ../lib/libexpatinternal.la
+runtests_LDADD = ../lib/libtestpat.la
+runtests_cxx_LDADD = ../lib/libtestpat.la
runtests_LDFLAGS = @AM_LDFLAGS@ @LIBM@
runtests_cxx_LDFLAGS = @AM_LDFLAGS@ @LIBM@
diff --git a/expat/tests/acc_tests.c b/expat/tests/acc_tests.c
index e1c4b7f7..f193aa58 100644
--- a/expat/tests/acc_tests.c
+++ b/expat/tests/acc_tests.c
@@ -378,6 +378,63 @@ START_TEST(test_helper_unsigned_char_to_printable) {
fail("unsignedCharToPrintable result mistaken");
}
END_TEST
+
+START_TEST(test_amplification_isolated_external_parser) {
+ // NOTE: Length 44 is precisely twice the length of "<!ENTITY a SYSTEM 'b'>"
+ // (22) that is used in function accountingGetCurrentAmplification in
+ // xmlparse.c.
+ // 1.........1.........1.........1.........1..4 => 44
+ const char doc[] = "<!ENTITY % p1 '123456789_123456789_1234567'>";
+ const int docLen = (int)sizeof(doc) - 1;
+ const float maximumToleratedAmplification = 2.0f;
+
+ struct TestCase {
+ int offsetOfThreshold;
+ enum XML_Status expectedStatus;
+ };
+
+ struct TestCase cases[] = {
+ {-2, XML_STATUS_ERROR}, {-1, XML_STATUS_ERROR}, {0, XML_STATUS_ERROR},
+ {+1, XML_STATUS_OK}, {+2, XML_STATUS_OK},
+ };
+
+ for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
+ const int offsetOfThreshold = cases[i].offsetOfThreshold;
+ const enum XML_Status expectedStatus = cases[i].expectedStatus;
+ const unsigned long long activationThresholdBytes
+ = docLen + offsetOfThreshold;
+
+ set_subtest("offsetOfThreshold=%d, expectedStatus=%d", offsetOfThreshold,
+ expectedStatus);
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ assert_true(XML_SetBillionLaughsAttackProtectionMaximumAmplification(
+ parser, maximumToleratedAmplification)
+ == XML_TRUE);
+ assert_true(XML_SetBillionLaughsAttackProtectionActivationThreshold(
+ parser, activationThresholdBytes)
+ == XML_TRUE);
+
+ XML_Parser ext_parser = XML_ExternalEntityParserCreate(parser, NULL, NULL);
+ assert_true(ext_parser != NULL);
+
+ const enum XML_Status actualStatus
+ = _XML_Parse_SINGLE_BYTES(ext_parser, doc, docLen, XML_TRUE);
+
+ assert_true(actualStatus == expectedStatus);
+ if (actualStatus != XML_STATUS_OK) {
+ assert_true(XML_GetErrorCode(ext_parser)
+ == XML_ERROR_AMPLIFICATION_LIMIT_BREACH);
+ }
+
+ XML_ParserFree(ext_parser);
+ XML_ParserFree(parser);
+ }
+}
+END_TEST
+
#endif // XML_GE == 1
void
@@ -390,6 +447,8 @@ make_accounting_test_case(Suite *s) {
tcase_add_test(tc_accounting, test_accounting_precision);
tcase_add_test(tc_accounting, test_billion_laughs_attack_protection_api);
tcase_add_test(tc_accounting, test_helper_unsigned_char_to_printable);
+ tcase_add_test__ifdef_xml_dtd(tc_accounting,
+ test_amplification_isolated_external_parser);
#else
UNUSED_P(s);
#endif /* XML_GE == 1 */
diff --git a/expat/tests/basic_tests.c b/expat/tests/basic_tests.c
index 7112a440..91c8dd7a 100644
--- a/expat/tests/basic_tests.c
+++ b/expat/tests/basic_tests.c
@@ -1202,6 +1202,49 @@ START_TEST(test_wfc_no_recursive_entity_refs) {
}
END_TEST
+START_TEST(test_recursive_external_parameter_entity_2) {
+ struct TestCase {
+ const char *doc;
+ enum XML_Status expectedStatus;
+ };
+
+ struct TestCase cases[] = {
+ {"<!ENTITY % p1 '%p1;'>", XML_STATUS_ERROR},
+ {"<!ENTITY % p1 '%p1;'>"
+ "<!ENTITY % p1 'first declaration wins'>",
+ XML_STATUS_ERROR},
+ {"<!ENTITY % p1 'first declaration wins'>"
+ "<!ENTITY % p1 '%p1;'>",
+ XML_STATUS_OK},
+ {"<!ENTITY % p1 '&#37;p1;'>", XML_STATUS_OK},
+ };
+
+ for (size_t i = 0; i < sizeof(cases) / sizeof(cases[0]); i++) {
+ const char *const doc = cases[i].doc;
+ const enum XML_Status expectedStatus = cases[i].expectedStatus;
+ set_subtest("%s", doc);
+
+ XML_Parser parser = XML_ParserCreate(NULL);
+ assert_true(parser != NULL);
+
+ XML_Parser ext_parser = XML_ExternalEntityParserCreate(parser, NULL, NULL);
+ assert_true(ext_parser != NULL);
+
+ const enum XML_Status actualStatus
+ = _XML_Parse_SINGLE_BYTES(ext_parser, doc, (int)strlen(doc), XML_TRUE);
+
+ assert_true(actualStatus == expectedStatus);
+ if (actualStatus != XML_STATUS_OK) {
+ assert_true(XML_GetErrorCode(ext_parser)
+ == XML_ERROR_RECURSIVE_ENTITY_REF);
+ }
+
+ XML_ParserFree(ext_parser);
+ XML_ParserFree(parser);
+ }
+}
+END_TEST
+
/* Test incomplete external entities are faulted */
START_TEST(test_ext_entity_invalid_parse) {
const char *text = "<!DOCTYPE doc [\n"
@@ -5202,13 +5245,7 @@ START_TEST(test_nested_entity_suspend) {
END_TEST
/* Regression test for quadratic parsing on large tokens */
-START_TEST(test_big_tokens_take_linear_time) {
- const char *const too_slow_failure_message
- = "Compared to the baseline runtime of the first test, this test has a "
- "slowdown of more than <max_slowdown>. "
- "Please keep increasing the value by 1 until it reliably passes the "
- "test on your hardware and open a bug sharing that number with us. "
- "Thanks in advance!";
+START_TEST(test_big_tokens_scale_linearly) {
const struct {
const char *pre;
const char *post;
@@ -5220,65 +5257,57 @@ START_TEST(test_big_tokens_take_linear_time) {
{"<e><", "/></e>"}, // big elem name, used to be O(N²)
};
const int num_cases = sizeof(text) / sizeof(text[0]);
- // For the test we need a <max_slowdown> value that is:
- // (1) big enough that the test passes reliably (avoiding flaky tests), and
- // (2) small enough that the test actually catches regressions.
- const int max_slowdown = 15;
char aaaaaa[4096];
const int fillsize = (int)sizeof(aaaaaa);
const int fillcount = 100;
+ const unsigned approx_bytes = fillsize * fillcount; // ignore pre/post.
+ const unsigned max_factor = 4;
+ const unsigned max_scanned = max_factor * approx_bytes;
memset(aaaaaa, 'a', fillsize);
if (! g_reparseDeferralEnabledDefault) {
return; // heuristic is disabled; we would get O(n^2) and fail.
}
-#if ! defined(__linux__)
- if (CLOCKS_PER_SEC < 100000) {
- // Skip this test if clock() doesn't have reasonably good resolution.
- // This workaround is primarily targeting Windows and FreeBSD, since
- // XSI requires the value to be 1.000.000 (10x the condition here), and
- // we want to be very sure that at least one platform in CI can catch
- // regressions (through a failing test).
- return;
- }
-#endif
- clock_t baseline = 0;
for (int i = 0; i < num_cases; ++i) {
XML_Parser parser = XML_ParserCreate(NULL);
assert_true(parser != NULL);
enum XML_Status status;
- set_subtest("max_slowdown=%d text=\"%saaaaaa%s\"", max_slowdown,
- text[i].pre, text[i].post);
- const clock_t start = clock();
+ set_subtest("text=\"%saaaaaa%s\"", text[i].pre, text[i].post);
// parse the start text
+ g_bytesScanned = 0;
status = _XML_Parse_SINGLE_BYTES(parser, text[i].pre,
(int)strlen(text[i].pre), XML_FALSE);
if (status != XML_STATUS_OK) {
xml_failure(parser);
}
+
// parse lots of 'a', failing the test early if it takes too long
+ unsigned past_max_count = 0;
for (int f = 0; f < fillcount; ++f) {
status = _XML_Parse_SINGLE_BYTES(parser, aaaaaa, fillsize, XML_FALSE);
if (status != XML_STATUS_OK) {
xml_failure(parser);
}
- // i == 0 means we're still calculating the baseline value
- if (i > 0) {
- const clock_t now = clock();
- const clock_t clocks_so_far = now - start;
- const int slowdown = clocks_so_far / baseline;
- if (slowdown >= max_slowdown) {
- fprintf(
- stderr,
- "fill#%d: clocks_so_far=%d baseline=%d slowdown=%d max_slowdown=%d\n",
- f, (int)clocks_so_far, (int)baseline, slowdown, max_slowdown);
- fail(too_slow_failure_message);
- }
+ if (g_bytesScanned > max_scanned) {
+ // We're not done, and have already passed the limit -- the test will
+ // definitely fail. This block allows us to save time by failing early.
+ const unsigned pushed
+ = (unsigned)strlen(text[i].pre) + (f + 1) * fillsize;
+ fprintf(
+ stderr,
+ "after %d/%d loops: pushed=%u scanned=%u (factor ~%.2f) max_scanned: %u (factor ~%u)\n",
+ f + 1, fillcount, pushed, g_bytesScanned,
+ g_bytesScanned / (double)pushed, max_scanned, max_factor);
+ past_max_count++;
+ // We are failing, but allow a few log prints first. If we don't reach
+ // a count of five, the test will fail after the loop instead.
+ assert_true(past_max_count < 5);
}
}
+
// parse the end text
status = _XML_Parse_SINGLE_BYTES(parser, text[i].post,
(int)strlen(text[i].post), XML_TRUE);
@@ -5286,18 +5315,14 @@ START_TEST(test_big_tokens_take_linear_time) {
xml_failure(parser);
}
- // how long did it take in total?
- const clock_t end = clock();
- const clock_t taken = end - start;
- if (i == 0) {
- assert_true(taken > 0); // just to make sure we don't div-by-0 later
- baseline = taken;
- }
- const int slowdown = taken / baseline;
- if (slowdown >= max_slowdown) {
- fprintf(stderr, "taken=%d baseline=%d slowdown=%d max_slowdown=%d\n",
- (int)taken, (int)baseline, slowdown, max_slowdown);
- fail(too_slow_failure_message);
+ assert_true(g_bytesScanned > approx_bytes); // or the counter isn't working
+ if (g_bytesScanned > max_scanned) {
+ fprintf(
+ stderr,
+ "after all input: scanned=%u (factor ~%.2f) max_scanned: %u (factor ~%u)\n",
+ g_bytesScanned, g_bytesScanned / (double)approx_bytes, max_scanned,
+ max_factor);
+ fail("scanned too many bytes");
}
XML_ParserFree(parser);
@@ -5774,19 +5799,17 @@ START_TEST(test_varying_buffer_fills) {
fillsize[2], fillsize[3]);
XML_Parser parser = XML_ParserCreate(NULL);
assert_true(parser != NULL);
- g_parseAttempts = 0;
CharData storage;
CharData_Init(&storage);
XML_SetUserData(parser, &storage);
XML_SetStartElementHandler(parser, start_element_event_handler);
+ g_bytesScanned = 0;
int worstcase_bytes = 0; // sum of (buffered bytes at each XML_Parse call)
- int scanned_bytes = 0; // sum of (buffered bytes at each actual parse)
int offset = 0;
while (*fillsize >= 0) {
assert_true(offset + *fillsize <= document_length); // or test is invalid
- const unsigned attempts_before = g_parseAttempts;
const enum XML_Status status
= XML_Parse(parser, &document[offset], *fillsize, XML_FALSE);
if (status != XML_STATUS_OK) {
@@ -5796,28 +5819,20 @@ START_TEST(test_varying_buffer_fills) {
fillsize++;
assert_true(offset <= INT_MAX - worstcase_bytes); // avoid overflow
worstcase_bytes += offset; // we might've tried to parse all pending bytes
- if (g_parseAttempts != attempts_before) {
- assert_true(g_parseAttempts == attempts_before + 1); // max 1/XML_Parse
- assert_true(offset <= INT_MAX - scanned_bytes); // avoid overflow
- scanned_bytes += offset; // we *did* try to parse all pending bytes
- }
}
assert_true(storage.count == 1); // the big token should've been parsed
- assert_true(scanned_bytes > 0); // test-the-test: does our counter work?
+ assert_true(g_bytesScanned > 0); // test-the-test: does our counter work?
if (g_reparseDeferralEnabledDefault) {
// heuristic is enabled; some XML_Parse calls may have deferred reparsing
- const int max_bytes_scanned = -*fillsize;
- if (scanned_bytes > max_bytes_scanned) {
+ const unsigned max_bytes_scanned = -*fillsize;
+ if (g_bytesScanned > max_bytes_scanned) {
fprintf(stderr,
- "bytes scanned in parse attempts: actual=%d limit=%d \n",
- scanned_bytes, max_bytes_scanned);
+ "bytes scanned in parse attempts: actual=%u limit=%u \n",
+ g_bytesScanned, max_bytes_scanned);
fail("too many bytes scanned in parse attempts");
}
- assert_true(scanned_bytes <= worstcase_bytes);
- } else {
- // heuristic is disabled; every XML_Parse() will have reparsed
- assert_true(scanned_bytes == worstcase_bytes);
}
+ assert_true(g_bytesScanned <= (unsigned)worstcase_bytes);
XML_ParserFree(parser);
}
@@ -5972,6 +5987,8 @@ make_basic_test_case(Suite *s) {
tcase_add_test__ifdef_xml_dtd(tc_basic, test_skipped_parameter_entity);
tcase_add_test__ifdef_xml_dtd(tc_basic,
test_recursive_external_parameter_entity);
+ tcase_add_test__ifdef_xml_dtd(tc_basic,
+ test_recursive_external_parameter_entity_2);
tcase_add_test(tc_basic, test_undefined_ext_entity_in_external_dtd);
tcase_add_test(tc_basic, test_suspend_xdecl);
tcase_add_test(tc_basic, test_abort_epilog);
@@ -6065,7 +6082,7 @@ make_basic_test_case(Suite *s) {
tcase_add_test__ifdef_xml_dtd(tc_basic,
test_pool_integrity_with_unfinished_attr);
tcase_add_test__if_xml_ge(tc_basic, test_nested_entity_suspend);
- tcase_add_test(tc_basic, test_big_tokens_take_linear_time);
+ tcase_add_test(tc_basic, test_big_tokens_scale_linearly);
tcase_add_test(tc_basic, test_set_reparse_deferral);
tcase_add_test(tc_basic, test_reparse_deferral_is_inherited);
tcase_add_test(tc_basic, test_set_reparse_deferral_on_null_parser);
diff --git a/expat/tests/misc_tests.c b/expat/tests/misc_tests.c
index b5212f58..ffde0563 100644
--- a/expat/tests/misc_tests.c
+++ b/expat/tests/misc_tests.c
@@ -208,7 +208,7 @@ START_TEST(test_misc_version) {
if (! versions_equal(&read_version, &parsed_version))
fail("Version mismatch");
- if (xcstrcmp(version_text, XCS("expat_2.6.0"))) /* needs bump on releases */
+ if (xcstrcmp(version_text, XCS("expat_2.6.2"))) /* needs bump on releases */
fail("XML_*_VERSION in expat.h out of sync?\n");
}
END_TEST
diff --git a/expat/win32/expat.iss b/expat/win32/expat.iss
index 90786bef..2a4c87e6 100644
--- a/expat/win32/expat.iss
+++ b/expat/win32/expat.iss
@@ -37,7 +37,7 @@
; OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
; USE OR OTHER DEALINGS IN THE SOFTWARE.
-#define expatVer "2.6.0"
+#define expatVer "2.6.2"
[Setup]
AppName=Expat
diff --git a/expat_config.h b/expat_config.h
index efc4f0ad..ae442231 100644
--- a/expat_config.h
+++ b/expat_config.h
@@ -91,7 +91,7 @@
#define PACKAGE_NAME "expat"
/* Define to the full name and version of this package. */
-#define PACKAGE_STRING "expat 2.6.0"
+#define PACKAGE_STRING "expat 2.6.2"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "expat"
@@ -100,7 +100,7 @@
#define PACKAGE_URL ""
/* Define to the version of this package. */
-#define PACKAGE_VERSION "2.6.0"
+#define PACKAGE_VERSION "2.6.2"
/* Define to 1 if all of the C90 standard headers exist (not just the ones
required in a freestanding environment). This macro is provided for
@@ -108,7 +108,7 @@
#define STDC_HEADERS 1
/* Version number of package */
-#define VERSION "2.6.0"
+#define VERSION "2.6.2"
/* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most
significant byte first (like Motorola and SPARC, unlike Intel). */