Skip to content

Commit f313848

Browse files
committed
hash: Report malloc failures
Introduce new API functions that return a separate error code if a memory allocation fails. - xmlHashAdd - xmlHashCopySafe
1 parent bd5ad03 commit f313848

File tree

2 files changed

+165
-28
lines changed

2 files changed

+165
-28
lines changed

hash.c

Lines changed: 146 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -445,16 +445,9 @@ xmlHashUpdateInternal(xmlHashTablePtr hash, const xmlChar *key,
445445
if (dealloc)
446446
dealloc(entry->payload, entry->key);
447447
entry->payload = payload;
448-
return(0);
449-
} else {
450-
/*
451-
* xmlHashAddEntry found an existing entry.
452-
*
453-
* TODO: We should return a different error code here to
454-
* distinguish from malloc failures.
455-
*/
456-
return(-1);
457448
}
449+
450+
return(0);
458451
}
459452

460453
/*
@@ -589,7 +582,7 @@ xmlHashUpdateInternal(xmlHashTablePtr hash, const xmlChar *key,
589582

590583
hash->nbElems++;
591584

592-
return(0);
585+
return(1);
593586
}
594587

595588
/**
@@ -604,6 +597,60 @@ xmlHashDefaultDeallocator(void *entry, const xmlChar *key ATTRIBUTE_UNUSED) {
604597
xmlFree(entry);
605598
}
606599

600+
/**
601+
* xmlHashAdd:
602+
* @hash: hash table
603+
* @key: string key
604+
* @payload: pointer to the payload
605+
*
606+
* Add a hash table entry. If an entry with this key already exists,
607+
* payload will not be updated and 0 is returned. This return value
608+
* can't be distinguished from out-of-memory errors, so this function
609+
* should be used with care.
610+
*
611+
* Returns 1 on success, 0 if an entry exists and -1 in case of error.
612+
*/
613+
int
614+
xmlHashAdd(xmlHashTablePtr hash, const xmlChar *key, void *payload) {
615+
return(xmlHashUpdateInternal(hash, key, NULL, NULL, payload, NULL, 0));
616+
}
617+
618+
/**
619+
* xmlHashAdd2:
620+
* @hash: hash table
621+
* @key: first string key
622+
* @key2: second string key
623+
* @payload: pointer to the payload
624+
*
625+
* Add a hash table entry with two strings as key.
626+
*
627+
* See xmlHashAdd.
628+
*/
629+
int
630+
xmlHashAdd2(xmlHashTablePtr hash, const xmlChar *key,
631+
const xmlChar *key2, void *payload) {
632+
return(xmlHashUpdateInternal(hash, key, key2, NULL, payload, NULL, 0));
633+
}
634+
635+
/**
636+
* xmlHashAdd3:
637+
* @hash: hash table
638+
* @key: first string key
639+
* @key2: second string key
640+
* @key3: third string key
641+
* @payload: pointer to the payload
642+
*
643+
* Add a hash table entry with three strings as key.
644+
*
645+
* See xmlHashAdd.
646+
*/
647+
int
648+
xmlHashAdd3(xmlHashTablePtr hash, const xmlChar *key,
649+
const xmlChar *key2, const xmlChar *key3,
650+
void *payload) {
651+
return(xmlHashUpdateInternal(hash, key, key2, key3, payload, NULL, 0));
652+
}
653+
607654
/**
608655
* xmlHashAddEntry:
609656
* @hash: hash table
@@ -615,11 +662,21 @@ xmlHashDefaultDeallocator(void *entry, const xmlChar *key ATTRIBUTE_UNUSED) {
615662
* can't be distinguished from out-of-memory errors, so this function
616663
* should be used with care.
617664
*
665+
* NOTE: This function doesn't allow to distinguish malloc failures from
666+
* existing entries. Use xmlHashAdd instead.
667+
*
618668
* Returns 0 on success and -1 in case of error.
619669
*/
620670
int
621671
xmlHashAddEntry(xmlHashTablePtr hash, const xmlChar *key, void *payload) {
622-
return(xmlHashUpdateInternal(hash, key, NULL, NULL, payload, NULL, 0));
672+
int res = xmlHashUpdateInternal(hash, key, NULL, NULL, payload, NULL, 0);
673+
674+
if (res == 0)
675+
res = -1;
676+
else if (res == 1)
677+
res = 0;
678+
679+
return(res);
623680
}
624681

