]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Allow zero length keys in isc_hashmap
authorOndřej Surý <ondrej@isc.org>
Thu, 8 Dec 2022 09:46:09 +0000 (10:46 +0100)
committerOndřej Surý <ondrej@isc.org>
Wed, 14 Dec 2022 16:59:07 +0000 (17:59 +0100)
In case, we are trying to hash the empty key into the hashmap, the key
is going to have zero length.  This might happen in the unit test.
Allow this and add a unit test to ensure the empty zero-length key
doesn't hash to slot 0 as SipHash 2-4 (our hash function of choice) has
no problem with zero-length inputs.

lib/isc/hashmap.c
tests/isc/hashmap_test.c

index 0abb1220c2f12c82fdddeca8ebd32bbf8ae7483c..2ea7a251821287b9896d347ffb953fb1e39885a6 100644 (file)
@@ -134,7 +134,7 @@ try_nexttable(const isc_hashmap_t *hashmap, uint8_t idx) {
 static void
 hashmap_node_init(hashmap_node_t *node, const uint32_t hashval,
                  const uint8_t *key, const uint32_t keysize, void *value) {
-       REQUIRE(key != NULL && keysize > 0 && keysize <= UINT16_MAX);
+       REQUIRE(key != NULL && keysize <= UINT16_MAX);
 
        *node = (hashmap_node_t){
                .value = value,
@@ -318,7 +318,6 @@ uint32_t
 isc_hashmap_hash(const isc_hashmap_t *hashmap, const void *key,
                 uint32_t keysize) {
        REQUIRE(ISC_HASHMAP_VALID(hashmap));
-       REQUIRE(key != NULL && keysize > 0 && keysize <= UINT16_MAX);
 
        uint32_t hashval;
 
@@ -332,7 +331,7 @@ isc_result_t
 isc_hashmap_find(const isc_hashmap_t *hashmap, const uint32_t *hashvalp,
                 const void *key, uint32_t keysize, void **valuep) {
        REQUIRE(ISC_HASHMAP_VALID(hashmap));
-       REQUIRE(key != NULL && keysize > 0 && keysize <= UINT16_MAX);
+       REQUIRE(key != NULL && keysize <= UINT16_MAX);
 
        hashmap_node_t *node;
        uint8_t idx = hashmap->hindex;
@@ -487,7 +486,7 @@ isc_result_t
 isc_hashmap_delete(isc_hashmap_t *hashmap, const uint32_t *hashvalp,
                   const void *key, uint32_t keysize) {
        REQUIRE(ISC_HASHMAP_VALID(hashmap));
-       REQUIRE(key != NULL && keysize > 0 && keysize <= UINT16_MAX);
+       REQUIRE(key != NULL && keysize <= UINT16_MAX);
 
        hashmap_node_t *node;
        isc_result_t result = ISC_R_NOTFOUND;
@@ -600,7 +599,7 @@ isc_result_t
 isc_hashmap_add(isc_hashmap_t *hashmap, const uint32_t *hashvalp,
                const void *key, uint32_t keysize, void *value) {
        REQUIRE(ISC_HASHMAP_VALID(hashmap));
-       REQUIRE(key != NULL && keysize > 0 && keysize <= UINT16_MAX);
+       REQUIRE(key != NULL && keysize <= UINT16_MAX);
 
        isc_result_t result;
        uint32_t hashval = (hashvalp != NULL)
index 334ed8d64f4b3a178fd5f85b3618b09a2769da97..99b7951f57c1ab3bb75fcd82afdff86a8051184c 100644 (file)
@@ -351,6 +351,30 @@ ISC_RUN_TEST_IMPL(isc_hashmap_iterator) {
        return;
 }
 
+ISC_RUN_TEST_IMPL(isc_hashmap_hash_zero_length) {
+       isc_hashmap_t *hashmap = NULL;
+       uint32_t hashval;
+       bool again = false;
+
+again:
+       isc_hashmap_create(mctx, 1, ISC_HASHMAP_CASE_SENSITIVE, &hashmap);
+
+       hashval = isc_hashmap_hash(hashmap, "", 0);
+
+       isc_hashmap_destroy(&hashmap);
+
+       if (hashval == 0 && !again) {
+               /*
+                * We could be extremely unlock and the siphash could hash the
+                * zero length string to 0, so try one more time.
+                */
+               again = true;
+               goto again;
+       }
+
+       assert_int_not_equal(hashval, 0);
+}
+
 ISC_RUN_TEST_IMPL(isc_hashmap_case) {
        isc_result_t result;
        isc_hashmap_t *hashmap = NULL;
@@ -401,6 +425,7 @@ ISC_RUN_TEST_IMPL(isc_hashmap_case) {
 }
 
 ISC_TEST_LIST_START
+ISC_TEST_ENTRY(isc_hashmap_hash_zero_length)
 ISC_TEST_ENTRY(isc_hashmap_case)
 ISC_TEST_ENTRY(isc_hashmap_1_120)
 ISC_TEST_ENTRY(isc_hashmap_6_1000)