On Fri, Apr 18, 2025 at 11:12 PM Shim Manning <shimmann...@gmail.com> wrote:
>
> Seems that using .EXTRA_PREREQS can cause a segfault under the right 
> conditions.
...
> snap_deps
> hash_map_arg   (loop happens here)
> snap_file
> expand_extra_prereqs
> enter_file
> hash_insert_at
> hash_rehash  (loop no longer valid)
>
> causes a fairly consistent crash. I'm working on a minimal reproduction if 
> it's necessary, but allowing the table to be rehashed while iterating seems 
> like a problem.

Thank you for your report.
A test case to reproduce would be good. We'll need to add a test along
with a fix.
Given that you have a setup that crashes consistently, let me ask you
to try out this fix and tell us if this helps.

diff --git a/src/hash.c b/src/hash.c
index 41e16895..23d6cd4d 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -235,14 +235,16 @@ hash_map (struct hash_table *ht, hash_map_func_t map)
 void
 hash_map_arg (struct hash_table *ht, hash_map_arg_func_t map, void *arg)
 {
-  void **slot;
-  void **end = &ht->ht_vec[ht->ht_size];
-
-  for (slot = ht->ht_vec; slot < end; slot++)
-    {
-      if (!HASH_VACANT (*slot))
-        (*map) (*slot, arg);
-    }
+  /* Need to call 'map' for each item in 'ht'.
+    Cannot iterate through 'ht', because 'map' can attempt to insert to 'ht'
+    and cause 'ht' to be rehashed.  Copy all items from 'ht' to a temporary
+    array 't' and then iterate through the temporary array.  */
+  const struct file **t;
+  t = alloca (sizeof (const struct file *) * (ht->ht_fill + 1));
+  hash_dump (ht, (void **) t, 0);
+  /* t is null terminated.  */
+  for (; *t; ++t)
+    (*map) (*t, arg);
 }

 /* Double the size of the hash table in the event of overflow... */


regards, Dmitry

Reply via email to