Hello, Milos Nikic, le ven. 27 mars 2026 22:04:22 -0700, a ecrit: > In HURD_IHASH_ITERATE and HURD_IHASH_ITERATE_ITEMS, the hash table > argument (ht) was evaluated multiple times during loop initialization > and condition checking. If a caller passed an expression with side > effects (e.g., a function call returning a table pointer), it would > be executed repeatedly per loop, leading to performance degradation > or unintended behavior. > > Fix this by wrapping the iterators in an outer `for` loop that > evaluates and caches `(ht)` exactly once using `__typeof__`.
Please read the comment above: We can not use two for-loops, because we want a break statement inside the iterator block to terminate the operation. Samuel > Token > pasting (##) is used to generate a unique cache variable name based > on the caller's item identifier, safely allowing these macros to be > nested without variable shadowing or naming collisions. > --- > libihash/ihash.h | 46 +++++++++++++++++++++++++++++----------------- > 1 file changed, 29 insertions(+), 17 deletions(-) > > diff --git a/libihash/ihash.h b/libihash/ihash.h > index 80679f14..5f73f3e1 100644 > --- a/libihash/ihash.h > +++ b/libihash/ihash.h > @@ -322,17 +322,22 @@ hurd_ihash_value_t hurd_ihash_locp_find (hurd_ihash_t > ht, > pointer pointed to must not have an influence on the condition > result, so the comma operator is used to make sure this > subexpression is always true). */ > -#define HURD_IHASH_ITERATE(ht, val) \ > - for (hurd_ihash_value_t val, > \ > - *_hurd_ihash_valuep = (ht)->size ? &(ht)->items[0].value : 0; > \ > - (ht)->size \ > - && (size_t) ((_hurd_ihash_item_t) _hurd_ihash_valuep \ > - - &(ht)->items[0]) \ > - < (ht)->size \ > - && (val = *_hurd_ihash_valuep, 1); \ > - _hurd_ihash_valuep = (hurd_ihash_value_t *) \ > - (((_hurd_ihash_item_t) _hurd_ihash_valuep) + 1)) \ > - if (val != _HURD_IHASH_EMPTY && val != _HURD_IHASH_DELETED) > +#define HURD_IHASH_ITERATE(ht, val) > \ > + /* Cache 'ht' to prevent multiple evaluation of functions. */ > \ > + for (__typeof__(ht) _ihash_ht_##val = (ht); > \ > + _ihash_ht_##val != NULL; > \ > + _ihash_ht_##val = NULL) > \ > + for (hurd_ihash_value_t val, > \ > + *_ihash_p_##val = _ihash_ht_##val->size > \ > + ? &_ihash_ht_##val->items[0].value : 0; > \ > + _ihash_ht_##val->size > \ > + && (size_t) ((_hurd_ihash_item_t) _ihash_p_##val > \ > + - &_ihash_ht_##val->items[0]) > \ > + < _ihash_ht_##val->size > \ > + && (((val) = *_ihash_p_##val), 1); > \ > + _ihash_p_##val = (hurd_ihash_value_t *) > \ > + (((_hurd_ihash_item_t) _ihash_p_##val) + 1)) > \ > + if ((val) != _HURD_IHASH_EMPTY && (val) != _HURD_IHASH_DELETED) > > /* Iterate over all elements in the hash table making both the key and > the value available. You use this macro with a block, for example > @@ -344,12 +349,19 @@ hurd_ihash_value_t hurd_ihash_locp_find (hurd_ihash_t > ht, > The block will be run for every element in the hash table HT. The > key and value of the current element is available as ITEM->key and > ITEM->value. */ > -#define HURD_IHASH_ITERATE_ITEMS(ht, item) \ > - for (_hurd_ihash_item_t item = (ht)->size? &(ht)->items[0]: 0; \ > - (ht)->size && item - &(ht)->items[0] < (ht)->size; \ > - item++) \ > - if (item->value != _HURD_IHASH_EMPTY && \ > - item->value != _HURD_IHASH_DELETED) > +#define HURD_IHASH_ITERATE_ITEMS(ht, item) > \ > + /* Cache 'ht' to prevent multiple evaluation of functions. */ > \ > + for (__typeof__(ht) _ihash_items_ht_##item = (ht); > \ > + _ihash_items_ht_##item != NULL; > \ > + _ihash_items_ht_##item = NULL) > \ > + for (_hurd_ihash_item_t item = _ihash_items_ht_##item->size > \ > + ? &_ihash_items_ht_##item->items[0] : 0; > \ > + _ihash_items_ht_##item->size > \ > + && (size_t) ((item) - &_ihash_items_ht_##item->items[0]) > \ > + < _ihash_items_ht_##item->size; > \ > + (item)++) > \ > + if ((item)->value != _HURD_IHASH_EMPTY && > \ > + (item)->value != _HURD_IHASH_DELETED) > > /* Remove the entry with the key KEY from the hash table HT. If such > an entry was found and removed, 1 is returned, otherwise 0. */ > -- > 2.53.0 > > -- Samuel <s> T'as pas de portable ? <m> J'ai un nokia, dans le bassin d'arcachon
