From nobody Wed May 20 03:00:25 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4gKx9p4mzPz6f1MS for ; Wed, 20 May 2026 03:00:30 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R13" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4gKx9p4Jlxz3Mvl for ; Wed, 20 May 2026 03:00:30 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1779246030; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Tg0Q3zA2LqM0HZ2uYaT0KglLvv1JDYZ6ReOBdqpuvYY=; b=HpmNnyMBH4pBU8zcaMUlMP9dZImE3ytrsVC2mj4PHfm9Lr/zuIFBc32x+18Bgex09Ptz7I 5k/6cH4Faw9EDt2OvR3AD0vAL2mJWd9nv8pmVtk35pFlaGm3f4/TGyTnlyW+E1KwNJArLk g10OBVnKwFLNonUwyMpjCV33yKypEAC77RF50VJgReQyD1R8dCBYe66xydVghaHSitGxx5 bczOikuuvFgobJvab9XH7nSIsCVdhF0gcKMmYMh47ueBA2MLmLFqHNgX9cClRdiSmPhEKr eNrMwYTxFdmN11f2JWIgC7c3yaSlFe/Go8zn/GQFXwwXDfj6Q3dSXf9axS3ydQ== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1779246030; a=rsa-sha256; cv=none; b=f3VPg9GYlKOvj/6Gr1LTz+oCbhjVGWKZ/yxaQZW17sgjpF1aF7m5qvzMW0/WWlTtHxGC6X oBt46bj7scRZcIZMulDI3s7iGJXr8GevXrJw7YBxnI3PmMXIawISiiGKBud4QO3oc11xIL +sW2bzXyfaz70s+0KeAqwySGNoWoSLPqnJlw81omHTJBsD91FqKsvahzeLLjVe0F6nFOay MsnveL9hSKA/sQt8frPLCuhBJDoAskUZsfWjiybtOOg+SKhG4vRRijx8QEokxExTQznnnO lkdjj7eOsxEaKXcW5aZ5HU0mciv4Q/dUW6qSAAGjVi9mYgvV+M6xxDSNmSMwBw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1779246030; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Tg0Q3zA2LqM0HZ2uYaT0KglLvv1JDYZ6ReOBdqpuvYY=; b=o3tslPkgP8rxEI0fBiPBtVvjun1obe18VnzreSMAPu33zqDp+LR4mPgBwsIfz/2mIB+/2E +C2rH782ENTIVek8vzf0MEX0N2tSb6SjZsdo9yYATriFr2YGFNdMDTe9wejBI4w4dVLBmi InOyC7Q2m/Dtrxf6kM4Z0OQpEEPDRpK8c2LVoZpTsN3+jM+hfXIz4UfWHPqEcQoQKgoWpi UcIZ2Cb3cYn1ZmWgLu5VUpVgxI/owZktjyyTSwbrKI5cEgn5od2Tz5mdEfgpKRdVp7r1hg dq0W8nGAFr+DSroqs7iTZpX/r26O/EtdnJZizEZ8wERjJHElWllnziYXq3a3Hg== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4gKx9p3w5Qzk4f for ; Wed, 20 May 2026 03:00:30 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 3e41b by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Wed, 20 May 2026 03:00:25 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Philip Paeps Subject: git: 659a27e48969 - stable/15 - contrib/expat: import expat 2.8.1 List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: philip X-Git-Repository: src X-Git-Refname: refs/heads/stable/15 X-Git-Reftype: branch X-Git-Commit: 659a27e48969f49a1b737791a14c2cc6a1626d00 Auto-Submitted: auto-generated Date: Wed, 20 May 2026 03:00:25 +0000 Message-Id: <6a0d23c9.3e41b.189820d1@gitrepo.freebsd.org> The branch stable/15 has been updated by philip: URL: https://cgit.FreeBSD.org/src/commit/?id=659a27e48969f49a1b737791a14c2cc6a1626d00 commit 659a27e48969f49a1b737791a14c2cc6a1626d00 Author: Philip Paeps AuthorDate: 2026-05-13 03:17:00 +0000 Commit: Philip Paeps CommitDate: 2026-05-20 02:50:51 +0000 contrib/expat: import expat 2.8.1 Changes: https://github.com/libexpat/libexpat/blob/R_2_8_1/expat/Changes Security: CVE-2026-45186 (cherry picked from commit 9cc9b8b372842b9a941d235c5e9949a214e5284f) --- contrib/expat/Changes | 26 ++++ contrib/expat/README.md | 2 +- contrib/expat/configure.ac | 2 +- contrib/expat/doc/reference.html | 2 +- contrib/expat/doc/xmlwf.1 | 2 +- contrib/expat/doc/xmlwf.xml | 2 +- contrib/expat/lib/expat.h | 2 +- contrib/expat/lib/xmlparse.c | 36 ++++- contrib/expat/tests/alloc_tests.c | 4 +- contrib/expat/tests/basic_tests.c | 310 ++++++++++++++++++++++++++++++++++++-- contrib/expat/tests/common.c | 5 +- contrib/expat/tests/handlers.c | 34 +++-- contrib/expat/tests/handlers.h | 2 + contrib/expat/tests/memcheck.c | 6 +- contrib/expat/tests/minicheck.c | 10 +- contrib/expat/tests/misc_tests.c | 7 +- contrib/expat/tests/structdata.c | 7 +- contrib/expat/xmlwf/unixfilemap.c | 5 +- contrib/expat/xmlwf/xmlfile.c | 4 +- contrib/expat/xmlwf/xmlwf.c | 83 +++++----- lib/libexpat/expat_config.h | 6 +- lib/libexpat/libbsdxml.3 | 4 +- 22 files changed, 450 insertions(+), 111 deletions(-) diff --git a/contrib/expat/Changes b/contrib/expat/Changes index 87611eea5c01..313b3dc60cd0 100644 --- a/contrib/expat/Changes +++ b/contrib/expat/Changes @@ -29,6 +29,32 @@ !! THANK YOU! Sebastian Pipping -- Berlin, 2026-03-17 !! !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! +Release 2.8.1 Sun May 10 2026 + Security fixes: + #1216 CVE-2026-45186 -- Fix quadratic runtime from attribute name + collision checks that allowed denial of service attacks + through moderately sized crafted XML input (CWE-407). + Please note that a layer of compression around XML can + significantly reduce the minimum attack payload size. + + Other changes: + #1209 #1213 Drop more casts related to `void *` that C99 does not need + #1213 xmlwf: Streamline use of `mmap` + #1214 #1217 Version info bumped from 13:0:12 (libexpat*.so.1.12.0) + to 13:1:12 (libexpat*.so.1.12.1); see https://verbump.de/ + for what these numbers do + + Infrastructure: + #1210 CI: Cover compilation with Visual Studio 18 2026 on Windows + #1215 CI: Cover compilation for ARM64 on Windows + #1212 CI: Bump WASI SDK from 32 to 33 + + Special thanks to: + Berkay Eren Ürün + Matthew Fernandez + Nick Wellnhofer + Tania Somanna + Release 2.8.0 Fri April 24 2026 Security fixes: #47 #1183 CVE-2026-41080 -- The existing hash flooding protection diff --git a/contrib/expat/README.md b/contrib/expat/README.md index 619e60b2d16b..7a5ed463b6d5 100644 --- a/contrib/expat/README.md +++ b/contrib/expat/README.md @@ -11,7 +11,7 @@ > at the top of the `Changes` file. -# Expat, Release 2.8.0 +# Expat, Release 2.8.1 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/contrib/expat/configure.ac b/contrib/expat/configure.ac index 87633650f321..fb492dfd79f7 100644 --- a/contrib/expat/configure.ac +++ b/contrib/expat/configure.ac @@ -90,7 +90,7 @@ dnl If the API changes incompatibly set LIBAGE back to 0 dnl LIBCURRENT=13 # sync -LIBREVISION=0 # with +LIBREVISION=1 # with LIBAGE=12 # CMakeLists.txt! AC_CONFIG_HEADERS([expat_config.h]) diff --git a/contrib/expat/doc/reference.html b/contrib/expat/doc/reference.html index 195bd183fd82..07d331ed7b56 100644 --- a/contrib/expat/doc/reference.html +++ b/contrib/expat/doc/reference.html @@ -53,7 +53,7 @@

