diff options
author | Adrian Moreno <amorenoz@redhat.com> | 2022-03-23 12:56:16 +0100 |
---|---|---|
committer | Ilya Maximets <i.maximets@ovn.org> | 2022-03-30 20:13:34 +0200 |
commit | e3e1e2045ca8cf0c6c23c4b9e85900b874fb8904 (patch) | |
tree | 48aae80a5b6e98ca04efc363b93e8c196ccdb71e | |
parent | 6aa8de029153408c8e7f77c2978d1dfd05b9a39e (diff) | |
download | openvswitch-e3e1e2045ca8cf0c6c23c4b9e85900b874fb8904.tar.gz |
hmap: implement UB-safe hmap pop iterator.
HMAP_FOR_EACH_POP iterator has an additional difficulty, which is the
use of two iterator variables of different types.
In order to re-write this loop in a UB-safe manner, create a iterator
struct to be used as loop variable.
Acked-by: Dumitru Ceara <dceara@redhat.com>
Acked-by: Eelco Chaudron <echaudro@redhat.com>
Signed-off-by: Adrian Moreno <amorenoz@redhat.com>
Signed-off-by: Ilya Maximets <i.maximets@ovn.org>
-rw-r--r-- | include/openvswitch/hmap.h | 31 | ||||
-rw-r--r-- | tests/test-hmap.c | 1 |
2 files changed, 20 insertions, 12 deletions
diff --git a/include/openvswitch/hmap.h b/include/openvswitch/hmap.h index 610ad9987..68c284cf1 100644 --- a/include/openvswitch/hmap.h +++ b/include/openvswitch/hmap.h @@ -199,26 +199,33 @@ bool hmap_contains(const struct hmap *, const struct hmap_node *); CONDITION_MULTIVAR(NODE, MEMBER, ITER_VAR(NODE) != NULL); \ UPDATE_MULTIVAR(NODE, hmap_next(HMAP, ITER_VAR(NODE)))) -static inline struct hmap_node * -hmap_pop_helper__(struct hmap *hmap, size_t *bucket) { +struct hmap_pop_helper_iter__ { + size_t bucket; + struct hmap_node *node; +}; + +static inline void +hmap_pop_helper__(struct hmap *hmap, struct hmap_pop_helper_iter__ *iter) { - for (; *bucket <= hmap->mask; (*bucket)++) { - struct hmap_node *node = hmap->buckets[*bucket]; + for (; iter->bucket <= hmap->mask; (iter->bucket)++) { + struct hmap_node *node = hmap->buckets[iter->bucket]; if (node) { hmap_remove(hmap, node); - return node; + iter->node = node; + return; } } - - return NULL; + iter->node = NULL; } -#define HMAP_FOR_EACH_POP(NODE, MEMBER, HMAP) \ - for (size_t bucket__ = 0; \ - INIT_CONTAINER(NODE, hmap_pop_helper__(HMAP, &bucket__), MEMBER), \ - (NODE != OBJECT_CONTAINING(NULL, NODE, MEMBER)) \ - || ((NODE = NULL), false);) +#define HMAP_FOR_EACH_POP(NODE, MEMBER, HMAP) \ + for (struct hmap_pop_helper_iter__ ITER_VAR(NODE) = { 0, NULL }; \ + hmap_pop_helper__(HMAP, &ITER_VAR(NODE)), \ + (ITER_VAR(NODE).node != NULL) ? \ + (((NODE) = OBJECT_CONTAINING(ITER_VAR(NODE).node, \ + NODE, MEMBER)),1): \ + (((NODE) = NULL), 0);) static inline struct hmap_node *hmap_first(const struct hmap *); static inline struct hmap_node *hmap_next(const struct hmap *, diff --git a/tests/test-hmap.c b/tests/test-hmap.c index a40ac8953..47b475538 100644 --- a/tests/test-hmap.c +++ b/tests/test-hmap.c @@ -317,6 +317,7 @@ test_hmap_for_each_pop(hash_func *hash) i++; } assert(i == n); + assert(e == NULL); hmap_destroy(&hmap); } |