diff --git a/parser.c b/parser.c
index 9c5a02e0..f2b62e5e 100644
--- a/parser.c
+++ b/parser.c
@@ -8928,6 +8928,35 @@ xmlAttrHashInsert(xmlParserCtxtPtr ctxt, unsigned size, const xmlChar *name,
return(INT_MAX);
}
+static int
+xmlAttrHashInsertQName(xmlParserCtxtPtr ctxt, unsigned size,
+ const xmlChar *name, const xmlChar *prefix,
+ unsigned hashValue, int aindex) {
+ xmlAttrHashBucket *table = ctxt->attrHash;
+ xmlAttrHashBucket *bucket;
+ unsigned hindex;
+
+ hindex = hashValue & (size - 1);
+ bucket = &table[hindex];
+
+ while (bucket->index >= 0) {
+ const xmlChar **atts = &ctxt->atts[bucket->index];
+
+ if ((name == atts[0]) && (prefix == atts[1]))
+ return(bucket->index);
+
+ hindex++;
+ bucket++;
+ if (hindex >= size) {
+ hindex = 0;
+ bucket = table;
+ }
+ }
+
+ bucket->index = aindex;
+
+ return(INT_MAX);
+}
/**
* xmlParseStartTag2:
* @ctxt: an XML parser context
@@ -8976,6 +9005,8 @@ xmlParseStartTag2(xmlParserCtxtPtr ctxt, const xmlChar **pref,
int nratts, nbatts, nbdef;
int i, j, nbNs, nbTotalDef, attval, nsIndex, maxAtts;
int alloc = 0;
+ int numNsErr = 0;
+ int numDupErr = 0;
if (RAW != '<') return(NULL);
NEXT1;
@@ -9354,10 +9385,12 @@ next_attr:
if (res < INT_MAX) {
if (aprefix == atts[res+1]) {
xmlErrAttributeDup(ctxt, aprefix, attname);
+ numDupErr += 1;
} else {
xmlNsErr(ctxt, XML_NS_ERR_ATTRIBUTE_REDEFINED,
"Namespaced Attribute %s in '%s' redefined\n",
attname, nsuri, NULL);
+ numNsErr += 1;
}
}
}
@@ -9456,6 +9489,43 @@ next_attr:
}
}
+ /*
+ * Using a single hash table for nsUri/localName pairs cannot
+ * detect duplicate QNames reliably. The following example will
+ * only result in two namespace errors.
+ *
+ *
+ *
+ *
+ *
+ * If we saw more than one namespace error but no duplicate QNames
+ * were found, we have to scan for duplicate QNames.
+ */
+ if ((numDupErr == 0) && (numNsErr > 1)) {
+ memset(ctxt->attrHash, -1,
+ attrHashSize * sizeof(ctxt->attrHash[0]));
+
+ for (i = 0, j = 0; j < nratts; i += 5, j++) {
+ unsigned hashValue, nameHashValue, prefixHashValue;
+ int res;
+
+ aprefix = atts[i+1];
+ if (aprefix == NULL)
+ continue;
+
+ attname = atts[i];
+ /* Hash values always have bit 31 set, see dict.c */
+ nameHashValue = ctxt->attallocs[j] | 0x80000000;
+ prefixHashValue = xmlDictComputeHash(ctxt->dict, aprefix);
+
+ hashValue = xmlDictCombineHash(nameHashValue, prefixHashValue);
+ res = xmlAttrHashInsertQName(ctxt, attrHashSize, attname,
+ aprefix, hashValue, i);
+ if (res < INT_MAX)
+ xmlErrAttributeDup(ctxt, aprefix, attname);
+ }
+ }
+
/*
* Reconstruct attribute pointers
*/
diff --git a/result/errors/dup-xml-attr2.xml.ent b/result/errors/dup-xml-attr2.xml.ent
new file mode 100644
index 00000000..ab28d807
--- /dev/null
+++ b/result/errors/dup-xml-attr2.xml.ent
@@ -0,0 +1,9 @@
+./test/errors/dup-xml-attr2.xml:2: namespace error : Namespaced Attribute a in 'urn:a' redefined
+
+ ^
+./test/errors/dup-xml-attr2.xml:2: namespace error : Namespaced Attribute a in 'urn:a' redefined
+
+ ^
+./test/errors/dup-xml-attr2.xml:2: parser error : Attribute b:a redefined
+
+ ^
diff --git a/result/errors/dup-xml-attr2.xml.err b/result/errors/dup-xml-attr2.xml.err
new file mode 100644
index 00000000..ab28d807
--- /dev/null
+++ b/result/errors/dup-xml-attr2.xml.err
@@ -0,0 +1,9 @@
+./test/errors/dup-xml-attr2.xml:2: namespace error : Namespaced Attribute a in 'urn:a' redefined
+
+ ^
+./test/errors/dup-xml-attr2.xml:2: namespace error : Namespaced Attribute a in 'urn:a' redefined
+
+ ^
+./test/errors/dup-xml-attr2.xml:2: parser error : Attribute b:a redefined
+
+ ^
diff --git a/result/errors/dup-xml-attr2.xml.str b/result/errors/dup-xml-attr2.xml.str
new file mode 100644
index 00000000..45dbb9e1
--- /dev/null
+++ b/result/errors/dup-xml-attr2.xml.str
@@ -0,0 +1,10 @@
+./test/errors/dup-xml-attr2.xml:2: namespace error : Namespaced Attribute a in 'urn:a' redefined
+
+ ^
+./test/errors/dup-xml-attr2.xml:2: namespace error : Namespaced Attribute a in 'urn:a' redefined
+
+ ^
+./test/errors/dup-xml-attr2.xml:2: parser error : Attribute b:a redefined
+
+ ^
+./test/errors/dup-xml-attr2.xml : failed to parse
diff --git a/test/errors/dup-xml-attr2.xml b/test/errors/dup-xml-attr2.xml
new file mode 100644
index 00000000..9bc014de
--- /dev/null
+++ b/test/errors/dup-xml-attr2.xml
@@ -0,0 +1,3 @@
+
+
+