Fix case insensitive matching in isc_ht hash table implementation
The case insensitive matching in isc_ht was basically completely broken as only the hashvalue computation was case insensitive, but the key comparison was always case sensitive. (cherry picked from commit 34ae6916f115fc291865857509433f95c2bc0871)
This commit is contained in:
55
lib/isc/ht.c
55
lib/isc/ht.c
@@ -93,11 +93,54 @@ maybe_rehash(isc_ht_t *ht, size_t newcount);
|
||||
static isc_result_t
|
||||
isc__ht_iter_next(isc_ht_iter_t *it);
|
||||
|
||||
static uint8_t maptolower[] = {
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
|
||||
0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
|
||||
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23,
|
||||
0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b,
|
||||
0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
|
||||
0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73,
|
||||
0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b,
|
||||
0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
|
||||
0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83,
|
||||
0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b,
|
||||
0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
|
||||
0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3,
|
||||
0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
|
||||
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb,
|
||||
0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
|
||||
0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3,
|
||||
0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
|
||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb,
|
||||
0xfc, 0xfd, 0xfe, 0xff
|
||||
};
|
||||
|
||||
static int
|
||||
memcasecmp(const void *vs1, const void *vs2, size_t len) {
|
||||
uint8_t const *s1 = vs1;
|
||||
uint8_t const *s2 = vs2;
|
||||
for (size_t i = 0; i < len; i++) {
|
||||
uint8_t u1 = s1[i];
|
||||
uint8_t u2 = s2[i];
|
||||
int U1 = maptolower[u1];
|
||||
int U2 = maptolower[u2];
|
||||
int diff = U1 - U2;
|
||||
if (diff) {
|
||||
return diff;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
isc__ht_node_match(isc_ht_node_t *node, const uint32_t hashval,
|
||||
const uint8_t *key, uint32_t keysize) {
|
||||
const uint8_t *key, uint32_t keysize, bool case_sensitive) {
|
||||
return (node->hashval == hashval && node->keysize == keysize &&
|
||||
memcmp(node->key, key, keysize) == 0);
|
||||
(case_sensitive ? (memcmp(node->key, key, keysize) == 0)
|
||||
: (memcasecmp(node->key, key, keysize) == 0)));
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
@@ -341,7 +384,9 @@ nexttable:
|
||||
for (isc_ht_node_t *node = ht->table[findex][hash]; node != NULL;
|
||||
node = node->next)
|
||||
{
|
||||
if (isc__ht_node_match(node, hashval, key, keysize)) {
|
||||
if (isc__ht_node_match(node, hashval, key, keysize,
|
||||
ht->case_sensitive))
|
||||
{
|
||||
return (node);
|
||||
}
|
||||
}
|
||||
@@ -390,7 +435,9 @@ isc__ht_delete(isc_ht_t *ht, const unsigned char *key, const uint32_t keysize,
|
||||
for (isc_ht_node_t *node = ht->table[idx][hash]; node != NULL;
|
||||
prev = node, node = node->next)
|
||||
{
|
||||
if (isc__ht_node_match(node, hashval, key, keysize)) {
|
||||
if (isc__ht_node_match(node, hashval, key, keysize,
|
||||
ht->case_sensitive))
|
||||
{
|
||||
if (prev == NULL) {
|
||||
ht->table[idx][hash] = node->next;
|
||||
} else {
|
||||
|
||||
@@ -312,7 +312,57 @@ ISC_RUN_TEST_IMPL(isc_ht_iterator) {
|
||||
test_ht_iterator();
|
||||
}
|
||||
|
||||
ISC_RUN_TEST_IMPL(isc_ht_case) {
|
||||
isc_ht_t *ht = NULL;
|
||||
void *f = NULL;
|
||||
isc_result_t result = ISC_R_UNSET;
|
||||
|
||||
unsigned char lower[16] = { "test case" };
|
||||
unsigned char same[16] = { "test case" };
|
||||
unsigned char upper[16] = { "TEST CASE" };
|
||||
unsigned char mixed[16] = { "tEsT CaSe" };
|
||||
|
||||
isc_ht_init(&ht, mctx, 8, ISC_HT_CASE_SENSITIVE);
|
||||
assert_non_null(ht);
|
||||
|
||||
result = isc_ht_add(ht, lower, 16, (void *)lower);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
result = isc_ht_add(ht, same, 16, (void *)same);
|
||||
assert_int_equal(result, ISC_R_EXISTS);
|
||||
|
||||
result = isc_ht_add(ht, upper, 16, (void *)upper);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
result = isc_ht_find(ht, mixed, 16, &f);
|
||||
assert_int_equal(result, ISC_R_NOTFOUND);
|
||||
assert_null(f);
|
||||
|
||||
isc_ht_destroy(&ht);
|
||||
assert_null(ht);
|
||||
|
||||
isc_ht_init(&ht, mctx, 8, ISC_HT_CASE_INSENSITIVE);
|
||||
assert_non_null(ht);
|
||||
|
||||
result = isc_ht_add(ht, lower, 16, (void *)lower);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
|
||||
result = isc_ht_add(ht, same, 16, (void *)same);
|
||||
assert_int_equal(result, ISC_R_EXISTS);
|
||||
|
||||
result = isc_ht_add(ht, upper, 16, (void *)upper);
|
||||
assert_int_equal(result, ISC_R_EXISTS);
|
||||
|
||||
result = isc_ht_find(ht, mixed, 16, &f);
|
||||
assert_int_equal(result, ISC_R_SUCCESS);
|
||||
assert_ptr_equal(f, &lower);
|
||||
|
||||
isc_ht_destroy(&ht);
|
||||
assert_null(ht);
|
||||
}
|
||||
|
||||
ISC_TEST_LIST_START
|
||||
ISC_TEST_ENTRY(isc_ht_case)
|
||||
ISC_TEST_ENTRY(isc_ht_20)
|
||||
ISC_TEST_ENTRY(isc_ht_8)
|
||||
ISC_TEST_ENTRY(isc_ht_1)
|
||||
|
||||
Reference in New Issue
Block a user