Skip to content

Commit d8778a4

Browse files
committed
Merge commit 'de918d45e1b2276a28a4cd32bcf556bef65284e4'
2 parents 02336c7 + de918d4 commit d8778a4

File tree

17 files changed

+213
-14
lines changed

17 files changed

+213
-14
lines changed

NEWS

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,21 @@
11
NEWS file for libxml2
22

3+
v2.13.5: Nov 12 2024
4+
5+
### Regressions
6+
7+
- xmlIO: Fix reading from non-regular files like pipes (Nick Wellnhofer)
8+
- xmlreader: Fix return value of xmlTextReaderReadString (Nick Wellnhofer)
9+
- parser: Fix loading of parameter entities in external DTDs (Nick Wellnhofer)
10+
- parser: Fix downstream code that swaps DTDs (Nick Wellnhofer)
11+
- parser: Fix detection of duplicate attributes (Nick Wellnhofer)
12+
- string: Fix va_copy fallback (Nick Wellnhofer)
13+
14+
### Bug fixes
15+
16+
- xpath: Fix parsing of non-ASCII names (Nick Wellnhofer)
17+
18+
319
v2.13.4: Sep 18 2024
420

521
### Regressions

configure.ac

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ AC_PREREQ([2.63])
33

44
m4_define([MAJOR_VERSION], 2)
55
m4_define([MINOR_VERSION], 13)
6-
m4_define([MICRO_VERSION], 4)
6+
m4_define([MICRO_VERSION], 5)
77

88
AC_INIT([libxml2],[MAJOR_VERSION.MINOR_VERSION.MICRO_VERSION])
99
AC_CONFIG_SRCDIR([entities.c])

