]> git.ipfire.org Git - thirdparty/freeradius-server.git/commitdiff
Add namesapce/hashtable validation
authorArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 29 Jun 2021 17:17:33 +0000 (12:17 -0500)
committerArran Cudbard-Bell <a.cudbardb@freeradius.org>
Tue, 29 Jun 2021 17:17:43 +0000 (12:17 -0500)
src/lib/util/dict_util.c
src/lib/util/hash.c
src/lib/util/hash.h

index e88028cfaec54ecdb32a7673c48e3aa784a801a7..b5853b6f330fc45e9b8cb92aca97d02febbb5dab 100644 (file)
@@ -484,7 +484,8 @@ static inline CC_HINT(always_inline) int dict_attr_namespace_init(fr_dict_attr_t
         *      namespace hash table.
         */
        if (!ext->namespace) {
-               ext->namespace = fr_hash_table_alloc(*da_p, dict_attr_name_hash, dict_attr_name_cmp, NULL);
+               ext->namespace = fr_hash_table_talloc_alloc(*da_p, fr_dict_attr_t,
+                                                           dict_attr_name_hash, dict_attr_name_cmp, NULL);
                if (!ext->namespace) {
                        fr_strerror_printf("Failed allocating \"namespace\" table");
                        return -1;
@@ -1261,13 +1262,15 @@ int dict_attr_enum_add_name(fr_dict_attr_t *da, char const *name,
         *      Initialise enumv hash tables
         */
        if (!ext->value_by_name || !ext->name_by_value) {
-               ext->value_by_name = fr_hash_table_alloc(da, dict_enum_name_hash, dict_enum_name_cmp, hash_pool_free);
+               ext->value_by_name = fr_hash_table_talloc_alloc(da, fr_dict_enum_t, dict_enum_name_hash,
+                                                               dict_enum_name_cmp, hash_pool_free);
                if (!ext->value_by_name) {
                        fr_strerror_printf("Failed allocating \"value_by_name\" table");
                        return -1;
                }
 
-               ext->name_by_value = fr_hash_table_alloc(da, dict_enum_value_hash, dict_enum_value_cmp, NULL);
+               ext->name_by_value = fr_hash_table_talloc_alloc(da, fr_dict_enum_t, dict_enum_value_hash,
+                                                               dict_enum_value_cmp, NULL);
                if (!ext->name_by_value) {
                        fr_strerror_printf("Failed allocating \"name_by_value\" table");
                        return -1;
@@ -3839,7 +3842,7 @@ void fr_dict_attr_verify(char const *file, int line, fr_dict_attr_t const *da)
                /*
                 *      Check the namespace hash table is ok
                 */
-               (void)talloc_get_type_abort(dict_attr_namespace(da), fr_hash_table_t);
+               fr_hash_table_verify(dict_attr_namespace(da));
        }
                break;
 
index 454e1fc1078a32e45f7be4901413e154d689fbb4..a90c707167e5f32b5a896c7d040d17f8fc9fb1cb 100644 (file)
@@ -49,18 +49,19 @@ struct fr_hash_entry_s {
 };
 
 struct fr_hash_table_s {
-       uint32_t                num_elements;
-       uint32_t                num_buckets; /* power of 2 */
+       uint32_t                num_elements;   //!< Number of elements in the hash table.
+       uint32_t                num_buckets;    //!< Number of buckets (how long the array is) - power of 2 */
        uint32_t                next_grow;
        uint32_t                mask;
 
-       fr_free_t               free;
-       fr_hash_t               hash;
-       fr_cmp_t                cmp;
+       fr_free_t               free;           //!< Data free function.
+       fr_hash_t               hash;           //!< Hashing function.
+       fr_cmp_t                cmp;            //!< Comparison function.
 
-       fr_hash_entry_t         null;
+       char const              *type;          //!< Talloc type to check elements against.
 
-       fr_hash_entry_t         **buckets;
+       fr_hash_entry_t         null;
+       fr_hash_entry_t         **buckets;      //!< Array of hash buckets.
 };
 
 #ifdef TESTING
@@ -277,32 +278,35 @@ static int _fr_hash_table_free(fr_hash_table_t *ht)
  *
  *     Memory usage in bytes is (20/3) * number of entries.
  */
-fr_hash_table_t *fr_hash_table_alloc(TALLOC_CTX *ctx,
-                                    fr_hash_t hash_func,
-                                    fr_cmp_t cmp_func,
-                                    fr_free_t free_func)
+fr_hash_table_t *_fr_hash_table_alloc(TALLOC_CTX *ctx,
+                                     char const *type,
+                                     fr_hash_t hash_func,
+                                     fr_cmp_t cmp_func,
+                                     fr_free_t free_func)
 {
        fr_hash_table_t *ht;
 
-       ht = talloc_zero(ctx, fr_hash_table_t);
+       ht = talloc(ctx, fr_hash_table_t);
        if (!ht) return NULL;
        talloc_set_destructor(ht, _fr_hash_table_free);
 
-       ht->free = free_func;
-       ht->hash = hash_func;
-       ht->cmp = cmp_func;
-       ht->num_buckets = FR_HASH_NUM_BUCKETS;
-       ht->mask = ht->num_buckets - 1;
-
-       /*
-        *      Have a default load factor of 2.5.  In practice this
-        *      means that the average load will hit 3 before the
-        *      table grows.
-        */
-       ht->next_grow = (ht->num_buckets << 1) + (ht->num_buckets >> 1);
+       *ht = (fr_hash_table_t){
+               .type = type,
+               .free = free_func,
+               .hash = hash_func,
+               .cmp = cmp_func,
+               .num_buckets = FR_HASH_NUM_BUCKETS,
+               .mask = FR_HASH_NUM_BUCKETS - 1,
 
-       ht->buckets = talloc_zero_array(ht, fr_hash_entry_t *, ht->num_buckets);
-       if (!ht->buckets) {
+               /*
+                *      Have a default load factor of 2.5.  In practice this
+                *      means that the average load will hit 3 before the
+                *      table grows.
+                */
+               .next_grow = (FR_HASH_NUM_BUCKETS << 1) + (FR_HASH_NUM_BUCKETS >> 1),
+               .buckets = talloc_zero_array(ht, fr_hash_entry_t *, FR_HASH_NUM_BUCKETS)
+       };
+       if (unlikely(!ht->buckets)) {
                talloc_free(ht);
                return NULL;
        }
@@ -467,6 +471,10 @@ bool fr_hash_table_insert(fr_hash_table_t *ht, void const *data)
        uint32_t                reversed;
        fr_hash_entry_t         *node;
 
+#ifndef TALLOC_GET_TYPE_ABORT_NOOP
+       if (ht->type) (void)_talloc_get_type_abort(data, ht->type, __location__);
+#endif
+
        key = ht->hash(data);
        entry = key & ht->mask;
        reversed = reverse(key);
@@ -876,6 +884,31 @@ uint32_t fr_hash_case_string(char const *p)
        return hash;
 }
 
+/** Check hash table is sane
+ *
+ */
+void fr_hash_table_verify(fr_hash_table_t *ht)
+{
+       fr_hash_iter_t  iter;
+       void            *ptr;
+
+       (void)talloc_get_type_abort(ht, fr_hash_table_t);
+       (void)talloc_get_type_abort(ht->buckets, fr_hash_entry_t *);
+
+       fr_assert(talloc_array_length(ht->buckets) == ht->num_buckets);
+
+       /*
+        *      Check talloc headers on all data
+        */
+       if (ht->type) {
+               for (ptr = fr_hash_table_iter_init(ht, &iter);
+                    ptr;
+                    ptr = fr_hash_table_iter_next(ht, &iter)) {
+                       (void)_talloc_get_type_abort(ptr, ht->type, __location__);
+               }
+       }
+}
+
 #ifdef TESTING
 /*
  *  cc -g -DTESTING -I ../include hash.c -o hash
index 0b3d75c887a305fc6e16743a3254f1527534376c..d5c78ab4ef331243cd3484bf05abad369ad33a8d 100644 (file)
@@ -55,10 +55,17 @@ uint32_t fr_hash_case_string(char const *p);
 typedef struct fr_hash_table_s fr_hash_table_t;
 typedef int (*fr_hash_table_walk_t)(void *data, void *uctx);
 
-fr_hash_table_t *fr_hash_table_alloc(TALLOC_CTX *ctx,
-                                    fr_hash_t hash_node,
-                                    fr_cmp_t cmp_node,
-                                    fr_free_t free_node) CC_HINT(nonnull(2,3));
+#define                fr_hash_table_alloc(_ctx, _hash_node, _cmp_node, _free_node) \
+               _fr_hash_table_alloc(_ctx, NULL, _hash_node, _cmp_node, _free_node)
+
+#define                fr_hash_table_talloc_alloc(_ctx, _type, _hash_node, _cmp_node, _free_node) \
+               _fr_hash_table_alloc(_ctx, #_type, _hash_node, _cmp_node, _free_node)
+
+fr_hash_table_t *_fr_hash_table_alloc(TALLOC_CTX *ctx,
+                                     char const *type,
+                                     fr_hash_t hash_node,
+                                     fr_cmp_t cmp_node,
+                                     fr_free_t free_node) CC_HINT(nonnull(3,4));
 
 void           *fr_hash_table_find(fr_hash_table_t *ht, void const *data) CC_HINT(nonnull);
 
@@ -82,6 +89,8 @@ int           fr_hash_table_flatten(TALLOC_CTX *ctx, void **out[], fr_hash_table_t *ht) C
 
 void           fr_hash_table_fill(fr_hash_table_t *ht) CC_HINT(nonnull);
 
+void           fr_hash_table_verify(fr_hash_table_t *ht);
+
 #ifdef __cplusplus
 }
 #endif