- The Expat XML Parser Release 2.8.0 + The Expat XML Parser Release 2.8.1

diff --git a/contrib/expat/doc/xmlwf.1 b/contrib/expat/doc/xmlwf.1 index 0736f110e3c1..12760944a5da 100644 --- a/contrib/expat/doc/xmlwf.1 +++ b/contrib/expat/doc/xmlwf.1 @@ -5,7 +5,7 @@ \\$2 \(la\\$1\(ra\\$3 .. .if \n(.g .mso www.tmac -.TH XMLWF 1 "April 24, 2026" "" "" +.TH XMLWF 1 "May 10, 2026" "" "" .SH NAME xmlwf \- Determines if an XML document is well-formed .SH SYNOPSIS diff --git a/contrib/expat/doc/xmlwf.xml b/contrib/expat/doc/xmlwf.xml index 3a3897750cb1..529dbba16722 100644 --- a/contrib/expat/doc/xmlwf.xml +++ b/contrib/expat/doc/xmlwf.xml @@ -21,7 +21,7 @@ "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd" [ Scott"> Bronson"> - April 24, 2026"> + May 10, 2026"> 1"> bronson@rinspin.com"> diff --git a/contrib/expat/lib/expat.h b/contrib/expat/lib/expat.h index 79c609f19aa4..ec3f58544cb0 100644 --- a/contrib/expat/lib/expat.h +++ b/contrib/expat/lib/expat.h @@ -1094,7 +1094,7 @@ XML_SetReparseDeferralEnabled(XML_Parser parser, XML_Bool enabled); */ # define XML_MAJOR_VERSION 2 # define XML_MINOR_VERSION 8 -# define XML_MICRO_VERSION 0 +# define XML_MICRO_VERSION 1 # ifdef __cplusplus } diff --git a/contrib/expat/lib/xmlparse.c b/contrib/expat/lib/xmlparse.c index 620d1e4b46e2..890a9389f15d 100644 --- a/contrib/expat/lib/xmlparse.c +++ b/contrib/expat/lib/xmlparse.c @@ -1,4 +1,4 @@ -/* a5d18f6a50f536615ac1c70304f87d94f99cc85a86b502188952440610ccf0f8 (2.8.0+) +/* 75ef4224f81c052e9e5aeea2ac7de75357d2169ff9908e39edc08b9dc3052513 (2.8.1+) __ __ _ ___\ \/ /_ __ __ _| |_ / _ \\ /| '_ \ / _` | __| @@ -387,6 +387,7 @@ typedef struct { int nDefaultAtts; int allocDefaultAtts; DEFAULT_ATTRIBUTE *defaultAtts; + HASH_TABLE defaultAttsNames; } ELEMENT_TYPE; typedef struct { @@ -3769,6 +3770,8 @@ storeAtts(XML_Parser parser, const ENCODING *enc, const char *attStr, sizeof(ELEMENT_TYPE)); if (! elementType) return XML_ERROR_NO_MEMORY; + if (! elementType->defaultAttsNames.parser) + hashTableInit(&(elementType->defaultAttsNames), parser); if (parser->m_ns && ! setElementTypePrefix(parser, elementType)) return XML_ERROR_NO_MEMORY; } @@ -7102,10 +7105,10 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata, if (value || isId) { /* The handling of default attributes gets messed up if we have a default which duplicates a non-default. */ - int i; - for (i = 0; i < type->nDefaultAtts; i++) - if (attId == type->defaultAtts[i].id) - return 1; + NAMED *const nameFound + = (NAMED *)lookup(parser, &(type->defaultAttsNames), attId->name, 0); + if (nameFound) + return 1; if (isId && ! type->idAtt && ! attId->xmlns) type->idAtt = attId; } @@ -7152,6 +7155,12 @@ defineAttribute(ELEMENT_TYPE *type, ATTRIBUTE_ID *attId, XML_Bool isCdata, att->isCdata = isCdata; if (! isCdata) attId->maybeTokenized = XML_TRUE; + + NAMED *const nameAddedOrFound = (NAMED *)lookup( + parser, &(type->defaultAttsNames), attId->name, sizeof(NAMED)); + if (! nameAddedOrFound) + return 0; + type->nDefaultAtts += 1; return 1; } @@ -7477,6 +7486,7 @@ dtdReset(DTD *p, XML_Parser parser) { ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter); if (! e) break; + hashTableDestroy(&(e->defaultAttsNames)); if (e->allocDefaultAtts != 0) FREE(parser, e->defaultAtts); } @@ -7518,6 +7528,7 @@ dtdDestroy(DTD *p, XML_Bool isDocEntity, XML_Parser parser) { ELEMENT_TYPE *e = (ELEMENT_TYPE *)hashTableIterNext(&iter); if (! e) break; + hashTableDestroy(&(e->defaultAttsNames)); if (e->allocDefaultAtts != 0) FREE(parser, e->defaultAtts); } @@ -7611,6 +7622,10 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, sizeof(ELEMENT_TYPE)); if (! newE) return 0; + + if (! newE->defaultAttsNames.parser) + hashTableInit(&(newE->defaultAttsNames), parser); + if (oldE->nDefaultAtts) { /* Detect and prevent integer overflow. * The preprocessor guard addresses the "always false" warning @@ -7635,8 +7650,9 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, newE->prefix = (PREFIX *)lookup(oldParser, &(newDtd->prefixes), oldE->prefix->name, 0); for (i = 0; i < newE->nDefaultAtts; i++) { + const XML_Char *const attributeName = oldE->defaultAtts[i].id->name; newE->defaultAtts[i].id = (ATTRIBUTE_ID *)lookup( - oldParser, &(newDtd->attributeIds), oldE->defaultAtts[i].id->name, 0); + oldParser, &(newDtd->attributeIds), attributeName, 0); newE->defaultAtts[i].isCdata = oldE->defaultAtts[i].isCdata; if (oldE->defaultAtts[i].value) { newE->defaultAtts[i].value @@ -7645,6 +7661,12 @@ dtdCopy(XML_Parser oldParser, DTD *newDtd, const DTD *oldDtd, return 0; } else newE->defaultAtts[i].value = NULL; + + NAMED *const nameAddedOrFound = (NAMED *)lookup( + parser, &(newE->defaultAttsNames), attributeName, sizeof(NAMED)); + if (! nameAddedOrFound) { + return 0; + } } } @@ -8391,6 +8413,8 @@ getElementType(XML_Parser parser, const ENCODING *enc, const char *ptr, sizeof(ELEMENT_TYPE)); if (! ret) return NULL; + if (! ret->defaultAttsNames.parser) + hashTableInit(&(ret->defaultAttsNames), getRootParserOf(parser, NULL)); if (ret->name != name) poolDiscard(&dtd->pool); else { diff --git a/contrib/expat/tests/alloc_tests.c b/contrib/expat/tests/alloc_tests.c index 5ae6c6a72025..433bf611808a 100644 --- a/contrib/expat/tests/alloc_tests.c +++ b/contrib/expat/tests/alloc_tests.c @@ -20,6 +20,7 @@ Copyright (c) 2021 Donghee Na Copyright (c) 2023 Sony Corporation / Snild Dolkow Copyright (c) 2025 Berkay Eren Ürün + Copyright (c) 2026 Matthew Fernandez Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -2136,8 +2137,7 @@ START_TEST(test_alloc_tracker_pointer_alignment) { XML_Parser parser = XML_ParserCreate(NULL); #if XML_GE == 1 assert_true(sizeof(long long) >= sizeof(size_t)); // self-test - long long *const ptr - = (long long *)expat_malloc(parser, 4 * sizeof(long long), -1); + long long *const ptr = expat_malloc(parser, 4 * sizeof(long long), -1); ptr[0] = 0LL; ptr[1] = 1LL; ptr[2] = 2LL; diff --git a/contrib/expat/tests/basic_tests.c b/contrib/expat/tests/basic_tests.c index 537c7e0e5a5c..b5088bcda988 100644 --- a/contrib/expat/tests/basic_tests.c +++ b/contrib/expat/tests/basic_tests.c @@ -19,8 +19,9 @@ Copyright (c) 2020 Tim Gates Copyright (c) 2021 Donghee Na Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow - Copyright (c) 2024-2025 Berkay Eren Ürün + Copyright (c) 2024-2026 Berkay Eren Ürün Copyright (c) 2026 Francesco Bertolaccini + Copyright (c) 2026 Matthew Fernandez Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -2491,11 +2492,9 @@ START_TEST(test_attributes) { {XCS("id"), XCS("one")}, {NULL, NULL}}; AttrInfo tag_info[] = {{XCS("c"), XCS("3")}, {NULL, NULL}}; - ElementInfo info[] = {{XCS("doc"), 3, XCS("id"), NULL}, - {XCS("tag"), 1, NULL, NULL}, - {NULL, 0, NULL, NULL}}; - info[0].attributes = doc_info; - info[1].attributes = tag_info; + ElementInfo info[] = {{XCS("doc"), 3, 0, XCS("id"), doc_info}, + {XCS("tag"), 1, 0, NULL, tag_info}, + {NULL, 0, 0, NULL, NULL}}; XML_Parser parser = XML_ParserCreate(NULL); assert_true(parser != NULL); @@ -2514,6 +2513,279 @@ START_TEST(test_attributes) { } END_TEST +START_TEST(test_duplicate_cdata_attribute) { + /* + https://www.w3.org/TR/xml/#attdecls + + Test the following statement from the linked specification: + When more than one definition is provided for the same attribute of a given + element type, the first declaration is binding and later declarations are + ignored. + */ + + const char *text + = "\n" + "]>\n" + "\n"; + AttrInfo doc_info[] = {{XCS("attribute"), XCS("expected")}, {NULL, NULL}}; + ElementInfo info[] + = {{XCS("doc"), 0, 1, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}}; + + XML_Parser parser = XML_ParserCreate(NULL); + assert_true(parser != NULL); + + ParserAndElementInfo parserAndElementInfos = { + parser, + info, + }; + + XML_SetStartElementHandler(parser, counting_start_element_handler); + XML_SetUserData(parser, &parserAndElementInfos); + + if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) + != XML_STATUS_OK) + xml_failure(parser); + + XML_ParserFree(parser); +} +END_TEST + +START_TEST(test_duplicate_id_attribute_1) { + /* + https://www.w3.org/TR/xml/#attdecls + + Test the following statement from the linked specification: + When more than one definition is provided for the same attribute of a given + element type, the first declaration is binding and later declarations are + ignored. + */ + + const char *text + = "\n" + "]>\n" + "\n"; + AttrInfo doc_info[] = {{XCS("identifier"), XCS("expected")}, {NULL, NULL}}; + ElementInfo info[] + = {{XCS("doc"), 0, 1, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}}; + + XML_Parser parser = XML_ParserCreate(NULL); + assert_true(parser != NULL); + + ParserAndElementInfo parserAndElementInfos = { + parser, + info, + }; + + XML_SetStartElementHandler(parser, counting_start_element_handler); + XML_SetUserData(parser, &parserAndElementInfos); + + if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) + != XML_STATUS_OK) + xml_failure(parser); + + XML_ParserFree(parser); +} +END_TEST + +START_TEST(test_duplicate_id_attribute_2) { + /* + https://www.w3.org/TR/xml/#attdecls + + Test the following statement from the linked specification: + When more than one definition is provided for the same attribute of a given + element type, the first declaration is binding and later declarations are + ignored. + */ + + const char *text + = "\n" + "]>\n" + "\n"; + AttrInfo doc_info[] = {{NULL, NULL}}; + + ElementInfo info[] + = {{XCS("doc"), 0, 0, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}}; + + XML_Parser parser = XML_ParserCreate(NULL); + assert_true(parser != NULL); + + ParserAndElementInfo parserAndElementInfos = { + parser, + info, + }; + + XML_SetStartElementHandler(parser, counting_start_element_handler); + XML_SetUserData(parser, &parserAndElementInfos); + + if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) + != XML_STATUS_OK) + xml_failure(parser); + + XML_ParserFree(parser); +} +END_TEST + +START_TEST(test_duplicate_cdata_attribute_multiple_attlistdecl) { + /* + https://www.w3.org/TR/xml/#attdecls + + Test the following statement from the linked specification: + When more than one AttlistDecl is provided for a given element type, + the contents of all those provided are merged. + */ + const char *text = "\n" + " \n" + "]>\n" + "\n"; + AttrInfo doc_info[] = {{XCS("attribute"), XCS("expected")}, {NULL, NULL}}; + ElementInfo info[] + = {{XCS("doc"), 0, 1, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}}; + + XML_Parser parser = XML_ParserCreate(NULL); + assert_true(parser != NULL); + + ParserAndElementInfo parserAndElementInfos = { + parser, + info, + }; + + XML_SetStartElementHandler(parser, counting_start_element_handler); + XML_SetUserData(parser, &parserAndElementInfos); + + if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) + != XML_STATUS_OK) + xml_failure(parser); + + XML_ParserFree(parser); +} +END_TEST + +START_TEST(test_duplicate_cdata_attribute_multiple_attlistdecl_2) { + /* + https://www.w3.org/TR/xml/#attdecls + + Test the following statement from the linked specification: + When more than one AttlistDecl is provided for a given element type, + the contents of all those provided are merged. + */ + const char *text = "\n" + " \n" + " \n" + "]>\n" + "\n"; + AttrInfo doc_info[] = {{XCS("attribute"), XCS("expected_doc")}, {NULL, NULL}}; + AttrInfo tag_info[] = {{XCS("attribute"), XCS("expected_tag")}, {NULL, NULL}}; + ElementInfo info[] = {{XCS("doc"), 0, 1, NULL, doc_info}, + {XCS("tag"), 0, 1, NULL, tag_info}, + {NULL, 0, 0, NULL, NULL}}; + + XML_Parser parser = XML_ParserCreate(NULL); + assert_true(parser != NULL); + + ParserAndElementInfo parserAndElementInfos = { + parser, + info, + }; + + XML_SetStartElementHandler(parser, counting_start_element_handler); + XML_SetUserData(parser, &parserAndElementInfos); + + if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) + != XML_STATUS_OK) + xml_failure(parser); + + XML_ParserFree(parser); +} +END_TEST + +START_TEST(test_duplicate_cdata_attribute_multiple_attlistdecl_3) { + /* + https://www.w3.org/TR/xml/#attdecls + + Test the following statement from the linked specification: + When more than one AttlistDecl is provided for a given element type, + the contents of all those provided are merged. + */ + const char *text + = "\n" + " \n" + " \n" + "]>\n" + "\n"; + AttrInfo doc_info[] = {{XCS("attribute"), XCS("expected_doc")}, + {XCS("second_attribute"), XCS("second_expected_doc")}, + {NULL, NULL}}; + AttrInfo tag_info[] = {{XCS("attribute"), XCS("expected_tag")}, {NULL, NULL}}; + ElementInfo info[] = {{XCS("doc"), 0, 2, NULL, doc_info}, + {XCS("tag"), 0, 1, NULL, tag_info}, + {NULL, 0, 0, NULL, NULL}}; + + XML_Parser parser = XML_ParserCreate(NULL); + assert_true(parser != NULL); + + ParserAndElementInfo parserAndElementInfos = { + parser, + info, + }; + + XML_SetStartElementHandler(parser, counting_start_element_handler); + XML_SetUserData(parser, &parserAndElementInfos); + + if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) + != XML_STATUS_OK) + xml_failure(parser); + + XML_ParserFree(parser); +} +END_TEST + +START_TEST(test_duplicate_id_attribute_multiple_attlistdecl) { + /* + https://www.w3.org/TR/xml/#attdecls + + Test the following statement from the linked specification: + When more than one AttlistDecl is provided for a given element type, + the contents of all those provided are merged. + */ + const char *text = "\n" + " \n" + " \n" + "]>\n" + "\n"; + AttrInfo doc_info[] + = {{XCS("identifier"), XCS("doc_identity")}, {NULL, NULL}}; + AttrInfo tag_info[] + = {{XCS("identifier"), XCS("identifier_tag")}, {NULL, NULL}}; + ElementInfo info[] = {{XCS("doc"), 1, 0, XCS("identifier"), doc_info}, + {XCS("tag"), 0, 1, NULL, tag_info}, + {NULL, 0, 0, NULL, NULL}}; + + XML_Parser parser = XML_ParserCreate(NULL); + assert_true(parser != NULL); + + ParserAndElementInfo parserAndElementInfos = { + parser, + info, + }; + + XML_SetStartElementHandler(parser, counting_start_element_handler); + XML_SetUserData(parser, &parserAndElementInfos); + + if (_XML_Parse_SINGLE_BYTES(parser, text, (int)strlen(text), XML_TRUE) + != XML_STATUS_OK) + xml_failure(parser); + + XML_ParserFree(parser); +} +END_TEST + /* Test reset works correctly in the middle of processing an internal * entity. Exercises some obscure code in XML_ParserReset(). */ @@ -3435,8 +3707,7 @@ external_bom_checker(XML_Parser parser, const XML_Char *context, fail("Could not create external entity parser"); if (! xcstrcmp(systemId, XCS("004-2.ent"))) { - struct bom_testdata *const testdata - = (struct bom_testdata *)XML_GetUserData(parser); + struct bom_testdata *const testdata = XML_GetUserData(parser); const char *const external = testdata->external; const int split = testdata->split; testdata->nested_callback_happened = XML_TRUE; @@ -5501,7 +5772,7 @@ START_TEST(test_deep_nested_entity) { const size_t N_LINES = 60000; const size_t SIZE_PER_LINE = 50; - char *const text = (char *)malloc((N_LINES + 4) * SIZE_PER_LINE); + char *const text = malloc((N_LINES + 4) * SIZE_PER_LINE); if (text == NULL) { fail("malloc failed"); } @@ -5547,7 +5818,7 @@ START_TEST(test_deep_nested_attribute_entity) { const size_t N_LINES = 60000; const size_t SIZE_PER_LINE = 100; - char *const text = (char *)malloc((N_LINES + 4) * SIZE_PER_LINE); + char *const text = malloc((N_LINES + 4) * SIZE_PER_LINE); if (text == NULL) { fail("malloc failed"); } @@ -5568,8 +5839,8 @@ START_TEST(test_deep_nested_attribute_entity) { (long unsigned)(N_LINES - 1)); AttrInfo doc_info[] = {{XCS("name"), XCS("deepText")}, {NULL, NULL}}; - ElementInfo info[] = {{XCS("foo"), 1, NULL, NULL}, {NULL, 0, NULL, NULL}}; - info[0].attributes = doc_info; + ElementInfo info[] + = {{XCS("foo"), 1, 0, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}}; XML_Parser parser = XML_ParserCreate(NULL); ParserAndElementInfo parserPlusElemenInfo = {parser, info}; @@ -5590,7 +5861,7 @@ START_TEST(test_deep_nested_entity_delayed_interpretation) { const size_t N_LINES = 70000; const size_t SIZE_PER_LINE = 100; - char *const text = (char *)malloc((N_LINES + 4) * SIZE_PER_LINE); + char *const text = malloc((N_LINES + 4) * SIZE_PER_LINE); if (text == NULL) { fail("malloc failed"); } @@ -6069,7 +6340,7 @@ START_TEST(test_bypass_heuristic_when_close_to_bufsize) { } const int document_length = 65536; - char *const document = (char *)malloc(document_length); + char *const document = malloc(document_length); assert_true(document != NULL); const XML_Memory_Handling_Suite memfuncs = { @@ -6180,7 +6451,7 @@ START_TEST(test_varying_buffer_fills) { return; // this test is slow, and doesn't use _XML_Parse_SINGLE_BYTES(). } - char *const document = (char *)malloc(document_length); + char *const document = malloc(document_length); assert_true(document != NULL); memset(document, 'x', document_length); document[0] = '<'; @@ -6400,6 +6671,15 @@ make_basic_test_case(Suite *s) { tcase_add_test__ifdef_xml_dtd(tc_basic, test_empty_foreign_dtd); tcase_add_test(tc_basic, test_set_base); tcase_add_test(tc_basic, test_attributes); + tcase_add_test(tc_basic, test_duplicate_cdata_attribute); + tcase_add_test(tc_basic, test_duplicate_id_attribute_1); + tcase_add_test(tc_basic, test_duplicate_id_attribute_2); + tcase_add_test(tc_basic, test_duplicate_cdata_attribute_multiple_attlistdecl); + tcase_add_test(tc_basic, + test_duplicate_cdata_attribute_multiple_attlistdecl_2); + tcase_add_test(tc_basic, + test_duplicate_cdata_attribute_multiple_attlistdecl_3); + tcase_add_test(tc_basic, test_duplicate_id_attribute_multiple_attlistdecl); tcase_add_test__if_xml_ge(tc_basic, test_reset_in_entity); tcase_add_test(tc_basic, test_resume_invalid_parse); tcase_add_test(tc_basic, test_resume_resuspended); diff --git a/contrib/expat/tests/common.c b/contrib/expat/tests/common.c index b2537d0deee1..389d61f00b3a 100644 --- a/contrib/expat/tests/common.c +++ b/contrib/expat/tests/common.c @@ -19,6 +19,7 @@ Copyright (c) 2020 Tim Gates Copyright (c) 2021 Donghee Na Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow + Copyright (c) 2026 Matthew Fernandez Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -261,7 +262,7 @@ _run_attribute_check(const char *text, const XML_Char *expected, void _run_ext_character_check(const char *text, ExtTest *test_data, const XML_Char *expected, const char *file, int line) { - CharData *const storage = (CharData *)malloc(sizeof(CharData)); + CharData *const storage = malloc(sizeof(CharData)); CharData_Init(storage); test_data->storage = storage; @@ -320,7 +321,7 @@ portable_strndup(const char *s, size_t n) { n = portable_strnlen(s, n); - char *const buffer = (char *)malloc(n + 1); + char *const buffer = malloc(n + 1); if (buffer == NULL) { errno = ENOMEM; return NULL; diff --git a/contrib/expat/tests/handlers.c b/contrib/expat/tests/handlers.c index e456df21c77c..cef04ed849b0 100644 --- a/contrib/expat/tests/handlers.c +++ b/contrib/expat/tests/handlers.c @@ -19,6 +19,8 @@ Copyright (c) 2020 Tim Gates Copyright (c) 2021 Donghee Na Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow + Copyright (c) 2026 Matthew Fernandez + Copyright (c) 2026 Berkay Eren Ürün Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -137,7 +139,7 @@ counting_start_element_handler(void *userData, const XML_Char *name, fail("ID does not have the correct name"); return; } - for (i = 0; i < info->attr_count; i++) { + for (i = 0; i < info->attr_count + info->default_attr_count; i++) { attr = info->attributes; while (attr->name != NULL) { if (! xcstrcmp(atts[0], attr->name)) @@ -155,6 +157,9 @@ counting_start_element_handler(void *userData, const XML_Char *name, /* Remember, two entries in atts per attribute (see above) */ atts += 2; } + + // Self-test that the test case's list of expected attributes is complete + assert_true(atts[0] == NULL); } void XMLCALL @@ -423,7 +428,7 @@ int XMLCALL external_entity_optioner(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { - ExtOption *options = (ExtOption *)XML_GetUserData(parser); + ExtOption *options = XML_GetUserData(parser); XML_Parser ext_parser; UNUSED_P(base); @@ -449,7 +454,7 @@ int XMLCALL external_entity_loader(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { - ExtTest *test_data = (ExtTest *)XML_GetUserData(parser); + ExtTest *test_data = XML_GetUserData(parser); XML_Parser extparser; UNUSED_P(base); @@ -477,7 +482,7 @@ external_entity_faulter(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { XML_Parser ext_parser; - ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser); + ExtFaults *fault = XML_GetUserData(parser); UNUSED_P(base); UNUSED_P(systemId); @@ -650,7 +655,7 @@ external_entity_suspending_faulter(XML_Parser parser, const XML_Char *context, const XML_Char *systemId, const XML_Char *publicId) { XML_Parser ext_parser; - ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser); + ExtFaults *fault = XML_GetUserData(parser); void *buffer; int parse_len = (int)strlen(fault->parse_text); @@ -981,7 +986,7 @@ external_entity_valuer(XML_Parser parser, const XML_Char *context, == XML_STATUS_ERROR) xml_failure(ext_parser); } else if (! xcstrcmp(systemId, XCS("004-2.ent"))) { - ExtFaults *fault = (ExtFaults *)XML_GetUserData(parser); + ExtFaults *fault = XML_GetUserData(parser); enum XML_Status status; enum XML_Error error; @@ -1083,7 +1088,7 @@ int XMLCALL external_entity_public(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { - const char *text1 = (const char *)XML_GetUserData(parser); + const char *text1 = XML_GetUserData(parser); const char *text2 = ""; const char *text = NULL; XML_Parser ext_parser; @@ -1139,7 +1144,7 @@ int XMLCALL external_entity_oneshot_loader(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { - ExtHdlrData *test_data = (ExtHdlrData *)XML_GetUserData(parser); + ExtHdlrData *test_data = XML_GetUserData(parser); XML_Parser ext_parser; UNUSED_P(base); @@ -1164,7 +1169,7 @@ int XMLCALL external_entity_loader2(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { - ExtTest2 *test_data = (ExtTest2 *)XML_GetUserData(parser); + ExtTest2 *test_data = XML_GetUserData(parser); XML_Parser extparser; UNUSED_P(base); @@ -1191,7 +1196,7 @@ int XMLCALL external_entity_faulter2(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { - ExtFaults2 *test_data = (ExtFaults2 *)XML_GetUserData(parser); + ExtFaults2 *test_data = XML_GetUserData(parser); XML_Parser extparser; UNUSED_P(base); @@ -1309,7 +1314,7 @@ int XMLCALL external_entity_dbl_handler(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { - int *pcallno = (int *)XML_GetUserData(parser); + int *pcallno = XML_GetUserData(parser); int callno = *pcallno; const char *text; XML_Parser new_parser = NULL; @@ -1366,7 +1371,7 @@ int XMLCALL external_entity_dbl_handler_2(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { - int *pcallno = (int *)XML_GetUserData(parser); + int *pcallno = XML_GetUserData(parser); int callno = *pcallno; const char *text; XML_Parser new_parser; @@ -1461,7 +1466,7 @@ int XMLCALL external_entity_alloc(XML_Parser parser, const XML_Char *context, const XML_Char *base, const XML_Char *systemId, const XML_Char *publicId) { - const char *text = (const char *)XML_GetUserData(parser); + const char *text = XML_GetUserData(parser); XML_Parser ext_parser; int parse_res; @@ -1516,8 +1521,7 @@ accounting_external_entity_ref_handler(XML_Parser parser, UNUSED_P(base); UNUSED_P(publicId); - const struct AccountingTestCase *const testCase - = (const struct AccountingTestCase *)XML_GetUserData(parser); + const struct AccountingTestCase *const testCase = XML_GetUserData(parser); const char *externalText = NULL; if (xcstrcmp(systemId, XCS("first.ent")) == 0) { diff --git a/contrib/expat/tests/handlers.h b/contrib/expat/tests/handlers.h index fcde27ae4940..be8f8931982c 100644 --- a/contrib/expat/tests/handlers.h +++ b/contrib/expat/tests/handlers.h @@ -19,6 +19,7 @@ Copyright (c) 2020 Tim Gates Copyright (c) 2021 Donghee Na Copyright (c) 2023 Sony Corporation / Snild Dolkow + Copyright (c) 2026 Berkay Eren Ürün Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -88,6 +89,7 @@ typedef struct attrInfo { typedef struct elementInfo { const XML_Char *name; int attr_count; + int default_attr_count; const XML_Char *id_name; AttrInfo *attributes; } ElementInfo; diff --git a/contrib/expat/tests/memcheck.c b/contrib/expat/tests/memcheck.c index de9254997214..2f43347e1717 100644 --- a/contrib/expat/tests/memcheck.c +++ b/contrib/expat/tests/memcheck.c @@ -9,6 +9,7 @@ Copyright (c) 2017 Rhodri James Copyright (c) 2017-2023 Sebastian Pipping Copyright (c) 2022 Sean McBride + Copyright (c) 2026 Matthew Fernandez Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -55,8 +56,7 @@ static AllocationEntry *find_allocation(const void *ptr); /* Allocate some memory and keep track of it. */ void * tracking_malloc(size_t size) { - AllocationEntry *const entry - = (AllocationEntry *)malloc(sizeof(AllocationEntry)); + AllocationEntry *const entry = malloc(sizeof(AllocationEntry)); if (entry == NULL) { printf("Allocator failure\n"); @@ -142,7 +142,7 @@ tracking_realloc(void *ptr, size_t size) { entry = find_allocation(ptr); if (entry == NULL) { printf("Attempting to realloc unallocated memory at %p\n", ptr); - entry = (AllocationEntry *)malloc(sizeof(AllocationEntry)); + entry = malloc(sizeof(AllocationEntry)); if (entry == NULL) { printf("Reallocator failure\n"); return NULL; diff --git a/contrib/expat/tests/minicheck.c b/contrib/expat/tests/minicheck.c index baccd76b4415..d452864e00fc 100644 --- a/contrib/expat/tests/minicheck.c +++ b/contrib/expat/tests/minicheck.c @@ -16,6 +16,7 @@ Copyright (c) 2018 Marco Maggi Copyright (c) 2019 David Loffredo Copyright (c) 2023-2024 Sony Corporation / Snild Dolkow + Copyright (c) 2026 Matthew Fernandez Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -54,7 +55,7 @@ Suite * suite_create(const char *name) { - Suite *suite = (Suite *)calloc(1, sizeof(Suite)); + Suite *suite = calloc(1, sizeof(Suite)); if (suite != NULL) { suite->name = name; } @@ -63,7 +64,7 @@ suite_create(const char *name) { TCase * tcase_create(const char *name) { - TCase *tc = (TCase *)calloc(1, sizeof(TCase)); + TCase *tc = calloc(1, sizeof(TCase)); if (tc != NULL) { tc->name = name; } @@ -94,8 +95,7 @@ tcase_add_test(TCase *tc, tcase_test_function test) { if (tc->allocated == tc->ntests) { int nalloc = tc->allocated + 100; size_t new_size = sizeof(tcase_test_function) * nalloc; - tcase_test_function *const new_tests - = (tcase_test_function *)realloc(tc->tests, new_size); + tcase_test_function *const new_tests = realloc(tc->tests, new_size); assert(new_tests != NULL); tc->tests = new_tests; tc->allocated = nalloc; @@ -130,7 +130,7 @@ suite_free(Suite *suite) { SRunner * srunner_create(Suite *suite) { - SRunner *const runner = (SRunner *)calloc(1, sizeof(SRunner)); + SRunner *const runner = calloc(1, sizeof(SRunner)); if (runner != NULL) { runner->suite = suite; } diff --git a/contrib/expat/tests/misc_tests.c b/contrib/expat/tests/misc_tests.c index 6d1a2f1488b0..015fb87295e6 100644 --- a/contrib/expat/tests/misc_tests.c +++ b/contrib/expat/tests/misc_tests.c @@ -20,6 +20,7 @@ Copyright (c) 2021 Donghee Na Copyright (c) 2023 Sony Corporation / Snild Dolkow Copyright (c) 2025 Berkay Eren Ürün + Copyright (c) 2026 Matthew Fernandez Licensed under the MIT license: Permission is hereby granted, free of charge, to any person obtaining @@ -212,7 +213,7 @@ START_TEST(test_misc_version) { if (! versions_equal(&read_version, &parsed_version)) fail("Version mismatch"); - if (xcstrcmp(version_text, XCS("expat_2.8.0")) + if (xcstrcmp(version_text, XCS("expat_2.8.1")) != 0) /* needs bump on releases */ fail("XML_*_VERSION in expat.h out of sync?\n"); } *** 421 LINES SKIPPED ***