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 c462d65b2f)
This commit is contained in:
Ondřej Surý
2024-02-11 00:49:32 +01:00
committed by Michał Kępień
parent c6026cbbaa
commit 418b379359
2 changed files with 111 additions and 4 deletions

View File

@@ -94,11 +94,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
@@ -345,7 +388,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);
}
}
@@ -394,7 +439,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 {

View File

@@ -345,9 +345,69 @@ isc_ht_iterator_test(void **state) {
test_ht_iterator();
}
static void
isc_ht_case(void **state) {
UNUSED(state);
isc_ht_t *ht = NULL;
void *f = NULL;
isc_result_t result = ISC_R_UNSET;
isc_mem_t *mctx = NULL;
result = isc_mem_createx2(0, 0, default_memalloc, default_memfree,
NULL, &mctx, 0);
assert_int_equal(result, ISC_R_SUCCESS);
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_mem_detach(&mctx);
}
int
main(void) {
const struct CMUnitTest tests[] = {
cmocka_unit_test(isc_ht_case),
cmocka_unit_test(isc_ht_20),
cmocka_unit_test(isc_ht_8),
cmocka_unit_test(isc_ht_1),