Compare commits

..

No commits in common. "c8" and "c9-beta" have entirely different histories.
c8 ... c9-beta

2 changed files with 91 additions and 704 deletions

View File

@ -1,635 +0,0 @@
From 88e9daef8fdaea58da12044cd16f5c9c1f201bfa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Berkay=20Eren=20=C3=9Cr=C3=BCn?= <berkay.ueruen@siemens.com>
Date: Fri, 13 Mar 2026 13:26:45 +0100
Subject: [PATCH 1/6] Make "counting_start_element_handler" count default attrs
---
expat/tests/runtests.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c
index 4a0a2e3f..c66656e0 100644
--- a/expat/tests/runtests.c
+++ b/expat/tests/runtests.c
@@ -3045,6 +3045,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;
@@ -3089,7 +3090,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))
@@ -3122,9 +3123,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}};
+ ElementInfo info[] = {{XCS("doc"), 3, 0, XCS("id"), NULL},
+ {XCS("tag"), 1, 0, NULL, NULL},
+ {NULL, 0, 0, NULL, NULL}};
info[0].attributes = doc_info;
info[1].attributes = tag_info;
@@ -7111,7 +7112,7 @@ 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}};
+ ElementInfo info[] = {{XCS("foo"), 1, 0, NULL, NULL}, {NULL, 0, 0, NULL, NULL}};
info[0].attributes = doc_info;
XML_SetStartElementHandler(g_parser, counting_start_element_handler);
--
2.52.0
From 04796d5b0e71cc37a4bfa0031270d7bee6e0128a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Berkay=20Eren=20=C3=9Cr=C3=BCn?= <berkay.ueruen@siemens.com>
Date: Fri, 13 Mar 2026 13:27:31 +0100
Subject: [PATCH 2/6] test(attlist): Cover duplicate attribute names
Co-authored-by: Sebastian Pipping <sebastian@pipping.org>
---
expat/tests/runtests.c | 315 +++++++++++++++++++++++++++++++++++++++--
1 file changed, 302 insertions(+), 13 deletions(-)
diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c
index c66656e0..13583e0a 100644
--- a/expat/tests/runtests.c
+++ b/expat/tests/runtests.c
@@ -3059,7 +3059,9 @@ typedef struct StructParserAndElementInfo {
static void XMLCALL
counting_start_element_handler(void *userData, const XML_Char *name,
const XML_Char **atts) {
- ElementInfo *info = (ElementInfo *)userData;
+ ParserAndElementInfo *const parserAndElementInfos
+ = (ParserAndElementInfo *)userData;
+ ElementInfo *info = parserAndElementInfos->info;
AttrInfo *attr;
int count, id, i;
@@ -3076,17 +3078,17 @@ counting_start_element_handler(void *userData, const XML_Char *name,
* is possibly a little unexpected, but it is what the
* documentation in expat.h tells us to expect.
*/
- count = XML_GetSpecifiedAttributeCount(g_parser);
+ count = XML_GetSpecifiedAttributeCount(parserAndElementInfos->parser);
if (info->attr_count * 2 != count) {
fail("Not got expected attribute count");
return;
}
- id = XML_GetIdAttributeIndex(g_parser);
+ id = XML_GetIdAttributeIndex(parserAndElementInfos->parser);
if (id == -1 && info->id_name != NULL) {
fail("ID not present");
return;
}
- if (id != -1 && xcstrcmp(atts[id], info->id_name)) {
+ if (id != -1 && xcstrcmp(atts[id], info->id_name) != 0) {
fail("ID does not have the correct name");
return;
}
@@ -3101,7 +3103,7 @@ counting_start_element_handler(void *userData, const XML_Char *name,
fail("Attribute not recognised");
return;
}
- if (xcstrcmp(atts[1], attr->value)) {
+ if (xcstrcmp(atts[1], attr->value) != 0) {
fail("Attribute has wrong value");
return;
}
@@ -3123,20 +3125,296 @@ START_TEST(test_attributes) {
{XCS("id"), XCS("one")},
{NULL, NULL}};
AttrInfo tag_info[] = {{XCS("c"), XCS("3")}, {NULL, NULL}};
- ElementInfo info[] = {{XCS("doc"), 3, 0, XCS("id"), NULL},
- {XCS("tag"), 1, 0, NULL, NULL},
+ ElementInfo info[] = {{XCS("doc"), 3, 0, XCS("id"), doc_info},
+ {XCS("tag"), 1, 0, NULL, tag_info},
{NULL, 0, 0, NULL, NULL}};
- info[0].attributes = doc_info;
- info[1].attributes = tag_info;
+
+ ParserAndElementInfo parserAndElementInfos = {
+ g_parser,
+ info,
+ };
XML_SetStartElementHandler(g_parser, counting_start_element_handler);
- XML_SetUserData(g_parser, info);
+ XML_SetUserData(g_parser, &parserAndElementInfos);
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
== XML_STATUS_ERROR)
xml_failure(g_parser);
}
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
+ = "<!DOCTYPE doc [\n"
+ " <!ATTLIST doc attribute CDATA 'expected' attribute CDATA 'ignored'>\n"
+ "]>\n"
+ "<doc/>\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
+ = "<!DOCTYPE doc [\n"
+ " <!ATTLIST doc identifier CDATA 'expected' identifier ID #REQUIRED>\n"
+ "]>\n"
+ "<doc/>\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
+ = "<!DOCTYPE doc [\n"
+ " <!ATTLIST doc identifier ID #REQUIRED identifier CDATA 'unexpected'>\n"
+ "]>\n"
+ "<doc/>\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 = "<!DOCTYPE doc [\n"
+ " <!ATTLIST doc attribute CDATA 'expected'>\n"
+ " <!ATTLIST doc attribute CDATA 'ignored'>\n"
+ "]>\n"
+ "<doc/>\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 = "<!DOCTYPE doc [\n"
+ " <!ATTLIST doc attribute CDATA 'expected_doc'>\n"
+ " <!ATTLIST tag attribute CDATA 'expected_tag'>\n"
+ " <!ATTLIST doc attribute CDATA 'ignored_doc'>\n"
+ "]>\n"
+ "<doc><tag></tag></doc>\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
+ = "<!DOCTYPE doc [\n"
+ " <!ATTLIST doc attribute CDATA 'expected_doc'>\n"
+ " <!ATTLIST tag attribute CDATA 'expected_tag'>\n"
+ " <!ATTLIST doc second_attribute CDATA 'second_expected_doc' attribute CDATA 'ignored_doc'>\n"
+ "]>\n"
+ "<doc><tag></tag></doc>\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 = "<!DOCTYPE doc [\n"
+ " <!ATTLIST doc identifier ID #REQUIRED>\n"
+ " <!ATTLIST tag identifier CDATA 'identifier_tag'>\n"
+ " <!ATTLIST doc identifier CDATA 'ignored'>\n"
+ "]>\n"
+ "<doc identifier='doc_identity'><tag></tag></doc>\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().
*/
@@ -7112,11 +7390,13 @@ 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, 0, NULL, NULL}, {NULL, 0, 0, NULL, NULL}};
- info[0].attributes = doc_info;
+ ElementInfo info[]
+ = {{XCS("foo"), 1, 0, NULL, doc_info}, {NULL, 0, 0, NULL, NULL}};
+
+ ParserAndElementInfo parserAndElementInfos = {g_parser, info};
XML_SetStartElementHandler(g_parser, counting_start_element_handler);
- XML_SetUserData(g_parser, &info);
+ XML_SetUserData(g_parser, &parserAndElementInfos);
if (_XML_Parse_SINGLE_BYTES(g_parser, text, (int)strlen(text), XML_TRUE)
== XML_STATUS_ERROR)
@@ -13625,6 +13905,15 @@ make_suite(void) {
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(tc_basic, test_reset_in_entity);
tcase_add_test(tc_basic, test_resume_invalid_parse);
tcase_add_test(tc_basic, test_resume_resuspended);
--
2.52.0
From 58d4b742fd88c9789e4a5e68de02164145f9c593 Mon Sep 17 00:00:00 2001
From: Sebastian Pipping <sebastian@pipping.org>
Date: Mon, 13 Apr 2026 01:34:03 +0200
Subject: [PATCH 3/6] tests: Make counting_start_element_handler enforce
complete attribute lists
---
expat/tests/runtests.c | 3 +++
1 file changed, 3 insertions(+)
diff --git a/expat/tests/runtests.c b/expat/tests/runtests.c
index 13583e0a..659ed030 100644
--- a/expat/tests/runtests.c
+++ b/expat/tests/runtests.c
@@ -3110,6 +3110,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);
}
START_TEST(test_attributes) {
--
2.52.0
From 2f13a612e82242af9954508240c6edfaf7cb0721 Mon Sep 17 00:00:00 2001
From: Sebastian Pipping <sebastian@pipping.org>
Date: Sun, 8 Mar 2026 22:14:41 +0100
Subject: [PATCH 4/6] lib: Extract a constant for upcoming reuse
---
expat/lib/xmlparse.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
index cba41f4b..ac9512e9 100644
--- a/expat/lib/xmlparse.c
+++ b/expat/lib/xmlparse.c
@@ -7528,8 +7528,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
--
2.52.0
From 8211c5affe00c6d92025f34ae7ffbc0f78426692 Mon Sep 17 00:00:00 2001
From: Sebastian Pipping <sebastian@pipping.org>
Date: Sun, 8 Mar 2026 23:05:49 +0100
Subject: [PATCH 5/6] lib: Introduce ELEMENT_TYPE.defaultAttsNames
---
expat/lib/xmlparse.c | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
index ac9512e9..d8e7335d 100644
--- a/expat/lib/xmlparse.c
+++ b/expat/lib/xmlparse.c
@@ -368,6 +368,7 @@ typedef struct {
int nDefaultAtts;
int allocDefaultAtts;
DEFAULT_ATTRIBUTE *defaultAtts;
+ HASH_TABLE defaultAttsNames;
} ELEMENT_TYPE;
typedef struct {
@@ -3756,6 +3757,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;
}
@@ -7369,6 +7372,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);
}
@@ -7410,6 +7414,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);
}
@@ -7503,6 +7508,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
@@ -7539,6 +7548,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;
+ }
}
}
@@ -8263,6 +8278,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 {
--
2.52.0
From 756dfc0850eb52005366da45859b1bb80a80466e Mon Sep 17 00:00:00 2001
From: Sebastian Pipping <sebastian@pipping.org>
Date: Sun, 8 Mar 2026 23:06:29 +0100
Subject: [PATCH 6/6] lib: Leverage ELEMENT_TYPE.defaultAttsNames for attribute
collision detection
.. to resolve quadratic runtime behavior
---
expat/lib/xmlparse.c | 14 ++++++++++----
1 file changed, 10 insertions(+), 4 deletions(-)
diff --git a/expat/lib/xmlparse.c b/expat/lib/xmlparse.c
index d8e7335d..d7d815e8 100644
--- a/expat/lib/xmlparse.c
+++ b/expat/lib/xmlparse.c
@@ -7009,10 +7009,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;
}
@@ -7059,6 +7059,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;
}
--
2.52.0