meson.build

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
project(
22
'libxml2',
33
'c',
4-
version: '2.13.4',
4+
version: '2.13.5',
55
license: 'MIT',
66
default_options: ['buildtype=debug', 'warning_level=3'],
77
meson_version: '>= 0.61',

parser.c

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8912,6 +8912,35 @@ xmlAttrHashInsert(xmlParserCtxtPtr ctxt, unsigned size, const xmlChar *name,
89128912
return(INT_MAX);
89138913
}
89148914

8915+
static int
8916+
xmlAttrHashInsertQName(xmlParserCtxtPtr ctxt, unsigned size,
8917+
const xmlChar *name, const xmlChar *prefix,
8918+
unsigned hashValue, int aindex) {
8919+
xmlAttrHashBucket *table = ctxt->attrHash;
8920+
xmlAttrHashBucket *bucket;
8921+
unsigned hindex;
8922+
8923+
hindex = hashValue & (size - 1);
8924+
bucket = &table[hindex];
8925+
8926+
while (bucket->index >= 0) {
8927+
const xmlChar **atts = &ctxt->atts[bucket->index];
8928+
8929+
if ((name == atts[0]) && (prefix == atts[1]))
8930+
return(bucket->index);
8931+
8932+
hindex++;
8933+
bucket++;
8934+
if (hindex >= size) {
8935+
hindex = 0;
8936+
bucket = table;
8937+
}
8938+
}
8939+
8940+
bucket->index = aindex;
8941+
8942+
return(INT_MAX);
8943+
}
89158944
/**
89168945
* xmlParseStartTag2:
89178946
* @ctxt: an XML parser context
@@ -8960,6 +8989,8 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref,
89608989
int nratts, nbatts, nbdef;
89618990
int i, j, nbNs, nbTotalDef, attval, nsIndex, maxAtts;
89628991
int alloc = 0;
8992+
int numNsErr = 0;
8993+
int numDupErr = 0;
89638994

89648995
if (RAW != '<') return(NULL);
89658996
NEXT1;
@@ -9338,10 +9369,12 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref,
93389369
if (res < INT_MAX) {
93399370
if (aprefix == atts[res+1]) {
93409371
xmlErrAttributeDup(ctxt, aprefix, attname);
9372+
numDupErr += 1;
93419373
} else {
93429374
xmlNsErr(ctxt, XML_NS_ERR_ATTRIBUTE_REDEFINED,
93439375
"Namespaced Attribute %s in '%s' redefined\n",
93449376
attname, nsuri, NULL);
9377+
numNsErr += 1;
93459378
}
93469379
}
93479380
}
@@ -9440,6 +9473,43 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref,
94409473
}
94419474
}
94429475

9476+
/*
9477+
* Using a single hash table for nsUri/localName pairs cannot
9478+
* detect duplicate QNames reliably. The following example will
9479+
* only result in two namespace errors.
9480+
*
9481+
* <doc xmlns:a="a" xmlns:b="a">
9482+
* <elem a:a="" b:a="" b:a=""/>
9483+
* </doc>
9484+
*
9485+
* If we saw more than one namespace error but no duplicate QNames
9486+
* were found, we have to scan for duplicate QNames.
9487+
*/
9488+
if ((numDupErr == 0) && (numNsErr > 1)) {
9489+
memset(ctxt->attrHash, -1,
9490+
attrHashSize * sizeof(ctxt->attrHash[0]));
9491+
9492+
for (i = 0, j = 0; j < nratts; i += 5, j++) {
9493+
unsigned hashValue, nameHashValue, prefixHashValue;
9494+
int res;
9495+
9496+
aprefix = atts[i+1];
9497+
if (aprefix == NULL)
9498+
continue;
9499+
9500+
attname = atts[i];
9501+
/* Hash values always have bit 31 set, see dict.c */
9502+
nameHashValue = ctxt->attallocs[j] | 0x80000000;
9503+
prefixHashValue = xmlDictComputeHash(ctxt->dict, aprefix);
9504+
9505+
hashValue = xmlDictCombineHash(nameHashValue, prefixHashValue);
9506+
res = xmlAttrHashInsertQName(ctxt, attrHashSize, attname,
9507+
aprefix, hashValue, i);
9508+
if (res < INT_MAX)
9509+
xmlErrAttributeDup(ctxt, aprefix, attname);
9510+
}
9511+
}
9512+
94439513
/*
94449514
* Reconstruct attribute pointers
94459515
*/
@@ -11763,6 +11833,7 @@ xmlIOParseDTD(xmlSAXHandlerPtr sax, xmlParserInputBufferPtr input,
1176311833
xmlFreeParserInputBuffer(input);
1176411834
return(NULL);
1176511835
}
11836+
xmlCtxtSetOptions(ctxt, XML_PARSE_DTDLOAD);
1176611837

1176711838
/*
1176811839
* generate a parser input from the I/O handler
@@ -11852,6 +11923,7 @@ xmlSAXParseDTD(xmlSAXHandlerPtr sax, const xmlChar *ExternalID,
1185211923
if (ctxt == NULL) {
1185311924
return(NULL);
1185411925
}
11926+
xmlCtxtSetOptions(ctxt, XML_PARSE_DTDLOAD);
1185511927

1185611928
/*
1185711929
* Canonicalise the system ID
@@ -12143,6 +12215,15 @@ xmlCtxtParseEntity(xmlParserCtxtPtr ctxt, xmlEntityPtr ent) {
1214312215

1214412216
while (list != NULL) {
1214512217
list->parent = (xmlNodePtr) ent;
12218+
12219+
/*
12220+
* Downstream code like the nginx xslt module can set
12221+
* ctxt->myDoc->extSubset to a separate DTD, so the entity
12222+
* might have a different or a NULL document.
12223+
*/
12224+
if (list->doc != ent->doc)
12225+
xmlSetTreeDoc(list, ent->doc);
12226+
1214612227
if (list->next == NULL)
1214712228
ent->last = list;
1214812229
list = list->next;

result/XPath/tests/unicodesimple

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
2+
========================
3+
Expression: /文書
4+
Object is a Node Set :
5+
Set contains 1 nodes:
6+
1 ELEMENT #E6#96#87#E6#9B#B8

result/errors/dup-xml-attr2.xml.ent

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
./test/errors/dup-xml-attr2.xml:2: namespace error : Namespaced Attribute a in 'urn:a' redefined
2+
<elem a:a="" b:a="" b:a=""/>
3+
^
4+
./test/errors/dup-xml-attr2.xml:2: namespace error : Namespaced Attribute a in 'urn:a' redefined
5+
<elem a:a="" b:a="" b:a=""/>
6+
^
7+
./test/errors/dup-xml-attr2.xml:2: parser error : Attribute b:a redefined
8+
<elem a:a="" b:a="" b:a=""/>
9+
^

result/errors/dup-xml-attr2.xml.err

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
./test/errors/dup-xml-attr2.xml:2: namespace error : Namespaced Attribute a in 'urn:a' redefined
2+
<elem a:a="" b:a="" b:a=""/>
3+
^
4+
./test/errors/dup-xml-attr2.xml:2: namespace error : Namespaced Attribute a in 'urn:a' redefined
5+
<elem a:a="" b:a="" b:a=""/>
6+
^
7+
./test/errors/dup-xml-attr2.xml:2: parser error : Attribute b:a redefined
8+
<elem a:a="" b:a="" b:a=""/>
9+
^

result/errors/dup-xml-attr2.xml.str

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
./test/errors/dup-xml-attr2.xml:2: namespace error : Namespaced Attribute a in 'urn:a' redefined
2+
<elem a:a="" b:a="" b:a=""/>
3+
^
4+
./test/errors/dup-xml-attr2.xml:2: namespace error : Namespaced Attribute a in 'urn:a' redefined
5+
<elem a:a="" b:a="" b:a=""/>
6+
^
7+
./test/errors/dup-xml-attr2.xml:2: parser error : Attribute b:a redefined
8+
<elem a:a="" b:a="" b:a=""/>
9+
^
10+
./test/errors/dup-xml-attr2.xml : failed to parse

test/XPath/docs/unicode

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<文書>text1</文書>

test/XPath/tests/unicodesimple

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/文書

test/errors/dup-xml-attr2.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
<doc xmlns:a="urn:a" xmlns:b="urn:a">
2+
<elem a:a="" b:a="" b:a=""/>
3+
</doc>

testparser.c

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,57 @@ testCFileIO(void) {
125125
return err;
126126
}
127127

128+
#ifdef LIBXML_VALID_ENABLED
129+
static void
130+
testSwitchDtdExtSubset(void *vctxt, const xmlChar *name ATTRIBUTE_UNUSED,
131+
const xmlChar *externalId ATTRIBUTE_UNUSED,
132+
const xmlChar *systemId ATTRIBUTE_UNUSED) {
133+
xmlParserCtxtPtr ctxt = vctxt;
134+
135+
ctxt->myDoc->extSubset = ctxt->_private;
136+
}
137+
138+
static int
139+
testSwitchDtd(void) {
140+
const char dtdContent[] =
141+
"<!ENTITY test '<elem1/><elem2/>'>\n";
142+
const char docContent[] =
143+
"<!DOCTYPE doc SYSTEM 'entities.dtd'>\n"
144+
"<doc>&test;</doc>\n";
145+
xmlParserInputBufferPtr input;
146+
xmlParserCtxtPtr ctxt;
147+
xmlDtdPtr dtd;
148+
xmlDocPtr doc;
149+
xmlEntityPtr ent;
150+
int err = 0;
151+
152+
input = xmlParserInputBufferCreateStatic(dtdContent,
153+
sizeof(dtdContent) - 1,
154+
XML_CHAR_ENCODING_NONE);
155+
dtd = xmlIOParseDTD(NULL, input, XML_CHAR_ENCODING_NONE);
156+
157+
ctxt = xmlNewParserCtxt();
158+
ctxt->_private = dtd;
159+
ctxt->sax->externalSubset = testSwitchDtdExtSubset;
160+
doc = xmlCtxtReadMemory(ctxt, docContent, sizeof(docContent) - 1, NULL,
161+
NULL, XML_PARSE_NOENT | XML_PARSE_DTDLOAD);
162+
xmlFreeParserCtxt(ctxt);
163+
164+
ent = xmlGetDocEntity(doc, BAD_CAST "test");
165+
if (ent->children->doc != NULL) {
166+
fprintf(stderr, "Entity content should have NULL doc\n");
167+
err = 1;
168+
}
169+
170+
/* Free doc before DTD */
171+
doc->extSubset = NULL;
172+
xmlFreeDoc(doc);
173+
xmlFreeDtd(dtd);
174+
175+
return err;
176+
}
177+
#endif /* LIBXML_VALID_ENABLED */
178+
128179
#ifdef LIBXML_SAX1_ENABLED
129180
static int
130181
testBalancedChunk(void) {
@@ -571,6 +622,9 @@ main(void) {
571622
err |= testUnsupportedEncoding();
572623
err |= testNodeGetContent();
573624
err |= testCFileIO();
625+
#ifdef LIBXML_VALID_ENABLED
626+
err |= testSwitchDtd();
627+
#endif
574628
#ifdef LIBXML_SAX1_ENABLED
575629
err |= testBalancedChunk();
576630
#endif

xmlIO.c

Lines changed: 13 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1210,7 +1210,13 @@ xmlInputDefaultOpen(xmlParserInputBufferPtr buf, const char *filename) {
12101210
if (xzStream == NULL) {
12111211
close(fd);
12121212
} else {
1213-
if (__libxml2_xzcompressed(xzStream) > 0) {
1213+
/*
1214+
* Non-regular files like pipes can't be reopened.
1215+
* If a file isn't seekable, we pipe uncompressed
1216+
* input through xzlib.
1217+
*/
1218+
if ((lseek(fd, 0, SEEK_CUR) < 0) ||
1219+
(__libxml2_xzcompressed(xzStream) > 0)) {
12141220
buf->context = xzStream;
12151221
buf->readcallback = xmlXzfileRead;
12161222
buf->closecallback = xmlXzfileClose;
@@ -1237,12 +1243,13 @@ xmlInputDefaultOpen(xmlParserInputBufferPtr buf, const char *filename) {
12371243
if (gzStream == NULL) {
12381244
close(fd);
12391245
} else {
1240-
char buff4[4];
1241-
1242-
if ((gzread(gzStream, buff4, 4) > 0) &&
1246+
/*
1247+
* Non-regular files like pipes can't be reopened.
1248+
* If a file isn't seekable, we pipe uncompressed
1249+
* input through zlib.
1250+
*/
1251+
if ((lseek(fd, 0, SEEK_CUR) < 0) ||
12431252
(gzdirect(gzStream) == 0)) {
1244-
gzrewind(gzStream);
1245-
12461253
buf->context = gzStream;
12471254
buf->readcallback = xmlGzfileRead;
12481255
buf->closecallback = xmlGzfileClose;

xmlreader.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@
5858
#ifdef __va_copy
5959
#define va_copy(dest, src) __va_copy(dest, src)
6060
#else
61-
#define va_copy(dest, src) memcpy(dest, src, sizeof(va_list))
61+
#define va_copy(dest, src) memcpy(&(dest), &(src), sizeof(va_list))
6262
#endif
6363
#endif
6464

@@ -1750,7 +1750,8 @@ xmlTextReaderReadString(xmlTextReaderPtr reader)
17501750
case XML_CDATA_SECTION_NODE:
17511751
break;
17521752
case XML_ELEMENT_NODE:
1753-
if (xmlTextReaderDoExpand(reader) == -1)
1753+
if ((xmlTextReaderDoExpand(reader) == -1) ||
1754+
(node->children == NULL))
17541755
return(NULL);
17551756
break;
17561757
case XML_ATTRIBUTE_NODE:

xmlstring.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
#ifdef __va_copy
3131
#define va_copy(dest, src) __va_copy(dest, src)
3232
#else
33-
#define va_copy(dest, src) memcpy(dest, src, sizeof(va_list))
33+
#define va_copy(dest, src) memcpy(&(dest), &(src), sizeof(va_list))
3434
#endif
3535
#endif
3636

xmlwriter.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
#ifdef __va_copy
3737
#define va_copy(dest, src) __va_copy(dest, src)
3838
#else
39-
#define va_copy(dest, src) memcpy(dest, src, sizeof(va_list))
39+
#define va_copy(dest, src) memcpy(&(dest), &(src), sizeof(va_list))
4040
#endif
4141
#endif
4242

xpath.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10434,8 +10434,9 @@ xmlXPathCompLocationPath(xmlXPathParserContextPtr ctxt) {
1043410434
} else if (CUR == '/') {
1043510435
NEXT;
1043610436
SKIP_BLANKS;
10437-
if ((CUR != 0 ) &&
10438-
((IS_ASCII_LETTER(CUR)) || (CUR == '_') || (CUR == '.') ||
10437+
if ((CUR != 0) &&
10438+
((IS_ASCII_LETTER(CUR)) || (CUR >= 0x80) ||
10439+
(CUR == '_') || (CUR == '.') ||
1043910440
(CUR == '@') || (CUR == '*')))
1044010441
xmlXPathCompRelativeLocationPath(ctxt);
1044110442
}

0 commit comments

Comments
 (0)