The most natural use of the 'flexmember' module is to allocate memory for a
struct { <some_fields>; <array_elt_type> member [FLEXIBLE_ARRAY_MEMBER]; } I was surprised to see that for this use, one has to pass <number_of_array_elements> * sizeof (<array_elt_type>) as third argument to FLEXSIZEOF, not merely <number_of_array_elements>. I made the mistake of not doing the multiplication (in some new code). And Marc, in the 'hamt' module, make the mistake of passing sizeof (Hamt_entry) rather than sizeof (Hamt_entry *). So, for better usability, it's good to have a macro that acts like FLEXSIZEOF, except that it expects an element count instead of a byte count as third argument. 2023-05-26 Bruno Haible <br...@clisp.org> flexmember: Make it easier to use. * lib/flexmember.h (FLEXNSIZEOF): New macro. * lib/hamt.c (alloc_bucket, alloc_subtrie): Fix FLEXSIZEOF invocation. Use FLEXNSIZEOF instead of FLEXSIZEOF. * lib/ssfmalloc.h (init_small_block_page_pool): Use FLEXNSIZEOF instead of FLEXSIZEOF. diff --git a/lib/flexmember.h b/lib/flexmember.h index 8c5915ecf9..8df4419539 100644 --- a/lib/flexmember.h +++ b/lib/flexmember.h @@ -43,7 +43,7 @@ followed by N bytes of other data. The result is suitable as an argument to malloc. For example: - struct s { int n; char d[FLEXIBLE_ARRAY_MEMBER]; }; + struct s { int a; char d[FLEXIBLE_ARRAY_MEMBER]; }; struct s *p = malloc (FLEXSIZEOF (struct s, d, n * sizeof (char))); FLEXSIZEOF (TYPE, MEMBER, N) is not simply (sizeof (TYPE) + N), @@ -63,3 +63,14 @@ #define FLEXSIZEOF(type, member, n) \ ((offsetof (type, member) + FLEXALIGNOF (type) - 1 + (n)) \ & ~ (FLEXALIGNOF (type) - 1)) + +/* Yield a properly aligned upper bound on the size of a struct of + type TYPE with a flexible array member named MEMBER that has N + elements. The result is suitable as an argument to malloc. + For example: + + struct s { int a; double d[FLEXIBLE_ARRAY_MEMBER]; }; + struct s *p = malloc (FLEXNSIZEOF (struct s, d, n)); + */ +#define FLEXNSIZEOF(type, member, n) \ + FLEXSIZEOF (type, member, (n) * sizeof (((type *) 0)->member[0])) diff --git a/lib/hamt.c b/lib/hamt.c index 8cbca387f0..6f39b77c2f 100644 --- a/lib/hamt.c +++ b/lib/hamt.c @@ -214,8 +214,7 @@ static struct bucket * alloc_bucket (size_t elt_count) { struct bucket *bucket - = xmalloc (FLEXSIZEOF (struct bucket, elts, - sizeof (Hamt_entry) * elt_count)); + = xmalloc (FLEXNSIZEOF (struct bucket, elts, elt_count)); init_ref_counter (&bucket->ref_counter, bucket_entry); bucket->elt_count = elt_count; return bucket; @@ -251,8 +250,7 @@ static struct subtrie * alloc_subtrie (int node_count) { struct subtrie *subtrie - = xmalloc (FLEXSIZEOF (struct subtrie, nodes, - sizeof (Hamt_entry) * node_count)); + = xmalloc (FLEXNSIZEOF (struct subtrie, nodes, node_count)); init_ref_counter (&subtrie->ref_count, subtrie_entry); return subtrie; } diff --git a/lib/ssfmalloc.h b/lib/ssfmalloc.h index 87f44014e4..5dd69c8199 100644 --- a/lib/ssfmalloc.h +++ b/lib/ssfmalloc.h @@ -332,8 +332,8 @@ static unsigned int small_block_page_num_bitmap_words; struct small_page_header { struct dissected_page_header common; - /* Two bitmaps, each with small_block_page_num_bitmap_words. In each a bit - represents ALIGNMENT bytes. + /* Two bitmaps, each with small_block_page_num_bitmap_words words. In each + a bit represents ALIGNMENT bytes. - available_bitmap: bit set means available, bit clear means allocated. - blockend_bitmap: bit set means the an allocated block ends here. */ uint32_t bitmap_words[FLEXIBLE_ARRAY_MEMBER]; @@ -365,8 +365,8 @@ init_small_block_page_pool (struct page_pool *pool) { num_bitmap_words = (num_bits + 32 - 1) / 32; blocks_start = - (FLEXSIZEOF (struct small_page_header, bitmap_words, - 2 * num_bitmap_words * sizeof (uint32_t)) + (FLEXNSIZEOF (struct small_page_header, bitmap_words, + 2 * num_bitmap_words) + ALIGNMENT - 1) & -ALIGNMENT; unsigned int num_bits_r = (unsigned int) (PAGESIZE - blocks_start) / ALIGNMENT; if (num_bits_r >= num_bits)