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:
Ondřej Surý
2024-02-11 00:49:32 +01:00
parent 96473a5edb
commit ec11aa2836
2 changed files with 101 additions and 4 deletions

View File

@@ -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 {

View File

@@ -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)