From acdc57259f18b40adeddbafa53a2a01ae97b00a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Mon, 12 Aug 2024 15:17:00 +0200 Subject: [PATCH] Fix the assertion failure in the isc_hashmap iterator When the round robin hashing reorders the map entries on deletion, we were adjusting the iterator table size only when the reordering was happening at the internal table boundary. The iterator table size had to be reduced by one to prevent seeing the entry that resized on position [0] twice because it migrated to [iter->size - 1] position. However, the same thing could happen when the same entry migrates a second time from [iter->size - 1] to [iter->size - 2] position (and so on) because the check that we are manipulating the entry just in the [0] position was insufficient. Instead of checking the position [pos == 0], we now check that the [pos % iter->size == 0], thus ignoring all the entries that might have moved back to the end of the internal table. --- lib/isc/hashmap.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/lib/isc/hashmap.c b/lib/isc/hashmap.c index d0611b97d3..338e497079 100644 --- a/lib/isc/hashmap.c +++ b/lib/isc/hashmap.c @@ -310,7 +310,8 @@ isc_hashmap_find(const isc_hashmap_t *hashmap, const uint32_t hashval, static bool hashmap_delete_node(isc_hashmap_t *hashmap, hashmap_node_t *entry, - uint32_t hashval, uint32_t psl, const uint8_t idx) { + uint32_t hashval, uint32_t psl, const uint8_t idx, + size_t size) { uint32_t pos; uint32_t hash; bool last = false; @@ -318,7 +319,7 @@ hashmap_delete_node(isc_hashmap_t *hashmap, hashmap_node_t *entry, hashmap->count--; hash = isc_hash_bits32(hashval, hashmap->tables[idx].hashbits); - pos = hash + psl; + pos = (hash + psl) & hashmap->tables[idx].hashmask; while (true) { hashmap_node_t *node = NULL; @@ -332,7 +333,7 @@ hashmap_delete_node(isc_hashmap_t *hashmap, hashmap_node_t *entry, break; } - if (pos == 0) { + if ((pos % size) == 0) { last = true; } @@ -373,7 +374,7 @@ hashmap_rehash_one(isc_hashmap_t *hashmap) { node = oldtable[hashmap->hiter]; (void)hashmap_delete_node(hashmap, &oldtable[hashmap->hiter], - node.hashval, node.psl, oldidx); + node.hashval, node.psl, oldidx, UINT32_MAX); isc_result_t result = hashmap_add(hashmap, node.hashval, NULL, node.key, node.value, NULL, hashmap->hindex); @@ -470,7 +471,8 @@ isc_hashmap_delete(isc_hashmap_t *hashmap, const uint32_t hashval, node = hashmap_find(hashmap, hashval, match, key, &psl, &idx); if (node != NULL) { INSIST(node->key != NULL); - (void)hashmap_delete_node(hashmap, node, hashval, psl, idx); + (void)hashmap_delete_node(hashmap, node, hashval, psl, idx, + UINT32_MAX); result = ISC_R_SUCCESS; } @@ -682,7 +684,7 @@ isc_hashmap_iter_delcurrent_next(isc_hashmap_iter_t *iter) { &iter->hashmap->tables[iter->hindex].table[iter->i]; if (hashmap_delete_node(iter->hashmap, node, node->hashval, node->psl, - iter->hindex)) + iter->hindex, iter->size)) { /* * We have seen the new last element so reduce the size