View File

@ -1,11 +1,10 @@
%global unversion 2_5_0
Summary: An XML parser library
Name: expat
Version: %(echo %{unversion} | sed 's/_/./g')
Release: 2%{?dist}
Source: https://github.com/libexpat/libexpat/archive/R_%{unversion}.tar.gz#/expat-%{version}.tar.gz
Version: 2.5.0
Release: 6%{?dist}
Source: https://github.com/libexpat/libexpat/archive/R_2_5_0.tar.gz#/expat-%{version}.tar.gz
URL: https://libexpat.github.io/
VCS: git:https://github.com/libexpat/libexpat.git
License: MIT
BuildRequires: autoconf, libtool, xmlto, gcc-c++
BuildRequires: make
@ -23,11 +22,8 @@ Patch4: expat-2.5.0-CVE-2024-45492.patch
Patch5: expat-2.5.0-CVE-2024-50602.patch
# https://issues.redhat.com/browse/RHEL-57489
Patch6: expat-2.5.0-CVE-2024-8176.patch
# https://issues.redhat.com/browse/RHEL-114618
# https://issues.redhat.com/browse/RHEL-114643
Patch7: expat-2.5.0-CVE-2025-59375.patch
# https://issues.redhat.com/browse/RHEL-177979
# https://github.com/libexpat/libexpat/pull/1216
Patch8: expat-2.5.0-CVE-2026-45186.patch
%description
This is expat, the C library for parsing XML, written by James Clark. Expat
@ -54,7 +50,7 @@ The expat-static package contains the static version of the expat library.
Install it if you need to link statically with expat.
%prep
%setup -q -n libexpat-R_%{unversion}/expat
%setup -q -n libexpat-R_2_5_0/expat
pushd ..
%patch0 -p1 -b .CVE-2023-52425
%patch1 -p1 -b .CVE-2024-28757
@ -64,7 +60,6 @@ pushd ..
%patch5 -p1 -b .CVE-2024-50602
%patch6 -p1 -b .CVE-2024-8176
%patch7 -p1 -b .CVE-2025-59375
%patch8 -p1 -b .CVE-2026-45186
popd
sed -i 's/install-data-hook/do-nothing-please/' lib/Makefile.am
@ -74,21 +69,21 @@ sed -i 's/install-data-hook/do-nothing-please/' lib/Makefile.am
export CFLAGS="$RPM_OPT_FLAGS -fPIC"
export DOCBOOK_TO_MAN="xmlto man --skip-validation"
%configure
make %{?_smp_mflags}
%make_build
%install
make install DESTDIR=$RPM_BUILD_ROOT
%make_install
rm -f $RPM_BUILD_ROOT%{_libdir}/*.la
%check
bash -c "for i in {1..500000}; do printf AAAAAAAAAAAAAAAAAAAA >> achars.txt; done"
for testfile in ../testdata/largefiles/aaaaaa_*; do
first_part="$(sed 's/\(.*\)ACHARS.*/\1/g' $testfile)"
second_part="$(sed 's/.*ACHARS\(.*\)/\1/g' $testfile)"
printf "$first_part" > "$testfile"
cat achars.txt >> "$testfile"
printf "$second_part" >> "$testfile"
first_part="$(sed 's/\(.*\)ACHARS.*/\1/g' $testfile)"
second_part="$(sed 's/.*ACHARS\(.*\)/\1/g' $testfile)"
printf "$first_part" > "$testfile"
cat achars.txt >> "$testfile"
printf "$second_part" >> "$testfile"
done
make check
@ -96,7 +91,6 @@ make check
%ldconfig_scriptlets
%files
%{!?_licensedir:%global license %%doc}
%doc AUTHORS Changes
%license COPYING
%{_bindir}/*
@ -114,65 +108,50 @@ make check
%{_libdir}/lib*.a
%changelog
* Thu May 28 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2.5.0-2
- Fix CVE-2026-45186
- Resolves: RHEL-177979
* Wed Nov 19 2025 Tomas Korbar <tkorbar@redhat.com> - 2.5.0-1
- Rebase to version 2.5.0
* Tue Dec 02 2025 Tomas Korbar <tkorbar@redhat.com> - 2.5.0-6
- Fix CVE-2025-59375
- Resolves: RHEL-114618
- Resolves: RHEL-114643
* Mon Apr 07 2025 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-17
* Mon Mar 31 2025 Tomas Korbar <tkorbar@redhat.com> - 2.5.0-5
- Fix CVE-2024-8176
- Resolves: RHEL-57477
- Resolves: RHEL-57489
* Fri Nov 08 2024 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-16
* Thu Nov 07 2024 Tomas Korbar <tkorbar@redhat.com> - 2.5.0-4
- Fix CVE-2024-50602
- Resolves: RHEL-65062
- Resolves: RHEL-65066
* Wed Sep 11 2024 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-15
- Rebuild for test reconfiguration
* Wed Oct 09 2024 Tomas Korbar <tkorbar@redhat.com> - 2.5.0-3
- Fix CVE-2024-45490, CVE-2024-45491, CVE-2024-45492
- Resolves: RHEL-56761
- Resolves: RHEL-57520
- Resolves: RHEL-57511
* Wed Sep 11 2024 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-14
- Fix multiple CVEs
- Fix CVE-2024-45492 integer overflow
- Fix CVE-2024-45491 Integer Overflow or Wraparound
- Fix CVE-2024-45490 Negative Length Parsing Vulnerability
- Resolves: RHEL-57505
- Resolves: RHEL-57493
- Resolves: RHEL-56751
* Tue Feb 13 2024 Tomas Korbar <tkorbar@redhat.com> - 2.5.0-2
- Fix parsing of large tokens
- Reject direct parameter entity recursion
- Resolves: RHEL-29699
- Resolves: RHEL-29696
* Tue Mar 26 2024 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-13
- Fix wrongly exposed variables
- Resolves: RHEL-29321
* Thu Mar 21 2024 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-12
- CVE-2023-52425 expat: parsing large tokens can trigger a denial of service
- Resolves: RHEL-29321
* Mon Nov 14 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-11
- CVE-2022-43680 expat: use-after free caused by overeager destruction of a shared DTD in XML_ExternalEntityParserCreate
* Thu Nov 10 2022 Tomas Korbar <tkorbar@redhat.com> - 2.5.0-1
- Rebase to version 2.5.0
- Resolves: CVE-2022-43680
* Fri Sep 30 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-10
- Ensure raw tagnames are safe exiting internalEntityParser
* Thu Sep 29 2022 Tomas Korbar <tkorbar@redhat.com> - 2.4.9-1
- Rebase to version 2.4.9
- Resolves: CVE-2022-40674
* Fri May 06 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-9
- Fix multiple CVEs
- Resolves: CVE-2022-25314
* Tue Apr 26 2022 Tomas Korbar <tkorbar@redhat.com> - 2.4.7-1
- Rebase to version 2.4.7
- Resolves: rhbz#2067201
- Resolves: CVE-2022-25313
- Resolves: CVE-2022-25314
- Resolves: CVE-2022-25236
* Mon Mar 14 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-8
- Improve patch for CVE-2022-25236
* Mon Mar 14 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.10-11
- Improve fix for CVE-2022-25236
- Related: CVE-2022-25236
* Fri Mar 04 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-7
- Fix patch for CVE-2022-25235
- Resolves: CVE-2022-25235
* Thu Mar 03 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-6
* Mon Feb 28 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.10-10
- Fix multiple CVEs
- CVE-2022-25236 expat: namespace-separator characters in "xmlns[:prefix]" attribute values can lead to arbitrary code execution
- CVE-2022-25235 expat: malformed 2- and 3-byte UTF-8 sequences can lead to arbitrary code execution
@ -181,20 +160,25 @@ make check
- Resolves: CVE-2022-25235
- Resolves: CVE-2022-25315
* Fri Feb 14 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.5-5
- Fix multiple CVEs
* Thu Feb 10 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.10-9
- CVE-2022-23852 expat: integer overflow in function XML_GetBuffer
- Resolves: CVE-2022-23852
* Thu Feb 10 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.10-8
- CVE-2021-45960 expat: Large number of prefixed XML attributes on a single tag can crash libexpat
- Resolves: CVE-2021-45960
* Wed Feb 09 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.10-7
- CVE-2021-46143 expat: Integer overflow in doProlog in xmlparse.c
- Resolves: CVE-2021-46143
* Wed Feb 09 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.10-6
- CVE-2022-22827 Integer overflow in storeAtts in xmlparse.c
- CVE-2022-22826 Integer overflow in nextScaffoldPart in xmlparse.c
- CVE-2022-22825 Integer overflow in lookup in xmlparse.c
- CVE-2022-22824 Integer overflow in defineAttribute in xmlparse.c
- CVE-2022-22823 Integer overflow in build_model in xmlparse.c
- CVE-2022-22822 Integer overflow in addBinding in xmlparse.c
- Resolves: CVE-2022-23852
- Resolves: CVE-2021-45960
- Resolves: CVE-2021-46143
- Resolves: CVE-2022-22827
- Resolves: CVE-2022-22826
- Resolves: CVE-2022-22825
@ -202,8 +186,46 @@ make check
- Resolves: CVE-2022-22823
- Resolves: CVE-2022-22822
* Fri Apr 24 2020 Joe Orton <jorton@redhat.com> - 2.2.5-4
- add security fixes for CVE-2018-20843, CVE-2019-15903
* Mon Feb 07 2022 Tomas Korbar <tkorbar@redhat.com> - 2.2.10-5
- CVE-2022-23990 expat: integer overflow in the doProlog function
- Resolve: rhbz#2050503
* Mon Aug 09 2021 Mohan Boddu <mboddu@redhat.com> - 2.2.10-4
- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags
Related: rhbz#1991688
* Thu Apr 15 2021 Mohan Boddu <mboddu@redhat.com> - 2.2.10-3
- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937
* Tue Jan 26 2021 Fedora Release Engineering <releng@fedoraproject.org> - 2.2.10-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
* Fri Nov 13 2020 Joe Orton <jorton@redhat.com> - 2.2.10-1
- update to 2.2.10 (#1884940)
* Mon Jul 27 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.2.8-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
* Tue Jan 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.2.8-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
* Mon Sep 16 2019 Joe Orton <jorton@redhat.com> - 2.2.8-1
- update to 2.2.8 (#1752167)
* Thu Jul 25 2019 Fedora Release Engineering <releng@fedoraproject.org> - 2.2.7-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
* Thu Jun 27 2019 Joe Orton <jorton@redhat.com> - 2.2.7-1
- update to 2.2.7 (#1723724, #1722224)
* Thu Jan 31 2019 Fedora Release Engineering <releng@fedoraproject.org> - 2.2.6-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
* Wed Aug 15 2018 Joe Orton <jorton@redhat.com> - 2.2.6-1
- update to 2.2.6
* Fri Jul 13 2018 Fedora Release Engineering <releng@fedoraproject.org> - 2.2.5-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
* Wed Feb 07 2018 Fedora Release Engineering <releng@fedoraproject.org> - 2.2.5-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_28_Mass_Rebuild