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__`. 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


Reply via email to