625682
/**
@@ -638,7 +695,14 @@ xmlHashAddEntry(xmlHashTablePtr hash, const xmlChar *key, void *payload) {
638695
int
639696
xmlHashAddEntry2(xmlHashTablePtr hash, const xmlChar *key,
640697
const xmlChar *key2, void *payload) {
641-
return(xmlHashUpdateInternal(hash, key, key2, NULL, payload, NULL, 0));
698+
int res = xmlHashUpdateInternal(hash, key, key2, NULL, payload, NULL, 0);
699+
700+
if (res == 0)
701+
res = -1;
702+
else if (res == 1)
703+
res = 0;
704+
705+
return(res);
642706
}
643707

644708
/**
@@ -659,7 +723,14 @@ int
659723
xmlHashAddEntry3(xmlHashTablePtr hash, const xmlChar *key,
660724
const xmlChar *key2, const xmlChar *key3,
661725
void *payload) {
662-
return(xmlHashUpdateInternal(hash, key, key2, key3, payload, NULL, 0));
726+
int res = xmlHashUpdateInternal(hash, key, key2, key3, payload, NULL, 0);
727+
728+
if (res == 0)
729+
res = -1;
730+
else if (res == 1)
731+
res = 0;
732+
733+
return(res);
663734
}
664735

665736
/**
@@ -677,8 +748,13 @@ xmlHashAddEntry3(xmlHashTablePtr hash, const xmlChar *key,
677748
int
678749
xmlHashUpdateEntry(xmlHashTablePtr hash, const xmlChar *key,
679750
void *payload, xmlHashDeallocator dealloc) {
680-
return(xmlHashUpdateInternal(hash, key, NULL, NULL, payload,
681-
dealloc, 1));
751+
int res = xmlHashUpdateInternal(hash, key, NULL, NULL, payload,
752+
dealloc, 1);
753+
754+
if (res == 1)
755+
res = 0;
756+
757+
return(res);
682758
}
683759

684760
/**
@@ -699,8 +775,13 @@ int
699775
xmlHashUpdateEntry2(xmlHashTablePtr hash, const xmlChar *key,
700776
const xmlChar *key2, void *payload,
701777
xmlHashDeallocator dealloc) {
702-
return(xmlHashUpdateInternal(hash, key, key2, NULL, payload,
703-
dealloc, 1));
778+
int res = xmlHashUpdateInternal(hash, key, key2, NULL, payload,
779+
dealloc, 1);
780+
781+
if (res == 1)
782+
res = 0;
783+
784+
return(res);
704785
}
705786

706787
/**
@@ -722,8 +803,13 @@ int
722803
xmlHashUpdateEntry3(xmlHashTablePtr hash, const xmlChar *key,
723804
const xmlChar *key2, const xmlChar *key3,
724805
void *payload, xmlHashDeallocator dealloc) {
725-
return(xmlHashUpdateInternal(hash, key, key2, key3, payload,
726-
dealloc, 1));
806+
int res = xmlHashUpdateInternal(hash, key, key2, key3, payload,
807+
dealloc, 1);
808+
809+
if (res == 1)
810+
res = 0;
811+
812+
return(res);
727813
}
728814

729815
/**
@@ -1037,21 +1123,23 @@ xmlHashScanFull3(xmlHashTablePtr hash, const xmlChar *key,
10371123
}
10381124
}
10391125

1040-
/**
1041-
* xmlHashCopy:
1126+
/*
1127+
* xmlHashCopySafe:
10421128
* @hash: hash table
1043-
* @copy: copier function for items in the hash
1129+
* @copyFunc: copier function for items in the hash
1130+
* @deallocFunc: deallocation function in case of errors
10441131
*
1045-
* Copy the hash @table using @copy to copy payloads.
1132+
* Copy the hash table using @copyFunc to copy payloads.
10461133
*
10471134
* Returns the new table or NULL if a memory allocation failed.
10481135
*/
10491136
xmlHashTablePtr
1050-
xmlHashCopy(xmlHashTablePtr hash, xmlHashCopier copy) {
1137+
xmlHashCopySafe(xmlHashTablePtr hash, xmlHashCopier copyFunc,
1138+
xmlHashDeallocator deallocFunc) {
10511139
const xmlHashEntry *entry, *end;
10521140
xmlHashTablePtr ret;
10531141

1054-
if ((hash == NULL) || (copy == NULL))
1142+
if ((hash == NULL) || (copyFunc == NULL))
10551143
return(NULL);
10561144

10571145
ret = xmlHashCreate(hash->size);
@@ -1064,12 +1152,42 @@ xmlHashCopy(xmlHashTablePtr hash, xmlHashCopier copy) {
10641152
end = &hash->table[hash->size];
10651153

10661154
for (entry = hash->table; entry < end; entry++) {
1067-
if (entry->hashValue != 0)
1068-
xmlHashAddEntry3(ret, entry->key, entry->key2, entry->key3,
1069-
copy(entry->payload, entry->key));
1155+
if (entry->hashValue != 0) {
1156+
void *copy;
1157+
1158+
copy = copyFunc(entry->payload, entry->key);
1159+
if (copy == NULL)
1160+
goto error;
1161+
if (xmlHashAdd3(ret, entry->key, entry->key2, entry->key3,
1162+
copy) <= 0) {
1163+
if (deallocFunc != NULL)
1164+
deallocFunc(copy, entry->key);
1165+
goto error;
1166+
}
1167+
}
10701168
}
10711169

10721170
return(ret);
1171+
1172+
error:
1173+
xmlHashFree(ret, deallocFunc);
1174+
return(NULL);
1175+
}
1176+
1177+
/*
1178+
* xmlHashCopy:
1179+
* @hash: hash table
1180+
* @copy: copier function for items in the hash
1181+
*
1182+
* DEPRECATED: Leaks memory in error case.
1183+
*
1184+
* Copy the hash table using @copy to copy payloads.
1185+
*
1186+
* Returns the new table or NULL if a memory allocation failed.
1187+
*/
1188+
xmlHashTablePtr
1189+
xmlHashCopy(xmlHashTablePtr hash, xmlHashCopier copy) {
1190+
return(xmlHashCopySafe(hash, copy, NULL));
10731191
}
10741192

10751193
/**

include/libxml/hash.h

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,10 @@ XMLPUBFUN void
109109
/*
110110
* Add a new entry to the hash table.
111111
*/
112+
XMLPUBFUN int
113+
xmlHashAdd (xmlHashTablePtr hash,
114+
const xmlChar *name,
115+
void *userdata);
112116
XMLPUBFUN int
113117
xmlHashAddEntry (xmlHashTablePtr hash,
114118
const xmlChar *name,
@@ -118,6 +122,11 @@ XMLPUBFUN int
118122
const xmlChar *name,
119123
void *userdata,
120124
xmlHashDeallocator dealloc);
125+
XMLPUBFUN int
126+
xmlHashAdd2 (xmlHashTablePtr hash,
127+
const xmlChar *name,
128+
const xmlChar *name2,
129+
void *userdata);
121130
XMLPUBFUN int
122131
xmlHashAddEntry2 (xmlHashTablePtr hash,
123132
const xmlChar *name,
@@ -129,6 +138,12 @@ XMLPUBFUN int
129138
const xmlChar *name2,
130139
void *userdata,
131140
xmlHashDeallocator dealloc);
141+
XMLPUBFUN int
142+
xmlHashAdd3 (xmlHashTablePtr hash,
143+
const xmlChar *name,
144+
const xmlChar *name2,
145+
const xmlChar *name3,
146+
void *userdata);
132147
XMLPUBFUN int
133148
xmlHashAddEntry3 (xmlHashTablePtr hash,
134149
const xmlChar *name,
@@ -199,6 +214,10 @@ XMLPUBFUN void *
199214
/*
200215
* Helpers.
201216
*/
217+
XMLPUBFUN xmlHashTablePtr
218+
xmlHashCopySafe (xmlHashTablePtr hash,
219+
xmlHashCopier copy,
220+
xmlHashDeallocator dealloc);
202221
XMLPUBFUN xmlHashTablePtr
203222
xmlHashCopy (xmlHashTablePtr hash,
204223
xmlHashCopier copy);

0 commit comments

Comments
 (0)