]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
hash.h: HASH_DO_REMOVE and HASH_INSERT macros can not be called from HASH_WALK, asser...
authorKaterina Kubecova <katerina.kubecova@nic.cz>
Wed, 27 Mar 2024 13:29:51 +0000 (14:29 +0100)
committerOndrej Zajicek <santiago@crfreenet.org>
Tue, 23 Apr 2024 14:36:49 +0000 (16:36 +0200)
lib/hash.h
lib/hash_test.c
nest/cmds.c
nest/mpls.c
proto/aggregator/aggregator.c
proto/bfd/bfd.c

index 3c173958ff8146b006c748ddc9715ea4a59d7ea4..02f7161bda6746fcccdee561c39b3ba2456d7970 100644 (file)
@@ -10,7 +10,7 @@
 #ifndef _BIRD_HASH_H_
 #define _BIRD_HASH_H_
 
-#define HASH(type)             struct { type **data; uint count, order; }
+#define HASH(type)             struct { type **data; uint count, order; char* is_in_walk; }
 #define HASH_TYPE(v)           typeof(** (v).data)
 #define HASH_SIZE(v)           (1U << (v).order)
 
@@ -23,6 +23,8 @@
     (v).count = 0;                                                     \
     (v).order = (init_order);                                          \
     (v).data = mb_allocz(pool, HASH_SIZE(v) * sizeof(* (v).data));     \
+    (v).is_in_walk = mb_allocz(pool, sizeof(char));                    \
+    *(v).is_in_walk = 0;                                               \
   })
 
 #define HASH_FREE(v)                                                   \
@@ -42,6 +44,8 @@
 
 #define HASH_INSERT(v,id,node)                                         \
   ({                                                                   \
+    if (*(v).is_in_walk)                                               \
+      bug("HASH_INSERT: Attempt to insert in HASH_WALK");              \
     u32 _h = HASH_FN(v, id, id##_KEY((node)));                         \
     HASH_TYPE(v) **_nn = (v).data + _h;                                        \
     id##_NEXT(node) = *_nn;                                            \
@@ -51,6 +55,8 @@
 
 #define HASH_DO_REMOVE(v,id,_nn)                                       \
   ({                                                                   \
+    if (*(v).is_in_walk)                                               \
+      bug("HASH_DELETE: Attempt to remove in HASH_WALK");              \
     *_nn = id##_NEXT((*_nn));                                          \
     (v).count--;                                                       \
   })
 #define HASH_WALK(v,next,n)                                            \
   do {                                                                 \
     HASH_TYPE(v) *n;                                                   \
+    *(v).is_in_walk = 1;                                               \
     uint _i;                                                           \
     uint _s = HASH_SIZE(v);                                            \
     for (_i = 0; _i < _s; _i++)                                                \
       for (n = (v).data[_i]; n; n = n->next)
 
-#define HASH_WALK_END } while (0)
+#define HASH_WALK_END(v) *(v).is_in_walk = 0; } while (0)
 
 
 #define HASH_WALK_DELSAFE(v,next,n)                                    \
index 4bce70179e0fcdf0416421018e1d8ec86de97100..6a175b31f82952208dc066eb4cc4e1d96b770c88 100644 (file)
@@ -185,7 +185,7 @@ t_walk(void)
   {
     check[n->key]++;
   }
-  HASH_WALK_END;
+  HASH_WALK_END(hash);
 
   for (i = 0; i < MAX_NUM; i++)
     bt_assert(check[i] == 1);
@@ -285,6 +285,26 @@ t_walk_filter(void)
   return 1;
 }
 
+void
+do_walk_delete_error(void)
+{
+    init_hash();
+  fill_hash();
+
+  HASH_WALK(hash, next, n)
+  {
+    HASH_DELETE(hash, TEST, n->key);
+  }
+  HASH_WALK_END(hash);
+}
+
+static int
+t_walk_check_bug(void)
+{
+  return bt_assert_bug(do_walk_delete_error, "HASH_DELETE: Attempt to remove in HASH_WALK");
+}
+
+
 int
 main(int argc, char *argv[])
 {
@@ -299,6 +319,7 @@ main(int argc, char *argv[])
   bt_test_suite(t_walk_delsafe_remove,         "HASH_WALK_DELSAFE and HASH_REMOVE");
   bt_test_suite(t_walk_delsafe_remove2,        "HASH_WALK_DELSAFE and HASH_REMOVE2. HASH_REMOVE2 is HASH_REMOVE and smart auto-resize function");
   bt_test_suite(t_walk_filter,         "HASH_WALK_FILTER");
+  bt_test_suite(t_walk_check_bug,      "HASH_DO_REMOVE returns error, because called from HASH_WALK");
 
   return bt_exit_value();
 }
index d49bbc53c32384454d7f38f8537142943adbe365..692743b1230d4d82414d16cff758c5e2bfb1ec6e 100644 (file)
@@ -62,7 +62,7 @@ cmd_show_symbols(struct sym_show_data *sd)
 
        cli_msg(-1010, "%-8s\t%s", sym->name, cf_symbol_class_name(sym));
       }
-      HASH_WALK_END;
+      HASH_WALK_END(scope->hash);
 
     cli_msg(0, "");
   }
index 9cdcd572adef497b583341a920117d13016a71e8..9963006edf585ba0ad05a0956311975c9ab0237c 100644 (file)
@@ -755,7 +755,7 @@ mpls_fec_map_reconfigure(struct mpls_fec_map *m, struct channel *C)
     mpls_unlink_fec(m, fec);
     fec->policy = MPLS_POLICY_NONE;
   }
