mirror of
https://gitlab.gnome.org/GNOME/libxml2
synced 2025-03-28 21:33:13 +00:00
hash: Fix deletion of entries during scan
Functions like xmlCleanSpecialAttr scan a hash table and possibly delete entries in the callback. xmlHashScanFull must detect such deletions and rescan the entry. This regressed when rewriting the hash table code in 4a513d56. Fixes #626.
This commit is contained in:
parent
aca37d8c77
commit
a2b5c90a44
76
hash.c
76
hash.c
@ -913,15 +913,42 @@ xmlHashScan(xmlHashTablePtr hash, xmlHashScanner scan, void *data) {
|
||||
void
|
||||
xmlHashScanFull(xmlHashTablePtr hash, xmlHashScannerFull scan, void *data) {
|
||||
const xmlHashEntry *entry, *end;
|
||||
xmlHashEntry old;
|
||||
unsigned i;
|
||||
|
||||
if ((hash == NULL) || (hash->size == 0) || (scan == NULL))
|
||||
return;
|
||||
|
||||
/*
|
||||
* We must handle the case that a scanned entry is removed when executing
|
||||
* the callback (xmlCleanSpecialAttr and possibly other places).
|
||||
*
|
||||
* Find the start of a probe sequence to avoid scanning entries twice if
|
||||
* a deletion happens.
|
||||
*/
|
||||
entry = hash->table;
|
||||
end = &hash->table[hash->size];
|
||||
while (entry->hashValue != 0) {
|
||||
if (++entry >= end)
|
||||
entry = hash->table;
|
||||
}
|
||||
|
||||
for (entry = hash->table; entry < end; entry++) {
|
||||
if ((entry->hashValue != 0) && (entry->payload != NULL))
|
||||
scan(entry->payload, data, entry->key, entry->key2, entry->key3);
|
||||
for (i = 0; i < hash->size; i++) {
|
||||
if ((entry->hashValue != 0) && (entry->payload != NULL)) {
|
||||
/*
|
||||
* Make sure to rescan after a possible deletion.
|
||||
*/
|
||||
do {
|
||||
old = *entry;
|
||||
scan(entry->payload, data, entry->key, entry->key2, entry->key3);
|
||||
} while ((entry->hashValue != 0) &&
|
||||
(entry->payload != NULL) &&
|
||||
((entry->key != old.key) ||
|
||||
(entry->key2 != old.key2) ||
|
||||
(entry->key3 != old.key3)));
|
||||
}
|
||||
if (++entry >= end)
|
||||
entry = hash->table;
|
||||
}
|
||||
}
|
||||
|
||||
@ -966,22 +993,47 @@ xmlHashScanFull3(xmlHashTablePtr hash, const xmlChar *key,
|
||||
const xmlChar *key2, const xmlChar *key3,
|
||||
xmlHashScannerFull scan, void *data) {
|
||||
const xmlHashEntry *entry, *end;
|
||||
xmlHashEntry old;
|
||||
unsigned i;
|
||||
|
||||
if ((hash == NULL) || (hash->size == 0) || (scan == NULL))
|
||||
return;
|
||||
|
||||
/*
|
||||
* We must handle the case that a scanned entry is removed when executing
|
||||
* the callback (xmlCleanSpecialAttr and possibly other places).
|
||||
*
|
||||
* Find the start of a probe sequence to avoid scanning entries twice if
|
||||
* a deletion happens.
|
||||
*/
|
||||
entry = hash->table;
|
||||
end = &hash->table[hash->size];
|
||||
while (entry->hashValue != 0) {
|
||||
if (++entry >= end)
|
||||
entry = hash->table;
|
||||
}
|
||||
|
||||
for (entry = hash->table; entry < end; entry++) {
|
||||
if (entry->hashValue == 0)
|
||||
continue;
|
||||
if (((key == NULL) ||
|
||||
(strcmp((const char *) key, (const char *) entry->key) == 0)) &&
|
||||
((key2 == NULL) || (xmlFastStrEqual(key2, entry->key2))) &&
|
||||
((key3 == NULL) || (xmlFastStrEqual(key3, entry->key3))) &&
|
||||
(entry->payload != NULL)) {
|
||||
scan(entry->payload, data, entry->key, entry->key2, entry->key3);
|
||||
for (i = 0; i < hash->size; i++) {
|
||||
if ((entry->hashValue != 0) && (entry->payload != NULL)) {
|
||||
/*
|
||||
* Make sure to rescan after a possible deletion.
|
||||
*/
|
||||
do {
|
||||
if (((key != NULL) && (strcmp((const char *) key,
|
||||
(const char *) entry->key) != 0)) ||
|
||||
((key2 != NULL) && (!xmlFastStrEqual(key2, entry->key2))) ||
|
||||
((key3 != NULL) && (!xmlFastStrEqual(key3, entry->key3))))
|
||||
break;
|
||||
old = *entry;
|
||||
scan(entry->payload, data, entry->key, entry->key2, entry->key3);
|
||||
} while ((entry->hashValue != 0) &&
|
||||
(entry->payload != NULL) &&
|
||||
((entry->key != old.key) ||
|
||||
(entry->key2 != old.key2) ||
|
||||
(entry->key3 != old.key3)));
|
||||
}
|
||||
if (++entry >= end)
|
||||
entry = hash->table;
|
||||
}
|
||||
}
|
||||
|
||||
|
14
result/issue626.xml
Normal file
14
result/issue626.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE doc [
|
||||
<!ATTLIST e a1 CDATA #IMPLIED>
|
||||
<!ATTLIST e a2 CDATA #IMPLIED>
|
||||
<!ATTLIST e a3 CDATA #IMPLIED>
|
||||
<!ATTLIST e a4 CDATA #IMPLIED>
|
||||
<!ATTLIST e a5 CDATA #IMPLIED>
|
||||
<!ATTLIST e a6 CDATA #IMPLIED>
|
||||
]>
|
||||
<doc>
|
||||
<!-- This tests whether xmlCleanSpecialAttr works. The attribute values
|
||||
must not be normalized. -->
|
||||
<e a1=" x x " a2=" x x " a3=" x x " a4=" x x " a5=" x x " a6=" x x "/>
|
||||
</doc>
|
12
result/issue626.xml.rde
Normal file
12
result/issue626.xml.rde
Normal file
@ -0,0 +1,12 @@
|
||||
0 10 doc 0 0
|
||||
0 1 doc 0 0
|
||||
1 14 #text 0 1
|
||||
|
||||
1 8 #comment 0 1 This tests whether xmlCleanSpecialAttr works. The attribute values
|
||||
must not be normalized.
|
||||
1 14 #text 0 1
|
||||
|
||||
1 1 e 1 0
|
||||
1 14 #text 0 1
|
||||
|
||||
0 15 doc 0 0
|
12
result/issue626.xml.rdr
Normal file
12
result/issue626.xml.rdr
Normal file
@ -0,0 +1,12 @@
|
||||
0 10 doc 0 0
|
||||
0 1 doc 0 0
|
||||
1 14 #text 0 1
|
||||
|
||||
1 8 #comment 0 1 This tests whether xmlCleanSpecialAttr works. The attribute values
|
||||
must not be normalized.
|
||||
1 14 #text 0 1
|
||||
|
||||
1 1 e 1 0
|
||||
1 14 #text 0 1
|
||||
|
||||
0 15 doc 0 0
|
23
result/issue626.xml.sax
Normal file
23
result/issue626.xml.sax
Normal file
@ -0,0 +1,23 @@
|
||||
SAX.setDocumentLocator()
|
||||
SAX.startDocument()
|
||||
SAX.internalSubset(doc, , )
|
||||
SAX.attributeDecl(e, a1, 1, 3, NULL, ...)
|
||||
SAX.attributeDecl(e, a2, 1, 3, NULL, ...)
|
||||
SAX.attributeDecl(e, a3, 1, 3, NULL, ...)
|
||||
SAX.attributeDecl(e, a4, 1, 3, NULL, ...)
|
||||
SAX.attributeDecl(e, a5, 1, 3, NULL, ...)
|
||||
SAX.attributeDecl(e, a6, 1, 3, NULL, ...)
|
||||
SAX.externalSubset(doc, , )
|
||||
SAX.startElement(doc)
|
||||
SAX.characters(
|
||||
, 5)
|
||||
SAX.comment( This tests whether xmlCleanSpecialAttr works. The attribute values
|
||||
must not be normalized. )
|
||||
SAX.characters(
|
||||
, 5)
|
||||
SAX.startElement(e, a1=' x x ', a2=' x x ', a3=' x x ', a4=' x x ', a5=' x x ', a6=' x x ')
|
||||
SAX.endElement(e)
|
||||
SAX.characters(
|
||||
, 1)
|
||||
SAX.endElement(doc)
|
||||
SAX.endDocument()
|
23
result/issue626.xml.sax2
Normal file
23
result/issue626.xml.sax2
Normal file
@ -0,0 +1,23 @@
|
||||
SAX.setDocumentLocator()
|
||||
SAX.startDocument()
|
||||
SAX.internalSubset(doc, , )
|
||||
SAX.attributeDecl(e, a1, 1, 3, NULL, ...)
|
||||
SAX.attributeDecl(e, a2, 1, 3, NULL, ...)
|
||||
SAX.attributeDecl(e, a3, 1, 3, NULL, ...)
|
||||
SAX.attributeDecl(e, a4, 1, 3, NULL, ...)
|
||||
SAX.attributeDecl(e, a5, 1, 3, NULL, ...)
|
||||
SAX.attributeDecl(e, a6, 1, 3, NULL, ...)
|
||||
SAX.externalSubset(doc, , )
|
||||
SAX.startElementNs(doc, NULL, NULL, 0, 0, 0)
|
||||
SAX.characters(
|
||||
, 5)
|
||||
SAX.comment( This tests whether xmlCleanSpecialAttr works. The attribute values
|
||||
must not be normalized. )
|
||||
SAX.characters(
|
||||
, 5)
|
||||
SAX.startElementNs(e, NULL, NULL, 0, 6, 0, a1=' x ...', 6, a2=' x ...', 6, a3=' x ...', 6, a4=' x ...', 6, a5=' x ...', 6, a6=' x ...', 6)
|
||||
SAX.endElementNs(e, NULL, NULL)
|
||||
SAX.characters(
|
||||
, 1)
|
||||
SAX.endElementNs(doc, NULL, NULL)
|
||||
SAX.endDocument()
|
14
result/noent/issue626.xml
Normal file
14
result/noent/issue626.xml
Normal file
@ -0,0 +1,14 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE doc [
|
||||
<!ATTLIST e a1 CDATA #IMPLIED>
|
||||
<!ATTLIST e a2 CDATA #IMPLIED>
|
||||
<!ATTLIST e a3 CDATA #IMPLIED>
|
||||
<!ATTLIST e a4 CDATA #IMPLIED>
|
||||
<!ATTLIST e a5 CDATA #IMPLIED>
|
||||
<!ATTLIST e a6 CDATA #IMPLIED>
|
||||
]>
|
||||
<doc>
|
||||
<!-- This tests whether xmlCleanSpecialAttr works. The attribute values
|
||||
must not be normalized. -->
|
||||
<e a1=" x x " a2=" x x " a3=" x x " a4=" x x " a5=" x x " a6=" x x "/>
|
||||
</doc>
|
23
result/noent/issue626.xml.sax2
Normal file
23
result/noent/issue626.xml.sax2
Normal file
@ -0,0 +1,23 @@
|
||||
SAX.setDocumentLocator()
|
||||
SAX.startDocument()
|
||||
SAX.internalSubset(doc, , )
|
||||
SAX.attributeDecl(e, a1, 1, 3, NULL, ...)
|
||||
SAX.attributeDecl(e, a2, 1, 3, NULL, ...)
|
||||
SAX.attributeDecl(e, a3, 1, 3, NULL, ...)
|
||||
SAX.attributeDecl(e, a4, 1, 3, NULL, ...)
|
||||
SAX.attributeDecl(e, a5, 1, 3, NULL, ...)
|
||||
SAX.attributeDecl(e, a6, 1, 3, NULL, ...)
|
||||
SAX.externalSubset(doc, , )
|
||||
SAX.startElementNs(doc, NULL, NULL, 0, 0, 0)
|
||||
SAX.characters(
|
||||
, 5)
|
||||
SAX.comment( This tests whether xmlCleanSpecialAttr works. The attribute values
|
||||
must not be normalized. )
|
||||
SAX.characters(
|
||||
, 5)
|
||||
SAX.startElementNs(e, NULL, NULL, 0, 6, 0, a1=' x ...', 6, a2=' x ...', 6, a3=' x ...', 6, a4=' x ...', 6, a5=' x ...', 6, a6=' x ...', 6)
|
||||
SAX.endElementNs(e, NULL, NULL)
|
||||
SAX.characters(
|
||||
, 1)
|
||||
SAX.endElementNs(doc, NULL, NULL)
|
||||
SAX.endDocument()
|
13
test/issue626.xml
Normal file
13
test/issue626.xml
Normal file
@ -0,0 +1,13 @@
|
||||
<!DOCTYPE doc [
|
||||
<!ATTLIST e a1 CDATA #IMPLIED>
|
||||
<!ATTLIST e a2 CDATA #IMPLIED>
|
||||
<!ATTLIST e a3 CDATA #IMPLIED>
|
||||
<!ATTLIST e a4 CDATA #IMPLIED>
|
||||
<!ATTLIST e a5 CDATA #IMPLIED>
|
||||
<!ATTLIST e a6 CDATA #IMPLIED>
|
||||
]>
|
||||
<doc>
|
||||
<!-- This tests whether xmlCleanSpecialAttr works. The attribute values
|
||||
must not be normalized. -->
|
||||
<e a1=" x x " a2=" x x " a3=" x x " a4=" x x " a5=" x x " a6=" x x "/>
|
||||
</doc>
|
Loading…
x
Reference in New Issue
Block a user