mirror of
https://github.com/freebsd/freebsd-src.git
synced 2026-11-07 04:36:52 -10:00
Vendor import of expat 2.10.0
This commit is contained in:
1 parent
91970165e3
commit
27ac437388
34 files changed
+1641
-192
No files matched your search
@@ -21,6 +21,86 @@
|
||||
// Sebastian Pipping -- Berlin, 2026-09-22 //
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
Release 2.10.0 Mon November 2 2026
|
||||
Security fixes:
|
||||
#1431 CVE-2026-113351 -- Fix denial of service with use of
|
||||
`XML_ParserReset`
|
||||
#1433 #1436 ..
|
||||
#1438 #1439 ..
|
||||
#1442 CVE-2026-115506 -- Detect billion laughs attacks quicker
|
||||
and more of its variations. Related payload fuzzer at:
|
||||
https://github.com/hannob/lololol
|
||||
Please note that a layer of compression around XML can
|
||||
significantly reduce the minimum attack payload size.
|
||||
In case of backporting, please note pull request #1439
|
||||
in particular.
|
||||
#1444 CVE-2026-117610 -- Fix initial non-final empty subparser
|
||||
parse calls. Was segfaulting previously.
|
||||
#1450 CVE-2026-118370 -- Protect `attIndex` and `nPrefixes` in
|
||||
function `storeAtts` from signed integer overflow
|
||||
|
||||
Bug fixes:
|
||||
#1452 lib: Initialize `m_parsingStatus.finalBuffer` in `parserInit`
|
||||
to fix calling `XML_GetParsingStatus` right after
|
||||
parser creation
|
||||
#1457 #1459 lib: Improve `XML_Parse` for `XML_CONTEXT_BYTES == 0`
|
||||
including NULL pointer arithmetic undefined behavior
|
||||
and uninitialized variable access
|
||||
#1458 lib: Use C99 length modifiers for `ptrdiff_t` and `size_t`
|
||||
to fix support for CHERI-RISC-V
|
||||
#1461 lib: Check `isCalledFromInsideHandler` first in `XML_Parse`
|
||||
#1467 lib: Add missing check for a character handler reset
|
||||
|
||||
Other changes:
|
||||
#1441 Autotools: Move `-lm` from LDFLAGS to LIBADD/LDADD
|
||||
to better support compilation with `-Wl,--as-needed`
|
||||
#1412 CMake: Support repeated `find_package` calls
|
||||
#1413 lib: Address warning `XML_GE is not defined [-Werror=undef]`
|
||||
#1415 lib: Stop delaying `callStoreEntityValue` error handling
|
||||
#1415 lib: Add missing call to `poolDiscard`
|
||||
#1437 lib: Add missing `NULL` check for `m_startDoctypeDeclHandler`
|
||||
#1417 lib: Migrate `ENTITY.textLen` and `ENTITY.processed` from
|
||||
`int` to `size_t`
|
||||
#1463 lib: Fix integer truncation in `XmlGetAttributes`/`getAtts`
|
||||
#1420 lib: Some more `XML_Bool` to `bool` migration
|
||||
#1449 #1460 lib: Document the memory reuse black magic that function
|
||||
`storeAtts` is doing
|
||||
#1453 lib: Document failure to reject bad redefinitions of
|
||||
predefined entities
|
||||
#1432 tests: Replace `XML_SetHashSalt` with
|
||||
`XML_SetHashSalt16Bytes`
|
||||
#1416 #1435 Version info bumped from 14:0:13 (libexpat*.so.1.13.0)
|
||||
to 14:1:13 (libexpat*.so.1.13.1); see https://verbump.de/
|
||||
for what these numbers do
|
||||
|
||||
Infrastructure:
|
||||
#1414 CI: Stop using about-to-be-removed image "macos-14"
|
||||
#1418 #1434 CI: Bump MinGW Clang from 23.1.2 to 23.1.4
|
||||
#1443 CI: Bump Fil-C from 0.686 to 0.687
|
||||
#1456 Drop a `lib/xcsinc.c` leftover
|
||||
|
||||
Special thanks to:
|
||||
Alexander Bluhm
|
||||
Bartłomiej Dmitruk
|
||||
Berkay Eren Ürün
|
||||
Brooks Davis
|
||||
brspoon
|
||||
Funda Wang
|
||||
Hanno Böck
|
||||
Matthew Fernandez
|
||||
Minkyung Park
|
||||
Mirko Swillus
|
||||
Pu Cheng
|
||||
Scott Moore
|
||||
Shani Yosef
|
||||
Xisco Fauli
|
||||
and
|
||||
City of Munich Open Source Sabbatical
|
||||
echo.ai
|
||||
Siemens
|
||||
Striga
|
||||
VulnCheck
|
||||
|
||||
Release 2.9.0 Mon October 5 2026
|
||||
Security fixes:
|
||||
#1392 CVE-2026-102633 -- Integer overflow in function
|
||||
@@ -106,6 +186,7 @@ Release 2.9.0 Mon October 5 2026
|
||||
Wade Sparks III
|
||||
and
|
||||
City of Munich Open Source Sabbatical
|
||||
Siemens
|
||||
VulnCheck
|
||||
|
||||
Release 2.8.5 Tue September 22 2026
|
||||
@@ -239,6 +320,7 @@ Release 2.8.4 Mon August 31 2026
|
||||
and
|
||||
City of Munich Open Source Sabbatical
|
||||
Moonshot AI
|
||||
Siemens
|
||||
VulnCheck
|
||||
Z.ai
|
||||
|
||||
@@ -425,6 +507,8 @@ Release 2.8.1 Sun May 10 2026
|
||||
Matthew Fernandez
|
||||
Nick Wellnhofer
|
||||
Tania Somanna
|
||||
and
|
||||
Siemens
|
||||
|
||||
Release 2.8.0 Fri April 24 2026
|
||||
Security fixes:
|
||||
@@ -537,6 +621,7 @@ Release 2.7.5 Tue March 17 2026
|
||||
AddressSanitizer
|
||||
Buttercup
|
||||
OSS-Fuzz / ClusterFuzz
|
||||
Siemens
|
||||
Trail of Bits
|
||||
|
||||
Release 2.7.4 Sat January 31 2026
|
||||
@@ -678,6 +763,7 @@ Release 2.7.3 Wed September 24 2025
|
||||
and
|
||||
Clang/GCC UndefinedBehaviorSanitizer
|
||||
OSS-Fuzz / ClusterFuzz
|
||||
Siemens
|
||||
Z3 Theorem Prover
|
||||
|
||||
Release 2.7.2 Tue September 16 2025
|
||||
@@ -791,6 +877,7 @@ Release 2.7.1 Thu March 27 2025
|
||||
Matthew Fernandez
|
||||
and
|
||||
Perl XML::Parser
|
||||
Siemens
|
||||
|
||||
Release 2.7.0 Thu March 13 2025
|
||||
Security fixes:
|
||||
@@ -950,6 +1037,8 @@ Release 2.6.3 Wed September 4 2024
|
||||
Dag-Erling Smørgrav
|
||||
Ferenc Géczi
|
||||
TaiYou
|
||||
and
|
||||
Siemens
|
||||
|
||||
Release 2.6.2 Wed March 13 2024
|
||||
Security fixes:
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
> Thank you! :heart: :pray:
|
||||
|
||||
|
||||
# Expat, Release 2.9.0
|
||||
# Expat, Release 2.10.0
|
||||
|
||||
This is Expat, a C99 library for parsing
|
||||
[XML 1.0 Fourth Edition](https://www.w3.org/TR/2006/REC-xml-20060816/), started by
|
||||
|
||||
+1
-1
@@ -104,7 +104,7 @@ dnl If the API changes incompatibly set LIBAGE back to 0
|
||||
dnl
|
||||
|
||||
LIBCURRENT=14 # sync
|
||||
LIBREVISION=0 # with
|
||||
LIBREVISION=1 # with
|
||||
LIBAGE=13 # CMakeLists.txt!
|
||||
|
||||
AC_CONFIG_HEADERS([expat_config.h])
|
||||
|
||||
+7
-1
@@ -53,7 +53,7 @@
|
||||
<body>
|
||||
<div>
|
||||
<h1>
|
||||
The Expat XML Parser <small>Release 2.9.0</small>
|
||||
The Expat XML Parser <small>Release 2.10.0</small>
|
||||
</h1>
|
||||
</div>
|
||||
|
||||
@@ -2862,6 +2862,12 @@ typedef void
|
||||
The <code>notationName</code> argument will have a non-<code>NULL</code> value
|
||||
only for unparsed entity declarations.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Note:</strong> Length <code>value_length</code> can wrap around on
|
||||
platforms where <code>int</code> is smaller than <code>size_t</code> including
|
||||
<code>x86_64</code>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="handler">
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
\\$2 \(la\\$1\(ra\\$3
|
||||
..
|
||||
.if \n(.g .mso www.tmac
|
||||
.TH XMLWF 1 "October 5, 2026" "" ""
|
||||
.TH XMLWF 1 "November 2, 2026" "" ""
|
||||
.SH NAME
|
||||
xmlwf \- Determines if an XML document is well-formed
|
||||
.SH SYNOPSIS
|
||||
|
||||
+1
-1
@@ -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>October 5, 2026</date>">
|
||||
<!ENTITY dhdate "<date>November 2, 2026</date>">
|
||||
<!-- Please adjust this^^ date whenever cutting a new release. -->
|
||||
<!ENTITY dhsection "<manvolnum>1</manvolnum>">
|
||||
<!ENTITY dhemail "<email>[email protected]</email>">
|
||||
|
||||
+4
-1
@@ -12,6 +12,7 @@
|
||||
# Copyright (c) 2026 Gordon Messmer <[email protected]>
|
||||
# Copyright (c) 2026 Nick Begg <[email protected]>
|
||||
# Copyright (c) 2026 Matthew Fernandez <[email protected]>
|
||||
# Copyright (c) 2026 Funda Wang <[email protected]>
|
||||
# Licensed under the MIT license:
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
@@ -45,13 +46,14 @@ endif
|
||||
|
||||
libexpat_la_LDFLAGS = \
|
||||
@AM_LDFLAGS@ \
|
||||
@LIBM@ \
|
||||
-no-undefined \
|
||||
-version-info @LIBCURRENT@:@LIBREVISION@:@LIBAGE@
|
||||
if HAVE_VSCRIPT
|
||||
libexpat_la_LDFLAGS += $(VSCRIPT_LDFLAGS),@builddir@/libexpat.map
|
||||
endif
|
||||
|
||||
libexpat_la_LIBADD = @LIBM@
|
||||
|
||||
libexpat_la_SOURCES = \
|
||||
xcs.c \
|
||||
xmlparse.c \
|
||||
@@ -113,6 +115,7 @@ uninstall-local:
|
||||
EXTRA_DIST = \
|
||||
ascii.h \
|
||||
asciitab.h \
|
||||
entities.h \
|
||||
expat_external.h \
|
||||
expat.h \
|
||||
fallthrough.h \
|
||||
|
||||
+5
-2
@@ -28,6 +28,7 @@
|
||||
# Copyright (c) 2026 Gordon Messmer <[email protected]>
|
||||
# Copyright (c) 2026 Nick Begg <[email protected]>
|
||||
# Copyright (c) 2026 Matthew Fernandez <[email protected]>
|
||||
# Copyright (c) 2026 Funda Wang <[email protected]>
|
||||
# Licensed under the MIT license:
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
@@ -205,7 +206,7 @@ am__uninstall_files_from_dir = { \
|
||||
am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(docdir)" \
|
||||
"$(DESTDIR)$(includedir)"
|
||||
LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES)
|
||||
libexpat_la_LIBADD =
|
||||
libexpat_la_DEPENDENCIES =
|
||||
am__libexpat_la_SOURCES_DIST = xcs.c xmlparse.c xmltok.c xmlrole.c \
|
||||
random_arc4random.c random_arc4random.h \
|
||||
random_arc4random_buf.c random_arc4random_buf.h \
|
||||
@@ -493,8 +494,9 @@ include_HEADERS = \
|
||||
|
||||
lib_LTLIBRARIES = libexpat.la
|
||||
@WITH_TESTS_TRUE@noinst_LTLIBRARIES = libtestpat.la
|
||||
libexpat_la_LDFLAGS = @AM_LDFLAGS@ @LIBM@ -no-undefined -version-info \
|
||||
libexpat_la_LDFLAGS = @AM_LDFLAGS@ -no-undefined -version-info \
|
||||
@LIBCURRENT@:@LIBREVISION@:@LIBAGE@ $(am__append_1)
|
||||
libexpat_la_LIBADD = @LIBM@
|
||||
libexpat_la_SOURCES = xcs.c xmlparse.c xmltok.c xmlrole.c \
|
||||
$(am__append_2) $(am__append_3) $(am__append_4) \
|
||||
$(am__append_5) $(am__append_6) $(am__append_7)
|
||||
@@ -507,6 +509,7 @@ doc_DATA = \
|
||||
EXTRA_DIST = \
|
||||
ascii.h \
|
||||
asciitab.h \
|
||||
entities.h \
|
||||
expat_external.h \
|
||||
expat.h \
|
||||
fallthrough.h \
|
||||
|
||||
+2
-1
@@ -10,7 +10,7 @@
|
||||
Copyright (c) 2000 Clark Cooper <[email protected]>
|
||||
Copyright (c) 2002 Fred L. Drake, Jr. <[email protected]>
|
||||
Copyright (c) 2007 Karl Waclawek <[email protected]>
|
||||
Copyright (c) 2017 Sebastian Pipping <[email protected]>
|
||||
Copyright (c) 2017-2026 Sebastian Pipping <[email protected]>
|
||||
Licensed under the MIT license:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
@@ -113,6 +113,7 @@
|
||||
#define ASCII_LT 0x3C
|
||||
#define ASCII_EQUALS 0x3D
|
||||
#define ASCII_GT 0x3E
|
||||
#define ASCII_QUEST 0x3F
|
||||
#define ASCII_LSQB 0x5B
|
||||
#define ASCII_RSQB 0x5D
|
||||
#define ASCII_UNDERSCORE 0x5F
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
/* Internal helpers related to entities
|
||||
__ __ _
|
||||
___\ \/ /_ __ __ _| |_
|
||||
/ _ \\ /| '_ \ / _` | __|
|
||||
| __// \| |_) | (_| | |_
|
||||
\___/_/\_\ .__/ \__,_|\__|
|
||||
|_| XML parser
|
||||
|
||||
Copyright (c) 2026 Sebastian Pipping <[email protected]>
|
||||
Licensed under the MIT license:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
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(EXPAT_ENTITIES_H)
|
||||
# define EXPAT_ENTITIES_H 1
|
||||
|
||||
# include "expat_config.h" // for XML_GE
|
||||
# include "expat_external.h" // for XML_Char
|
||||
# include "internal.h" // for XML_NONTESTING_STATIC
|
||||
# include <stdbool.h> // for size_t
|
||||
# include <stddef.h> // for size_t
|
||||
|
||||
typedef struct {
|
||||
const XML_Char *name;
|
||||
const XML_Char *textPtr;
|
||||
size_t textLen; /* length in XML_Chars */
|
||||
size_t processed; /* # of processed bytes - when suspended */
|
||||
const XML_Char *systemId;
|
||||
const XML_Char *base;
|
||||
const XML_Char *publicId;
|
||||
const XML_Char *notation;
|
||||
bool open;
|
||||
bool hasMore; /* true if entity has not been completely processed */
|
||||
/* An entity can be open while being already completely processed (!hasMore).
|
||||
The reason is the delayed closing of entities until their inner
|
||||
entities are processed and closed */
|
||||
bool is_param;
|
||||
bool is_internal; /* true if declared in internal subset outside PE */
|
||||
# if XML_GE == 1
|
||||
/* Indirect accounting bytes charged when this entity is expanded: 1 per text
|
||||
character, plus each reference's "&name;"/"%name;" token length and its own
|
||||
expansion. Matches XML_ACCOUNT_ENTITY_EXPANSION, so it is not the
|
||||
replacement-text size. 0 means "not computed yet" (an empty entity is 0
|
||||
too, told apart by textLen == 0). */
|
||||
XmlBigCount expandedSize;
|
||||
bool beingAnalyzed; /* on the resolveEntityClosureExpandedSize depth-first
|
||||
search stack; used for cycle detection */
|
||||
const XML_Char
|
||||
*scanPtr; /* cursor position into the entity's replacement text; NULL when
|
||||
`textPtr` is NULL, else a pointer into the entity value,
|
||||
ranging from `.textPtr` to `.textPtr + .textLen`. */
|
||||
# endif /* XML_GE == 1 */
|
||||
} ENTITY;
|
||||
|
||||
# if XML_GE == 1
|
||||
/* How a scanEntityText call ended. */
|
||||
enum EntityScanResult {
|
||||
ENTITY_SCAN_COMPLETE, /* reached end of text; *expandedSize is final */
|
||||
ENTITY_SCAN_BLOCKED, /* stopped at a defined entity whose expanded
|
||||
size has not been computed yet; *blockerOut
|
||||
names the entity whose size to compute
|
||||
first */
|
||||
ENTITY_SCAN_OVERFLOW /* the expanded size would exceed XmlBigCount;
|
||||
callers must abort parsing */
|
||||
};
|
||||
|
||||
XML_NONTESTING_STATIC int isCDataCommentOrPIStart(const XML_Char *pos,
|
||||
size_t maxLen,
|
||||
size_t *openTextLen);
|
||||
|
||||
XML_NONTESTING_STATIC int isPredefinedEntityName(const XML_Char *name,
|
||||
size_t nameLen);
|
||||
|
||||
XML_NONTESTING_STATIC enum EntityScanResult
|
||||
scanEntityText(XML_Parser parser, ENTITY *entity, const XML_Char **posPtr,
|
||||
XmlBigCount *expandedSize, ENTITY **blockerOut);
|
||||
# endif /* XML_GE == 1 */
|
||||
|
||||
#endif // ! defined(EXPAT_ENTITIES_H)
|
||||
+3
-2
@@ -21,6 +21,7 @@
|
||||
Copyright (c) 2024 Taichi Haradaguchi <[email protected]>
|
||||
Copyright (c) 2025 Matthew Fernandez <[email protected]>
|
||||
Copyright (c) 2026 Braian Plaku <[email protected]>
|
||||
Copyright (c) 2026 Xisco Fauli <[email protected]>
|
||||
Licensed under the MIT license:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
@@ -1084,7 +1085,7 @@ enum XML_Parser_Property {
|
||||
# if defined(XML_TESTING)
|
||||
XML_PROP_INVALID = 0,
|
||||
# endif
|
||||
# if XML_GE == 1
|
||||
# if defined(XML_GE) && XML_GE == 1
|
||||
XML_PROP_ALLOC_TRACKER_ACTIVATION_THRESHOLD = 1, // of type `uint64_t`
|
||||
XML_PROP_ALLOC_TRACKER_MAXIMUM_AMPLIFICATION = 2, // of type `double`
|
||||
XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD = 3, // of type `uint64_t`
|
||||
@@ -1146,7 +1147,7 @@ XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled);
|
||||
See https://semver.org
|
||||
*/
|
||||
# define XML_MAJOR_VERSION 2
|
||||
# define XML_MINOR_VERSION 9
|
||||
# define XML_MINOR_VERSION 10
|
||||
# define XML_MICRO_VERSION 0
|
||||
|
||||
# ifdef __cplusplus
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
Copyright (c) 2001-2002 Greg Stein <[email protected]>
|
||||
Copyright (c) 2002-2006 Karl Waclawek <[email protected]>
|
||||
Copyright (c) 2016 Cristian Rodríguez <[email protected]>
|
||||
Copyright (c) 2016-2025 Sebastian Pipping <[email protected]>
|
||||
Copyright (c) 2016-2026 Sebastian Pipping <[email protected]>
|
||||
Copyright (c) 2017 Rhodri James <[email protected]>
|
||||
Copyright (c) 2018 Yury Gribov <[email protected]>
|
||||
Copyright (c) 2026 Matthew Fernandez <[email protected]>
|
||||
|
||||
+5
-3
@@ -29,6 +29,7 @@
|
||||
Copyright (c) 2026 Matthew Wozniczka <[email protected]>
|
||||
Copyright (c) 2026 Braian Plaku <[email protected]>
|
||||
Copyright (c) 2026 Florian Schmaus <[email protected]>
|
||||
Copyright (c) 2026 Brooks Davis <[email protected]>
|
||||
Licensed under the MIT license:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
@@ -90,11 +91,10 @@
|
||||
# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "u"
|
||||
# endif
|
||||
# else
|
||||
# include <inttypes.h> // PRIdPTR, PRIuPTR
|
||||
# define EXPAT_FMT_LLX(midpart) "%" midpart "llx"
|
||||
# define EXPAT_FMT_ULL(midpart) "%" midpart "llu"
|
||||
# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart PRIdPTR
|
||||
# define EXPAT_FMT_SIZE_T(midpart) "%" midpart PRIuPTR
|
||||
# define EXPAT_FMT_PTRDIFF_T(midpart) "%" midpart "td"
|
||||
# define EXPAT_FMT_SIZE_T(midpart) "%" midpart "zu"
|
||||
# endif
|
||||
|
||||
# ifndef UNUSED_P
|
||||
@@ -127,6 +127,8 @@ union expat_align {
|
||||
|
||||
# include "expat.h" // so we can use type XML_Parser below
|
||||
|
||||
typedef unsigned long long XmlBigCount;
|
||||
|
||||
void _INTERNAL_trim_to_complete_utf8_characters(const char *from,
|
||||
const char **fromLimRef);
|
||||
|
||||
|
||||
@@ -88,3 +88,24 @@ xcsncmp(const XML_Char *a, const XML_Char *b, size_t len) {
|
||||
return strncmp(a, b, len);
|
||||
#endif
|
||||
}
|
||||
|
||||
// A port of `strnstr(3bsd)` to `XML_Char`
|
||||
const XML_Char *
|
||||
xcsnstr(const XML_Char *haystack, const XML_Char *needle, size_t maxLen) {
|
||||
// NOTE: We are not calling `xcsnlen(haystack, maxLen)` because
|
||||
// `haystack` could be long and `xcsnlen` could be used in a loop
|
||||
// and we need to avoid quadratic runtime behavior.
|
||||
if (! *needle)
|
||||
return haystack; // i.e. empty needle is always a match
|
||||
const size_t needleLen = xcslen(needle);
|
||||
if (needleLen > maxLen)
|
||||
return NULL;
|
||||
const size_t maxTries = (maxLen - needleLen) + 1;
|
||||
for (size_t i = 0; i < maxTries && haystack[i]; i++) {
|
||||
if (haystack[i] == needle[0]
|
||||
&& xcsncmp(haystack + i, needle, needleLen) == 0) {
|
||||
return haystack + i;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
@@ -41,4 +41,7 @@ extern size_t xcslen(const XML_Char *s);
|
||||
extern int xcscmp(const XML_Char *a, const XML_Char *b);
|
||||
extern int xcsncmp(const XML_Char *a, const XML_Char *b, size_t len);
|
||||
|
||||
extern const XML_Char *xcsnstr(const XML_Char *haystack, const XML_Char *needle,
|
||||
size_t maxLen);
|
||||
|
||||
#endif // ! defined(EXPAT_XCS_H)
|
||||
+731
-138
File diff suppressed because it is too large.
Load diff
+2
-2
@@ -176,8 +176,8 @@ struct encoding {
|
||||
const char *);
|
||||
int (*nameLength)(const ENCODING *, const char *);
|
||||
const char *(*skipS)(const ENCODING *, const char *);
|
||||
int (*getAtts)(const ENCODING *enc, const char *ptr, int attsMax,
|
||||
ATTRIBUTE *atts);
|
||||
size_t (*getAtts)(const ENCODING *enc, const char *ptr, size_t attsMax,
|
||||
ATTRIBUTE *atts);
|
||||
int (*charRefNumber)(const ENCODING *enc, const char *ptr);
|
||||
int (*predefinedEntityName)(const ENCODING *, const char *, const char *);
|
||||
void (*updatePosition)(const ENCODING *, const char *ptr, const char *end,
|
||||
|
||||
+3
-3
@@ -1505,11 +1505,11 @@ PREFIX(isPublicId)(const ENCODING *enc, const char *ptr, const char *end,
|
||||
first attsMax attributes are stored in atts.
|
||||
*/
|
||||
|
||||
static int
|
||||
PREFIX(getAtts)(const ENCODING *enc, const char *ptr, int attsMax,
|
||||
static size_t
|
||||
PREFIX(getAtts)(const ENCODING *enc, const char *ptr, size_t attsMax,
|
||||
ATTRIBUTE *atts) {
|
||||
enum { other, inName, inValue } state = inName;
|
||||
int nAtts = 0;
|
||||
size_t nAtts = 0;
|
||||
int open = 0; /* defined when state == inValue;
|
||||
initialization just to shut up compilers */
|
||||
|
||||
|
||||
+5
-2
@@ -10,6 +10,7 @@
|
||||
# Copyright (c) 2017-2022 Rhodri James <[email protected]>
|
||||
# Copyright (c) 2020 Jeffrey Walton <[email protected]>
|
||||
# Copyright (c) 2024 Dag-Erling Smørgrav <[email protected]>
|
||||
# Copyright (c) 2026 Funda Wang <[email protected]>
|
||||
# Licensed under the MIT license:
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
@@ -50,6 +51,7 @@ runtests_SOURCES = \
|
||||
dummy.c \
|
||||
handlers.c \
|
||||
hash_tests.c \
|
||||
entities_tests.c \
|
||||
memcheck.c \
|
||||
minicheck.c \
|
||||
misc_tests.c \
|
||||
@@ -60,9 +62,9 @@ runtests_SOURCES = \
|
||||
structdata.c \
|
||||
xcs_tests.c
|
||||
|
||||
runtests_LDADD = ../lib/libtestpat.la
|
||||
runtests_LDADD = ../lib/libtestpat.la @LIBM@
|
||||
|
||||
runtests_LDFLAGS = @AM_LDFLAGS@ @LIBM@
|
||||
runtests_LDFLAGS = @AM_LDFLAGS@
|
||||
|
||||
EXTRA_DIST = \
|
||||
acc_tests.h \
|
||||
@@ -73,6 +75,7 @@ EXTRA_DIST = \
|
||||
dummy.h \
|
||||
handlers.h \
|
||||
hash_tests.h \
|
||||
entities_tests.h \
|
||||
memcheck.h \
|
||||
minicheck.h \
|
||||
misc_tests.h \
|
||||
|
||||
+19
-12
@@ -26,6 +26,7 @@
|
||||
# Copyright (c) 2017-2022 Rhodri James <[email protected]>
|
||||
# Copyright (c) 2020 Jeffrey Walton <[email protected]>
|
||||
# Copyright (c) 2024 Dag-Erling Smørgrav <[email protected]>
|
||||
# Copyright (c) 2026 Funda Wang <[email protected]>
|
||||
# Licensed under the MIT license:
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
@@ -150,10 +151,10 @@ CONFIG_CLEAN_VPATH_FILES =
|
||||
am_runtests_OBJECTS = acc_tests.$(OBJEXT) alloc_tests.$(OBJEXT) \
|
||||
basic_tests.$(OBJEXT) chardata.$(OBJEXT) common.$(OBJEXT) \
|
||||
dummy.$(OBJEXT) handlers.$(OBJEXT) hash_tests.$(OBJEXT) \
|
||||
memcheck.$(OBJEXT) minicheck.$(OBJEXT) misc_tests.$(OBJEXT) \
|
||||
ns_tests.$(OBJEXT) nsalloc_tests.$(OBJEXT) \
|
||||
props_tests.$(OBJEXT) runtests.$(OBJEXT) structdata.$(OBJEXT) \
|
||||
xcs_tests.$(OBJEXT)
|
||||
entities_tests.$(OBJEXT) memcheck.$(OBJEXT) \
|
||||
minicheck.$(OBJEXT) misc_tests.$(OBJEXT) ns_tests.$(OBJEXT) \
|
||||
nsalloc_tests.$(OBJEXT) props_tests.$(OBJEXT) \
|
||||
runtests.$(OBJEXT) structdata.$(OBJEXT) xcs_tests.$(OBJEXT)
|
||||
runtests_OBJECTS = $(am_runtests_OBJECTS)
|
||||
runtests_DEPENDENCIES = ../lib/libtestpat.la
|
||||
AM_V_lt = $(am__v_lt_@AM_V@)
|
||||
@@ -181,12 +182,13 @@ am__maybe_remake_depfiles = depfiles
|
||||
am__depfiles_remade = ./$(DEPDIR)/acc_tests.Po \
|
||||
./$(DEPDIR)/alloc_tests.Po ./$(DEPDIR)/basic_tests.Po \
|
||||
./$(DEPDIR)/chardata.Po ./$(DEPDIR)/common.Po \
|
||||
./$(DEPDIR)/dummy.Po ./$(DEPDIR)/handlers.Po \
|
||||
./$(DEPDIR)/hash_tests.Po ./$(DEPDIR)/memcheck.Po \
|
||||
./$(DEPDIR)/minicheck.Po ./$(DEPDIR)/misc_tests.Po \
|
||||
./$(DEPDIR)/ns_tests.Po ./$(DEPDIR)/nsalloc_tests.Po \
|
||||
./$(DEPDIR)/props_tests.Po ./$(DEPDIR)/runtests.Po \
|
||||
./$(DEPDIR)/structdata.Po ./$(DEPDIR)/xcs_tests.Po
|
||||
./$(DEPDIR)/dummy.Po ./$(DEPDIR)/entities_tests.Po \
|
||||
./$(DEPDIR)/handlers.Po ./$(DEPDIR)/hash_tests.Po \
|
||||
./$(DEPDIR)/memcheck.Po ./$(DEPDIR)/minicheck.Po \
|
||||
./$(DEPDIR)/misc_tests.Po ./$(DEPDIR)/ns_tests.Po \
|
||||
./$(DEPDIR)/nsalloc_tests.Po ./$(DEPDIR)/props_tests.Po \
|
||||
./$(DEPDIR)/runtests.Po ./$(DEPDIR)/structdata.Po \
|
||||
./$(DEPDIR)/xcs_tests.Po
|
||||
am__mv = mv -f
|
||||
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
|
||||
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
|
||||
@@ -650,6 +652,7 @@ runtests_SOURCES = \
|
||||
dummy.c \
|
||||
handlers.c \
|
||||
hash_tests.c \
|
||||
entities_tests.c \
|
||||
memcheck.c \
|
||||
minicheck.c \
|
||||
misc_tests.c \
|
||||
@@ -660,8 +663,8 @@ runtests_SOURCES = \
|
||||
structdata.c \
|
||||
xcs_tests.c
|
||||
|
||||
runtests_LDADD = ../lib/libtestpat.la
|
||||
runtests_LDFLAGS = @AM_LDFLAGS@ @LIBM@
|
||||
runtests_LDADD = ../lib/libtestpat.la @LIBM@
|
||||
runtests_LDFLAGS = @AM_LDFLAGS@
|
||||
EXTRA_DIST = \
|
||||
acc_tests.h \
|
||||
alloc_tests.h \
|
||||
@@ -671,6 +674,7 @@ EXTRA_DIST = \
|
||||
dummy.h \
|
||||
handlers.h \
|
||||
hash_tests.h \
|
||||
entities_tests.h \
|
||||
memcheck.h \
|
||||
minicheck.h \
|
||||
misc_tests.h \
|
||||
@@ -738,6 +742,7 @@ distclean-compile:
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/chardata.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dummy.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/entities_tests.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/handlers.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/hash_tests.Po@am__quote@ # am--include-marker
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/memcheck.Po@am__quote@ # am--include-marker
|
||||
@@ -1184,6 +1189,7 @@ distclean: distclean-recursive
|
||||
-rm -f ./$(DEPDIR)/chardata.Po
|
||||
-rm -f ./$(DEPDIR)/common.Po
|
||||
-rm -f ./$(DEPDIR)/dummy.Po
|
||||
-rm -f ./$(DEPDIR)/entities_tests.Po
|
||||
-rm -f ./$(DEPDIR)/handlers.Po
|
||||
-rm -f ./$(DEPDIR)/hash_tests.Po
|
||||
-rm -f ./$(DEPDIR)/memcheck.Po
|
||||
@@ -1246,6 +1252,7 @@ maintainer-clean: maintainer-clean-recursive
|
||||
-rm -f ./$(DEPDIR)/chardata.Po
|
||||
-rm -f ./$(DEPDIR)/common.Po
|
||||
-rm -f ./$(DEPDIR)/dummy.Po
|
||||
-rm -f ./$(DEPDIR)/entities_tests.Po
|
||||
-rm -f ./$(DEPDIR)/handlers.Po
|
||||
-rm -f ./$(DEPDIR)/hash_tests.Po
|
||||
-rm -f ./$(DEPDIR)/memcheck.Po
|
||||
|
||||
@@ -475,6 +475,37 @@ START_TEST(test_amplification_isolated_external_parser) {
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_amplification_reset_neutrality) {
|
||||
// Speed up the test, chunk size expected to not matter in this test
|
||||
if (g_chunkSize != 0)
|
||||
return;
|
||||
|
||||
const char *const doc
|
||||
= "<!DOCTYPE r [<!ENTITY e 'general entity'>]><r>&e;</r>";
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
assert_true(XML_SetPropertyDouble(
|
||||
parser, XML_PROP_BILLION_LAUGHS_MAXIMUM_AMPLIFICATION, 1.0)
|
||||
== XML_PROP_ERROR_NONE);
|
||||
assert_true(XML_SetPropertyUInt64(
|
||||
parser, XML_PROP_BILLION_LAUGHS_ACTIVATION_THRESHOLD, 0)
|
||||
== XML_PROP_ERROR_NONE);
|
||||
|
||||
assert_true(_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc),
|
||||
/*isFinal=*/XML_TRUE)
|
||||
== XML_STATUS_ERROR);
|
||||
assert_true(XML_GetErrorCode(parser) == XML_ERROR_AMPLIFICATION_LIMIT_BREACH);
|
||||
|
||||
assert_true(XML_ParserReset(parser, NULL) == XML_STATUS_OK);
|
||||
|
||||
assert_true(_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc),
|
||||
/*isFinal=*/XML_TRUE)
|
||||
== XML_STATUS_ERROR);
|
||||
assert_true(XML_GetErrorCode(parser) == XML_ERROR_AMPLIFICATION_LIMIT_BREACH);
|
||||
|
||||
XML_ParserFree(parser);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
#endif // XML_GE == 1
|
||||
|
||||
void
|
||||
@@ -491,6 +522,7 @@ make_accounting_test_case(Suite *s) {
|
||||
tcase_add_test(tc_accounting, test_helper_unsigned_char_to_printable);
|
||||
tcase_add_test__ifdef_xml_dtd(tc_accounting,
|
||||
test_amplification_isolated_external_parser);
|
||||
tcase_add_test(tc_accounting, test_amplification_reset_neutrality);
|
||||
#else
|
||||
UNUSED_P(s);
|
||||
#endif /* XML_GE == 1 */
|
||||
|
||||
@@ -2330,6 +2330,47 @@ START_TEST(test_alloc_tracker_api_float_round_trip) {
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_alloc_tracker_reset_neutrality) {
|
||||
// Speed up the test, chunk size expected to not matter in this test
|
||||
if (g_chunkSize != 0)
|
||||
return;
|
||||
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
|
||||
const char *const small = "<hello/>";
|
||||
|
||||
// Create a document that drives `parser->m_alloc_tracker.bytesAllocated`
|
||||
// towards the activation threshold
|
||||
#if XML_GE == 1
|
||||
const size_t bigSizeBytes
|
||||
= (size_t)(1.1f * EXPAT_ALLOC_TRACKER_ACTIVATION_THRESHOLD_DEFAULT);
|
||||
const char *const before = "<doc a='";
|
||||
const char *const after = "'/>";
|
||||
char *const big = malloc(bigSizeBytes);
|
||||
assert_true(big != NULL);
|
||||
memset(big, 'X', bigSizeBytes);
|
||||
memcpy(big, before, strlen(before)); // without zero terminator
|
||||
strcpy(big + (bigSizeBytes - strlen(after) - 1),
|
||||
after); // with zero terminator
|
||||
assert_true(strlen(big) == bigSizeBytes - 1); // self-test
|
||||
|
||||
assert_true(
|
||||
_XML_Parse_SINGLE_BYTES(parser, big, strlen(big), /*isFinal=*/XML_TRUE)
|
||||
== XML_STATUS_OK);
|
||||
|
||||
free(big);
|
||||
#endif // XML_GE == 1
|
||||
|
||||
XML_ParserReset(parser, NULL);
|
||||
|
||||
assert_true(_XML_Parse_SINGLE_BYTES(parser, small, strlen(small),
|
||||
/*isFinal=*/XML_TRUE)
|
||||
== XML_STATUS_OK);
|
||||
|
||||
XML_ParserFree(parser);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_mem_api_cycle) {
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
|
||||
@@ -2445,6 +2486,7 @@ make_alloc_test_case(Suite *s) {
|
||||
tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_getbuffer_unlimited);
|
||||
tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_api);
|
||||
tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_api_float_round_trip);
|
||||
tcase_add_test__if_xml_ge(tc_alloc, test_alloc_tracker_reset_neutrality);
|
||||
|
||||
tcase_add_test(tc_alloc, test_mem_api_cycle);
|
||||
tcase_add_test__if_xml_ge(tc_alloc, test_mem_api_unlimited);
|
||||
|
||||
+48
-15
@@ -27,6 +27,7 @@
|
||||
Copyright (c) 2026 Afonso Januário <afonso-januario@hotmail.com>
|
||||
Copyright (c) 2026 Braian Plaku <braianplaku@gmail.com>
|
||||
Copyright (c) 2026 Filippo Tedeschi <filippotedeschi98@gmail.com>
|
||||
Copyright (c) 2026 Alexander Bluhm <alexander.bluhm@gmx.net>
|
||||
Licensed under the MIT license:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
@@ -208,7 +209,8 @@ START_TEST(test_hash_collision) {
|
||||
* tests invoked from qa.sh usually provide a hash collision, but
|
||||
* not always. This is an attempt to provide insurance.
|
||||
*/
|
||||
#define COLLIDING_HASH_SALT (unsigned long)SIP_ULL(0xffffffffU, 0xff99fc90U)
|
||||
const uint8_t entropy[16] = {0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0x90, 0xfc, 0x99, 0xff, 0xff, 0xff, 0xff, 0xff};
|
||||
const char *text
|
||||
= "<doc>\n"
|
||||
"<a1/><a2/><a3/><a4/><a5/><a6/><a7/><a8/>\n"
|
||||
@@ -219,13 +221,12 @@ START_TEST(test_hash_collision) {
|
||||
"<d8>This triggers the table growth and collides with b2</d8>\n"
|
||||
"</doc>\n";
|
||||
|
||||
xmlSetHashSalt(g_parser, COLLIDING_HASH_SALT);
|
||||
XML_SetHashSalt16Bytes(g_parser, entropy);
|
||||
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
|
||||
== XML_STATUS_ERROR)
|
||||
xml_failure(g_parser);
|
||||
}
|
||||
END_TEST
|
||||
#undef COLLIDING_HASH_SALT
|
||||
|
||||
START_TEST(test_hash_salt_setter) {
|
||||
const uint8_t entropy[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
|
||||
@@ -251,6 +252,29 @@ START_TEST(test_hash_salt_setter) {
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_hash_salt_ulong) {
|
||||
const unsigned long salt = 0x12345678;
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
|
||||
// NULL parser should be rejected
|
||||
assert_true(xmlSetHashSalt(NULL, salt) == 0);
|
||||
|
||||
// salt 0 is ignored, but accepted
|
||||
assert_true(xmlSetHashSalt(parser, 0) == 1);
|
||||
|
||||
// Setting should be allowed more than once
|
||||
assert_true(xmlSetHashSalt(parser, salt) == 1);
|
||||
assert_true(xmlSetHashSalt(parser, salt) == 1);
|
||||
|
||||
// But not after parsing has started
|
||||
assert_true(XML_Parse(parser, "", 0, XML_FALSE /* isFinal */)
|
||||
== XML_STATUS_OK);
|
||||
assert_true(xmlSetHashSalt(parser, salt) == 0);
|
||||
|
||||
XML_ParserFree(parser);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Regression test for SF bug #491986. */
|
||||
START_TEST(test_danish_latin1) {
|
||||
const char *text = "<?xml version='1.0' encoding='iso-8859-1'?>\n"
|
||||
@@ -2743,12 +2767,13 @@ END_TEST
|
||||
|
||||
/* Test foreign DTD handling */
|
||||
START_TEST(test_set_foreign_dtd) {
|
||||
const uint8_t entropy[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8};
|
||||
const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n";
|
||||
const char *text2 = "<doc>&entity;</doc>";
|
||||
ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
|
||||
|
||||
/* Check hash salt is passed through too */
|
||||
xmlSetHashSalt(g_parser, 0x12345678);
|
||||
XML_SetHashSalt16Bytes(g_parser, entropy);
|
||||
XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
|
||||
XML_SetUserData(g_parser, &test_data);
|
||||
XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
|
||||
@@ -2767,7 +2792,7 @@ START_TEST(test_set_foreign_dtd) {
|
||||
!= XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING)
|
||||
fail("Failed to reject late foreign DTD setting");
|
||||
/* Ditto for the hash salt */
|
||||
if (xmlSetHashSalt(g_parser, 0x23456789))
|
||||
if (XML_SetHashSalt16Bytes(g_parser, entropy))
|
||||
fail("Failed to reject late hash salt change");
|
||||
|
||||
/* Now finish the parse */
|
||||
@@ -2812,13 +2837,14 @@ END_TEST
|
||||
|
||||
/* Test foreign DTD use with a doctype */
|
||||
START_TEST(test_foreign_dtd_with_doctype) {
|
||||
const uint8_t entropy[16] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8};
|
||||
const char *text1 = "<?xml version='1.0' encoding='us-ascii'?>\n"
|
||||
"<!DOCTYPE doc [<!ENTITY entity 'hello world'>]>\n";
|
||||
const char *text2 = "<doc>&entity;</doc>";
|
||||
ExtTest test_data = {"<!ELEMENT doc (#PCDATA)*>", NULL, NULL};
|
||||
|
||||
/* Check hash salt is passed through too */
|
||||
xmlSetHashSalt(g_parser, 0x12345678);
|
||||
XML_SetHashSalt16Bytes(g_parser, entropy);
|
||||
XML_SetParamEntityParsing(g_parser, XML_PARAM_ENTITY_PARSING_ALWAYS);
|
||||
XML_SetUserData(g_parser, &test_data);
|
||||
XML_SetExternalEntityRefHandler(g_parser, external_entity_loader);
|
||||
@@ -2837,7 +2863,7 @@ START_TEST(test_foreign_dtd_with_doctype) {
|
||||
!= XML_ERROR_CANT_CHANGE_FEATURE_ONCE_PARSING)
|
||||
fail("Failed to reject late foreign DTD setting");
|
||||
/* Ditto for the hash salt */
|
||||
if (xmlSetHashSalt(g_parser, 0x23456789))
|
||||
if (XML_SetHashSalt16Bytes(g_parser, entropy))
|
||||
fail("Failed to reject late hash salt change");
|
||||
|
||||
/* Now finish the parse */
|
||||
@@ -4402,17 +4428,23 @@ START_TEST(test_attribute_enum_value) {
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Slightly bizarrely, the library seems to silently ignore entity
|
||||
* definitions for predefined entities, even when they are wrong. The
|
||||
* language of the XML 1.0 spec is somewhat unhelpful as to what ought
|
||||
* to happen, so this is currently treated as acceptable.
|
||||
*/
|
||||
START_TEST(test_predefined_entity_redefinition) {
|
||||
// NOTE: This violates XML 1.0 fourth edition section
|
||||
// "4.6 Predefined Entities" (that demands rejection of bad
|
||||
// redefinitions) only for backwards-compatibility reasons.
|
||||
const char *text = "<!DOCTYPE doc [\n"
|
||||
"<!ENTITY apos 'foo'>\n"
|
||||
" <!ENTITY amp 'bad'>\n"
|
||||
" <!ENTITY apos 'bad'>\n"
|
||||
" <!ENTITY gt 'bad'>\n"
|
||||
" <!ENTITY lt 'bad'>\n"
|
||||
" <!ENTITY quot 'bad'>\n"
|
||||
"]>\n"
|
||||
"<doc>'</doc>";
|
||||
run_character_check(text, XCS("'"));
|
||||
"<doc>&'><"</doc>";
|
||||
run_character_check(text, XCS("&"
|
||||
"'"
|
||||
">"
|
||||
"<"
|
||||
"\""));
|
||||
}
|
||||
END_TEST
|
||||
|
||||
@@ -7154,6 +7186,7 @@ make_basic_test_case(Suite *s) {
|
||||
tcase_add_test(tc_basic, test_nobom_utf16_le);
|
||||
tcase_add_test(tc_basic, test_hash_collision);
|
||||
tcase_add_test(tc_basic, test_hash_salt_setter);
|
||||
tcase_add_test(tc_basic, test_hash_salt_ulong);
|
||||
tcase_add_test(tc_basic, test_illegal_utf8);
|
||||
tcase_add_test(tc_basic, test_utf8_auto_align);
|
||||
tcase_add_test(tc_basic, test_utf16);
|
||||
|
||||
@@ -339,3 +339,15 @@ portable_strndup(const char *s, size_t n) {
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
XML_Char *
|
||||
xcsdup_str(const char *s) {
|
||||
const size_t len = strlen(s);
|
||||
XML_Char *const buf = calloc(len + /*terminator*/ 1, sizeof(XML_Char));
|
||||
if (! buf)
|
||||
return NULL;
|
||||
XML_Char *t = buf;
|
||||
while (*s)
|
||||
*t++ = *s++;
|
||||
return buf;
|
||||
}
|
||||
@@ -140,4 +140,6 @@ extern void *duff_reallocator(void *ptr, size_t size);
|
||||
|
||||
extern char *portable_strndup(const char *s, size_t n);
|
||||
|
||||
extern XML_Char *xcsdup_str(const char *s);
|
||||
|
||||
#endif /* XML_COMMON_H */
|
||||
@@ -45,6 +45,9 @@
|
||||
#ifndef XML_DUMMY_H
|
||||
#define XML_DUMMY_H
|
||||
|
||||
#include "expat.h" // for XML_Content
|
||||
#include "expat_external.h" // for XMLCALL, XML_Char
|
||||
|
||||
#define DUMMY_START_DOCTYPE_HANDLER_FLAG (1UL << 0)
|
||||
#define DUMMY_END_DOCTYPE_HANDLER_FLAG (1UL << 1)
|
||||
#define DUMMY_ENTITY_DECL_HANDLER_FLAG (1UL << 2)
|
||||
|
||||
@@ -0,0 +1,246 @@
|
||||
/* Unit tests related to internal handling of entities
|
||||
__ __ _
|
||||
___\ \/ /_ __ __ _| |_
|
||||
/ _ \\ /| '_ \ / _` | __|
|
||||
| __// \| |_) | (_| | |_
|
||||
\___/_/\_\ .__/ \__,_|\__|
|
||||
|_| XML parser
|
||||
|
||||
Copyright (c) 2026 Sebastian Pipping <[email protected]>
|
||||
Licensed under the MIT license:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
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 "entities_tests.h"
|
||||
#include "expat_config.h" // for XML_GE
|
||||
|
||||
#include "ascii.h" // for ASCII_*
|
||||
#include "common.h" // for g_chunkSize, xcsdup_str
|
||||
#include "entities.h" // for isCDataCommentOrPIStart, isPredefinedEntityName, ..
|
||||
#include "xmltok.h" // for XML_TOK_*
|
||||
#include "xcs.h" // for xcslen
|
||||
|
||||
#include <string.h> // for strlen
|
||||
|
||||
static void
|
||||
assert_entity_expanded_size_equals(XML_Parser parser, const char *text,
|
||||
XmlBigCount expectedExpandedSize);
|
||||
|
||||
static void assert_predefined_entity_name_match(const char *text,
|
||||
int expectedCharacter);
|
||||
|
||||
static ENTITY *createGeneralEntityWithText(const char *text);
|
||||
|
||||
START_TEST(test_is_cdata_comment_or_pi_start) {
|
||||
// Speed up the test, chunk size expected to not matter in this test
|
||||
if (g_chunkSize != 0)
|
||||
return;
|
||||
|
||||
XML_Char *const cdataOpen = xcsdup_str("<![CDATA[");
|
||||
XML_Char *const commentOpen = xcsdup_str("<!--");
|
||||
XML_Char *const piOpen = xcsdup_str("<?");
|
||||
|
||||
#if XML_GE == 1
|
||||
const size_t expectedCdataOpenLen = xcslen(cdataOpen);
|
||||
const size_t expectedCommentOpenLen = xcslen(commentOpen);
|
||||
const size_t expectedPiOpenLen = xcslen(piOpen);
|
||||
|
||||
size_t actualCdataOpenLen = 0;
|
||||
assert_true(isCDataCommentOrPIStart(cdataOpen, expectedCdataOpenLen,
|
||||
&actualCdataOpenLen)
|
||||
== XML_TOK_CDATA_SECT_OPEN);
|
||||
assert_true(actualCdataOpenLen == expectedCdataOpenLen);
|
||||
|
||||
size_t actualCommentOpenLen = 0;
|
||||
assert_true(isCDataCommentOrPIStart(commentOpen, expectedCommentOpenLen,
|
||||
&actualCommentOpenLen)
|
||||
== XML_TOK_COMMENT);
|
||||
assert_true(actualCommentOpenLen == expectedCommentOpenLen);
|
||||
|
||||
size_t actualPiOpenLen = 0;
|
||||
assert_true(
|
||||
isCDataCommentOrPIStart(piOpen, expectedPiOpenLen, &actualPiOpenLen)
|
||||
== XML_TOK_PI);
|
||||
assert_true(actualCdataOpenLen == expectedCdataOpenLen);
|
||||
|
||||
size_t dummy = 0;
|
||||
assert_true(isCDataCommentOrPIStart(piOpen, 0, &dummy) == XML_TOK_INVALID);
|
||||
assert_true(isCDataCommentOrPIStart(piOpen, 1, &dummy) == XML_TOK_INVALID);
|
||||
#endif // XML_GE == 1
|
||||
|
||||
free(cdataOpen);
|
||||
free(commentOpen);
|
||||
free(piOpen);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static void
|
||||
assert_predefined_entity_name_match(const char *text, int expectedCharacter) {
|
||||
XML_Char *const xcsText = xcsdup_str(text);
|
||||
assert_true(xcsText != NULL);
|
||||
|
||||
#if XML_GE == 1
|
||||
assert_true(isPredefinedEntityName(xcsText, xcslen(xcsText))
|
||||
== expectedCharacter);
|
||||
#else
|
||||
UNUSED_P(expectedCharacter);
|
||||
#endif // XML_GE == 1
|
||||
|
||||
free(xcsText);
|
||||
}
|
||||
|
||||
START_TEST(test_is_predefined_entity_name) {
|
||||
// Speed up the test, chunk size expected to not matter in this test
|
||||
if (g_chunkSize != 0)
|
||||
return;
|
||||
|
||||
assert_predefined_entity_name_match("amp", ASCII_AMP);
|
||||
assert_predefined_entity_name_match("apos", ASCII_APOS);
|
||||
assert_predefined_entity_name_match("gt", ASCII_GT);
|
||||
assert_predefined_entity_name_match("lt", ASCII_LT);
|
||||
assert_predefined_entity_name_match("quot", ASCII_QUOT);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static ENTITY *
|
||||
createGeneralEntityWithText(const char *text) {
|
||||
assert_true(text != NULL);
|
||||
|
||||
ENTITY *const entity = calloc(1, sizeof(ENTITY));
|
||||
assert_true(entity != NULL);
|
||||
|
||||
entity->textPtr = xcsdup_str(text);
|
||||
assert_true(entity->textPtr != NULL);
|
||||
|
||||
entity->textLen = xcslen(entity->textPtr);
|
||||
|
||||
#if XML_GE == 1
|
||||
entity->scanPtr = entity->textPtr;
|
||||
#endif // XML_GE == 1
|
||||
|
||||
return entity;
|
||||
}
|
||||
|
||||
static void
|
||||
assert_entity_expanded_size_equals(XML_Parser parser, const char *text,
|
||||
XmlBigCount expectedExpandedSize) {
|
||||
// Turn `text` into a general entity with that text
|
||||
ENTITY *const entity = createGeneralEntityWithText(text);
|
||||
|
||||
#if XML_GE == 1
|
||||
XmlBigCount actualExpandedSize = 0;
|
||||
assert_true(scanEntityText(parser, entity, &entity->scanPtr,
|
||||
&actualExpandedSize, NULL)
|
||||
== ENTITY_SCAN_COMPLETE);
|
||||
assert_true(entity->scanPtr == entity->textPtr + entity->textLen);
|
||||
assert_true(actualExpandedSize == expectedExpandedSize);
|
||||
#else
|
||||
UNUSED_P(parser);
|
||||
UNUSED_P(expectedExpandedSize);
|
||||
#endif // XML_GE == 1
|
||||
|
||||
free((XML_Char *)entity->textPtr);
|
||||
free(entity);
|
||||
}
|
||||
|
||||
START_TEST(test_scan_entity_text) {
|
||||
// Speed up the test, chunk size expected to not matter in this test
|
||||
if (g_chunkSize != 0)
|
||||
return;
|
||||
|
||||
const char *const doc = "<!DOCTYPE doc[\n"
|
||||
" <!ENTITY ten '123456789a'>\n"
|
||||
"]>\n"
|
||||
"<doc/>";
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
assert_true(parser != NULL);
|
||||
assert_true(_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc),
|
||||
/*isFinal=*/XML_TRUE)
|
||||
== XML_STATUS_OK);
|
||||
|
||||
assert_entity_expanded_size_equals(parser, "", 0);
|
||||
assert_entity_expanded_size_equals(parser, "123", 3);
|
||||
assert_entity_expanded_size_equals(parser, "&'><"",
|
||||
strlen("&'><"") + 5);
|
||||
assert_entity_expanded_size_equals(parser, "&undefined;",
|
||||
strlen("&undefined;"));
|
||||
|
||||
// Extract entity "ten" and set its `.expandedSize` so that we can scan text
|
||||
// that refers to "&ten;" without blocking
|
||||
#if XML_GE == 1
|
||||
ENTITY *entityTen = NULL;
|
||||
#endif
|
||||
{
|
||||
ENTITY *const entityReferencingTen
|
||||
= createGeneralEntityWithText("referencing &ten;");
|
||||
assert_true(entityReferencingTen != NULL);
|
||||
|
||||
#if XML_GE == 1
|
||||
assert_true(scanEntityText(parser, entityReferencingTen,
|
||||
&entityReferencingTen->scanPtr,
|
||||
&entityReferencingTen->expandedSize, &entityTen)
|
||||
== ENTITY_SCAN_BLOCKED);
|
||||
assert_true(entityTen != NULL);
|
||||
assert_true(entityReferencingTen->expandedSize == strlen("referencing "));
|
||||
assert_true(entityReferencingTen->scanPtr
|
||||
== entityReferencingTen->textPtr
|
||||
+ entityReferencingTen->expandedSize);
|
||||
XML_Char *const ten = xcsdup_str("ten");
|
||||
assert_true(xcscmp(entityTen->name, ten) == 0);
|
||||
free(ten);
|
||||
|
||||
entityTen->expandedSize = 10; // which makes it stop being a blocker
|
||||
#endif // XML_GE == 1
|
||||
|
||||
free((XML_Char *)entityReferencingTen->textPtr);
|
||||
free(entityReferencingTen);
|
||||
}
|
||||
|
||||
assert_entity_expanded_size_equals(parser, "&ten;",
|
||||
strlen("&ten;") + strlen("123456789a"));
|
||||
assert_entity_expanded_size_equals(
|
||||
parser, "[&ten;&ten;|&ten;]",
|
||||
3 * (strlen("&ten;") + strlen("123456789a")) + strlen("[|]"));
|
||||
|
||||
// Cases where no entities should be recognized
|
||||
assert_entity_expanded_size_equals(
|
||||
parser, "<![CDATA[&ten;]]><!--&ten;--><?php &ten;?>",
|
||||
strlen("<![CDATA[&ten;]]><!--&ten;--><?php &ten;?>"));
|
||||
assert_entity_expanded_size_equals(parser, "<![CDATA[&ten;",
|
||||
strlen("<![CDATA[&ten;"));
|
||||
assert_entity_expanded_size_equals(parser, "<!--&ten;", strlen("<!--&ten;"));
|
||||
assert_entity_expanded_size_equals(parser, "<?php &ten;",
|
||||
strlen("<?php &ten;"));
|
||||
|
||||
XML_ParserFree(parser);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void
|
||||
make_entities_test_case(Suite *s) {
|
||||
TCase *const tc_entities = tcase_create("entities tests");
|
||||
suite_add_tcase(s, tc_entities);
|
||||
tcase_add_test(tc_entities, test_is_cdata_comment_or_pi_start);
|
||||
tcase_add_test(tc_entities, test_is_predefined_entity_name);
|
||||
tcase_add_test(tc_entities, test_scan_entity_text);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/* Unit tests related to internal handling of entities
|
||||
__ __ _
|
||||
___\ \/ /_ __ __ _| |_
|
||||
/ _ \\ /| '_ \ / _` | __|
|
||||
| __// \| |_) | (_| | |_
|
||||
\___/_/\_\ .__/ \__,_|\__|
|
||||
|_| XML parser
|
||||
|
||||
Copyright (c) 2026 Sebastian Pipping <[email protected]>
|
||||
Licensed under the MIT license:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
persons to whom the Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
|
||||
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||
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 XML_ENTITIES_TESTS_H
|
||||
#define XML_ENTITIES_TESTS_H
|
||||
|
||||
#include "minicheck.h"
|
||||
|
||||
extern void make_entities_test_case(Suite *s);
|
||||
|
||||
#endif /* XML_ENTITIES_TESTS_H */
|
||||
@@ -51,6 +51,7 @@
|
||||
#include "expat_config.h"
|
||||
|
||||
#include "expat.h"
|
||||
#include "chardata.h"
|
||||
|
||||
/* Variable holding the expected handler userData */
|
||||
extern const void *g_handler_data;
|
||||
|
||||
+180
-1
@@ -25,6 +25,7 @@
|
||||
Copyright (c) 2026 Evgeny Kotkov <[email protected]>
|
||||
Copyright (c) 2026 Darren Carreras <[email protected]>
|
||||
Copyright (c) 2026 Junki Lee <[email protected]>
|
||||
Copyright (c) 2026 Pu Cheng <[email protected]>
|
||||
Licensed under the MIT license:
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
@@ -60,6 +61,7 @@
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "dummy.h" // for dummy_start_element
|
||||
#include "expat.h"
|
||||
#include "internal.h"
|
||||
#include "minicheck.h"
|
||||
@@ -222,7 +224,7 @@ START_TEST(test_misc_version) {
|
||||
if (! versions_equal(&read_version, &parsed_version))
|
||||
fail("Version mismatch");
|
||||
|
||||
if (xcscmp(version_text, XCS("expat_2.9.0"))
|
||||
if (xcscmp(version_text, XCS("expat_2.10.0"))
|
||||
!= 0) /* needs bump on releases */
|
||||
fail("XML_*_VERSION in expat.h out of sync?\n");
|
||||
}
|
||||
@@ -591,6 +593,26 @@ START_TEST(test_misc_stopparser_rejects_unstarted_parser) {
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static void *
|
||||
nonzero_filling_malloc(size_t size) {
|
||||
void *const ptr = malloc(size);
|
||||
if (ptr != NULL)
|
||||
memset(ptr, 0xA5, size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
START_TEST(test_misc_parsing_status_of_unstarted_parser) {
|
||||
XML_Memory_Handling_Suite memsuite = {nonzero_filling_malloc, realloc, free};
|
||||
XML_Parser parser = XML_ParserCreate_MM(NULL, &memsuite, NULL);
|
||||
assert_true(parser != NULL);
|
||||
XML_ParsingStatus status = {.parsing = XML_PARSING, .finalBuffer = XML_TRUE};
|
||||
XML_GetParsingStatus(parser, &status);
|
||||
assert_true(status.parsing == XML_INITIALIZED);
|
||||
assert_true(status.finalBuffer == XML_FALSE);
|
||||
XML_ParserFree(parser);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
/* Adaptation of accumulate_characters that takes ExtHdlrData input to work with
|
||||
* test_renter_loop_finite_content below */
|
||||
void XMLCALL
|
||||
@@ -1024,6 +1046,159 @@ START_TEST(test_misc_input_2gb) {
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static void
|
||||
dummy_start_doctype(void *userData, const XML_Char *name,
|
||||
const XML_Char *systemId, const XML_Char *publicId,
|
||||
int has_internal_subset) {
|
||||
UNUSED_P(userData);
|
||||
UNUSED_P(name);
|
||||
UNUSED_P(systemId);
|
||||
UNUSED_P(publicId);
|
||||
UNUSED_P(has_internal_subset);
|
||||
}
|
||||
|
||||
static int
|
||||
reset_start_doctype_decl_handler_not_standalone(void *userData) {
|
||||
XML_Parser parser = userData;
|
||||
XML_SetStartDoctypeDeclHandler(parser, NULL);
|
||||
return XML_STATUS_OK;
|
||||
}
|
||||
|
||||
START_TEST(test_misc_start_doctype_decl_handler_reset) {
|
||||
// Speed up the test, chunk size expected to not matter in this test
|
||||
if (g_chunkSize != 0)
|
||||
return;
|
||||
|
||||
const char *const doc = "<!DOCTYPE r SYSTEM \"s\"><r/>";
|
||||
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
|
||||
XML_SetUserData(parser, parser);
|
||||
XML_SetStartDoctypeDeclHandler(parser, dummy_start_doctype);
|
||||
XML_SetNotStandaloneHandler(parser,
|
||||
reset_start_doctype_decl_handler_not_standalone);
|
||||
|
||||
assert_true(_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc),
|
||||
/*isFinal=*/XML_TRUE)
|
||||
== XML_STATUS_OK);
|
||||
|
||||
XML_ParserFree(parser);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_misc_storeatts_attssize_allocation) {
|
||||
// Speed up the test, chunk size expected to not matter in this test
|
||||
if (g_chunkSize != 0)
|
||||
return;
|
||||
|
||||
// NOTE: This has 17 attributes defined because `INIT_ATTS_SIZE` is 16.
|
||||
// Array size is calculated as
|
||||
// parser->m_attsSize = n + nDefaultAtts + INIT_ATTS_SIZE
|
||||
// when I expected it would have needed to be
|
||||
// parser->m_attsSize = n + 2 * nDefaultAtts + INIT_ATTS_SIZE .
|
||||
// Please see the in-code comments in `storeAtts` for the black magic
|
||||
// that makes it work nonetheless. The same memory is used as an array
|
||||
// of `ATTRIBUTE` elements first, and then as an array of `XML_Char *`
|
||||
// elements after.
|
||||
const char *const doc = "<!DOCTYPE doc [\n"
|
||||
" <!ELEMENT doc EMPTY>\n"
|
||||
" <!ATTLIST doc\n"
|
||||
" a01 CDATA '01'\n"
|
||||
" a02 CDATA '02'\n"
|
||||
" a03 CDATA '03'\n"
|
||||
" a04 CDATA '04'\n"
|
||||
" a05 CDATA '05'\n"
|
||||
" a06 CDATA '06'\n"
|
||||
" a07 CDATA '07'\n"
|
||||
" a08 CDATA '08'\n"
|
||||
" a09 CDATA '09'\n"
|
||||
" a10 CDATA '10'\n"
|
||||
" a11 CDATA '11'\n"
|
||||
" a12 CDATA '12'\n"
|
||||
" a13 CDATA '13'\n"
|
||||
" a14 CDATA '14'\n"
|
||||
" a15 CDATA '15'\n"
|
||||
" a16 CDATA '16'\n"
|
||||
" a17 CDATA '17'\n"
|
||||
" >\n"
|
||||
"]>\n"
|
||||
"<doc/>\n";
|
||||
|
||||
init_dummy_handlers();
|
||||
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
XML_SetStartElementHandler(
|
||||
parser, dummy_start_element); // i.e. ask for calling `storeAtts`
|
||||
assert_true(_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc),
|
||||
/*isFinal=*/XML_TRUE));
|
||||
XML_ParserFree(parser);
|
||||
|
||||
assert_true(get_dummy_handler_flags() == DUMMY_START_ELEMENT_HANDLER_FLAG);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static void
|
||||
comparingPiHandler(void *userData, const XML_Char *target,
|
||||
const XML_Char *data) {
|
||||
UNUSED_P(userData);
|
||||
|
||||
XML_Char *const literalTarget = xcsdup_str("target");
|
||||
XML_Char *const literalData = xcsdup_str("data");
|
||||
assert_true(literalTarget != NULL);
|
||||
assert_true(literalData != NULL);
|
||||
|
||||
assert_true(xcscmp(target, literalTarget) == 0);
|
||||
assert_true(xcscmp(data, literalData) == 0);
|
||||
|
||||
free(literalTarget);
|
||||
free(literalData);
|
||||
}
|
||||
|
||||
static int XMLCALL
|
||||
piParsingExternalEntityHandler(XML_Parser parent, const XML_Char *context,
|
||||
const XML_Char *base, const XML_Char *systemId,
|
||||
const XML_Char *publicId) {
|
||||
UNUSED_P(base);
|
||||
UNUSED_P(systemId);
|
||||
UNUSED_P(publicId);
|
||||
|
||||
const char *const doc = "<?target data?>";
|
||||
|
||||
XML_Parser subParser = XML_ExternalEntityParserCreate(parent, context, NULL);
|
||||
assert_true(subParser != NULL);
|
||||
|
||||
// NOTE: Related test "test_empty_ext_param_entity_in_value" could be of
|
||||
// interest
|
||||
assert_true(_XML_Parse_SINGLE_BYTES(subParser, "", 0, /*isFinal=*/XML_FALSE)
|
||||
== XML_STATUS_OK);
|
||||
assert_true(_XML_Parse_SINGLE_BYTES(subParser, doc, (int)strlen(doc),
|
||||
/*isFinal=*/XML_TRUE)
|
||||
== XML_STATUS_OK);
|
||||
|
||||
XML_ParserFree(subParser);
|
||||
|
||||
return XML_STATUS_OK;
|
||||
}
|
||||
|
||||
START_TEST(test_misc_empty_nonfinal_subparser_parse) {
|
||||
const char *const doc = "<!DOCTYPE root [\n"
|
||||
" <!ENTITY ext SYSTEM 'external.dtd'>\n"
|
||||
"]>\n"
|
||||
"<root>&ext;</root>\n";
|
||||
|
||||
XML_Parser parser = XML_ParserCreate(NULL);
|
||||
assert_true(parser != NULL);
|
||||
|
||||
XML_SetProcessingInstructionHandler(parser, comparingPiHandler);
|
||||
XML_SetExternalEntityRefHandler(parser, piParsingExternalEntityHandler);
|
||||
|
||||
assert_true(_XML_Parse_SINGLE_BYTES(parser, doc, (int)strlen(doc),
|
||||
/*isFinal=*/XML_TRUE));
|
||||
|
||||
XML_ParserFree(parser);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void
|
||||
make_miscellaneous_test_case(Suite *s) {
|
||||
TCase *tc_misc = tcase_create("miscellaneous tests");
|
||||
@@ -1050,6 +1225,7 @@ make_miscellaneous_test_case(Suite *s) {
|
||||
tcase_add_test(tc_misc, test_misc_char_handler_stop_without_leak);
|
||||
tcase_add_test(tc_misc, test_misc_resumeparser_not_crashing);
|
||||
tcase_add_test(tc_misc, test_misc_stopparser_rejects_unstarted_parser);
|
||||
tcase_add_test(tc_misc, test_misc_parsing_status_of_unstarted_parser);
|
||||
tcase_add_test__if_xml_ge(tc_misc, test_renter_loop_finite_content);
|
||||
tcase_add_test(tc_misc, test_misc_expected_event_ptr_issue_980);
|
||||
tcase_add_test(tc_misc, test_misc_sync_entity_tolerated);
|
||||
@@ -1064,4 +1240,7 @@ make_miscellaneous_test_case(Suite *s) {
|
||||
test_misc_unknown_encoding_release_getter_parser_reset);
|
||||
tcase_add_test(tc_misc, test_misc_input_2gb);
|
||||
tcase_add_test(tc_misc, test_misc_low_surrogate_mozilla_bug_2053153);
|
||||
tcase_add_test(tc_misc, test_misc_storeatts_attssize_allocation);
|
||||
tcase_add_test(tc_misc, test_misc_start_doctype_decl_handler_reset);
|
||||
tcase_add_test(tc_misc, test_misc_empty_nonfinal_subparser_parse);
|
||||
}
|
||||
@@ -57,6 +57,7 @@
|
||||
#include "acc_tests.h"
|
||||
#include "alloc_tests.h"
|
||||
#include "basic_tests.h"
|
||||
#include "entities_tests.h"
|
||||
#include "hash_tests.h"
|
||||
#include "misc_tests.h"
|
||||
#include "ns_tests.h"
|
||||
@@ -75,6 +76,7 @@ make_suite(void) {
|
||||
#endif
|
||||
make_alloc_test_case(s);
|
||||
make_basic_test_case(s);
|
||||
make_entities_test_case(s);
|
||||
make_hash_test_case(s);
|
||||
make_miscellaneous_test_case(s);
|
||||
make_namespace_test_case(s);
|
||||
|
||||
@@ -76,6 +76,28 @@ START_TEST(test_xcs_ncmp) {
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_xcs_nstr) {
|
||||
if (g_chunkSize != 0)
|
||||
return;
|
||||
|
||||
const XML_Char haystack[] = {ASCII_h, ASCII_a, ASCII_y, ASCII_s, ASCII_t,
|
||||
ASCII_a, ASCII_c, ASCII_k, '\0'};
|
||||
const XML_Char hay[] = {ASCII_h, ASCII_a, ASCII_y, '\0'};
|
||||
const XML_Char stack[] = {ASCII_s, ASCII_t, ASCII_a, ASCII_c, ASCII_k, '\0'};
|
||||
const XML_Char other[] = {ASCII_o, ASCII_t, ASCII_h, ASCII_e, ASCII_r, '\0'};
|
||||
|
||||
assert_true(xcsnstr(haystack, haystack, xcslen(haystack)) == haystack);
|
||||
assert_true(xcsnstr(haystack, hay, xcslen(haystack)) == haystack);
|
||||
assert_true(xcsnstr(haystack, hay, xcslen(hay)) == haystack);
|
||||
assert_true(xcsnstr(haystack, hay, xcslen(hay) - 1) == NULL);
|
||||
assert_true(xcsnstr(haystack, stack, xcslen(haystack))
|
||||
== haystack + xcslen(hay));
|
||||
assert_true(xcsnstr(haystack, other, xcslen(haystack)) == NULL);
|
||||
assert_true(xcsnstr(haystack, empty, xcslen(haystack)) == haystack);
|
||||
assert_true(xcsnstr(hay, haystack, xcslen(hay)) == NULL);
|
||||
}
|
||||
END_TEST
|
||||
|
||||
void
|
||||
make_xcs_test_case(Suite *s) {
|
||||
TCase *const tc_xcs = tcase_create("xcs tests");
|
||||
@@ -83,4 +105,5 @@ make_xcs_test_case(Suite *s) {
|
||||
tcase_add_test(tc_xcs, test_xcs_len);
|
||||
tcase_add_test(tc_xcs, test_xcs_cmp);
|
||||
tcase_add_test(tc_xcs, test_xcs_ncmp);
|
||||
tcase_add_test(tc_xcs, test_xcs_nstr);
|
||||
}
|
||||
+3
-2
@@ -7,6 +7,7 @@
|
||||
# |_| XML parser
|
||||
#
|
||||
# Copyright (c) 2017-2026 Sebastian Pipping <[email protected]>
|
||||
# Copyright (c) 2026 Funda Wang <[email protected]>
|
||||
# Licensed under the MIT license:
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
@@ -30,7 +31,7 @@
|
||||
|
||||
bin_PROGRAMS = xmlwf
|
||||
|
||||
xmlwf_LDADD = ../lib/libexpat.la
|
||||
xmlwf_LDADD = ../lib/libexpat.la @LIBM@
|
||||
xmlwf_SOURCES = \
|
||||
../lib/xcs.c \
|
||||
xmlwf.c \
|
||||
@@ -39,7 +40,7 @@ xmlwf_SOURCES = \
|
||||
@[email protected]
|
||||
|
||||
xmlwf_CPPFLAGS = @AM_CPPFLAGS@ -I$(srcdir)/../lib
|
||||
xmlwf_LDFLAGS = @AM_LDFLAGS@ @LIBM@
|
||||
xmlwf_LDFLAGS = @AM_LDFLAGS@
|
||||
|
||||
if MINGW
|
||||
if UNICODE
|
||||
|
||||
+3
-2
@@ -23,6 +23,7 @@
|
||||
# |_| XML parser
|
||||
#
|
||||
# Copyright (c) 2017-2026 Sebastian Pipping <[email protected]>
|
||||
# Copyright (c) 2026 Funda Wang <[email protected]>
|
||||
# Licensed under the MIT license:
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining
|
||||
@@ -378,7 +379,7 @@ target_alias = @target_alias@
|
||||
top_build_prefix = @top_build_prefix@
|
||||
top_builddir = @top_builddir@
|
||||
top_srcdir = @top_srcdir@
|
||||
xmlwf_LDADD = ../lib/libexpat.la
|
||||
xmlwf_LDADD = ../lib/libexpat.la @LIBM@
|
||||
xmlwf_SOURCES = \
|
||||
../lib/xcs.c \
|
||||
xmlwf.c \
|
||||
@@ -387,7 +388,7 @@ xmlwf_SOURCES = \
|
||||
@[email protected]
|
||||
|
||||
xmlwf_CPPFLAGS = @AM_CPPFLAGS@ -I$(srcdir)/../lib $(am__append_1)
|
||||
xmlwf_LDFLAGS = @AM_LDFLAGS@ @LIBM@ $(am__append_2)
|
||||
xmlwf_LDFLAGS = @AM_LDFLAGS@ $(am__append_2)
|
||||
EXTRA_DIST = \
|
||||
codepage.h \
|
||||
ct.c \
|
||||
|
||||
Reference in new issue
Block a user