-  HASH_WALK_END;
+  HASH_WALK_END(m->label_hash);
 
   /* Remove old unused handles */
 
@@ -777,7 +777,7 @@ mpls_fec_map_free(struct mpls_fec_map *m)
       rta_free(fec->rta);
       fec->rta = NULL;
     }
-    HASH_WALK_END;
+    HASH_WALK_END(m->rta_hash);
   }
 
   /* Free allocated labels */
@@ -788,7 +788,7 @@ mpls_fec_map_free(struct mpls_fec_map *m)
     if (!fec->policy && !fec->handle->label_count)
       mpls_free_handle(m->domain, fec->handle);
   }
-  HASH_WALK_END;
+  HASH_WALK_END(m->label_hash);
 
   if (m->static_handle)
     mpls_free_handle(m->domain, m->static_handle);
index e5c2a176826c1a42f0bb55f914eccae4ff39f032..0ea2f497f41b0bf08b5b2186194cc97d03dee067 100644 (file)
@@ -254,7 +254,7 @@ aggregator_reload_buckets(void *data)
       aggregator_bucket_update(p, b, b->rte->net);
       lp_flush(rte_update_pool);
     }
-  HASH_WALK_END;
+  HASH_WALK_END(p->buckets);
 }
 
 
@@ -732,7 +732,7 @@ aggregator_shutdown(struct proto *P)
     HASH_REMOVE(p->buckets, AGGR_BUCK, b);
     sl_free(b);
   }
-  HASH_WALK_END;
+  HASH_WALK_END(p->buckets);
 
   return PS_DOWN;
 }
index 4f8499bacdfa4326eed4df8018e7406b780161f3..272d27c0d4d039d2ab3cf1098b2a05995aa2d174 100644 (file)
@@ -764,7 +764,7 @@ bfd_drop_requests(struct bfd_proto *p)
     WALK_LIST_FIRST(n, s->request_list)
       bfd_submit_request(SKIP_BACK(struct bfd_request, n, n));
   }
-  HASH_WALK_END;
+  HASH_WALK_END(p->session_hash_id);
 }
 
 static struct resclass bfd_request_class;
@@ -1162,7 +1162,7 @@ bfd_reconfigure(struct proto *P, struct proto_config *c)
     if (s->ifa->changed)
       bfd_reconfigure_session(p, s);
   }
-  HASH_WALK_END;
+  HASH_WALK_END(p->session_hash_id);
 
   bfd_reconfigure_neighbors(p, new);
 
@@ -1289,7 +1289,7 @@ bfd_show_sessions(struct proto *P, struct bfd_show_sessions_cmd *args)
 
     bfd_show_session(s, args->verbose);
   }
-  HASH_WALK_END;
+  HASH_WALK_END(p->session_hash_id);
 }