summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/alloc.c6
-rw-r--r--src/alloc.h41
-rw-r--r--tests/alloc.c4
3 files changed, 29 insertions, 22 deletions
diff --git a/src/alloc.c b/src/alloc.c
index 4e68e13..79e4ce7 100644
--- a/src/alloc.c
+++ b/src/alloc.c
@@ -247,7 +247,7 @@ void arena_destroy(struct arena *arena) {
sanitize_uninit(arena);
}
-void varena_init(struct varena *varena, size_t align, size_t min, size_t offset, size_t size) {
+void varena_init(struct varena *varena, size_t align, size_t offset, size_t size) {
varena->align = align;
varena->offset = offset;
varena->size = size;
@@ -256,7 +256,7 @@ void varena_init(struct varena *varena, size_t align, size_t min, size_t offset,
// The smallest size class is at least as many as fit in the smallest
// aligned allocation size
- size_t min_count = (flex_size(align, min, offset, size, 1) - offset + size - 1) / size;
+ size_t min_count = (flex_size(align, offset, size, 1) - offset + size - 1) / size;
varena->shift = bit_width(min_count - 1);
}
@@ -269,7 +269,7 @@ static size_t varena_size_class(struct varena *varena, size_t count) {
/** Get the exact size of a flexible struct. */
static size_t varena_exact_size(const struct varena *varena, size_t count) {
- return flex_size(varena->align, 0, varena->offset, varena->size, count);
+ return flex_size(varena->align, varena->offset, varena->size, count);
}
/** Get the arena for the given array length. */
diff --git a/src/alloc.h b/src/alloc.h
index 34d9273..1fafbab 100644
--- a/src/alloc.h
+++ b/src/alloc.h
@@ -63,12 +63,30 @@ static inline size_t size_mul(size_t size, size_t count) {
sizeof(((type *)NULL)->member)
/**
+ * @internal
+ * Our flexible struct size calculations assume that structs have the minimum
+ * trailing padding to align the type properly. A pathological ABI that adds
+ * extra padding would result in us under-allocating space for those structs,
+ * so we static_assert() that no such padding exists.
+ */
+#define ASSERT_FLEX_ABI(type, member) \
+ ASSERT_FLEX_ABI_( \
+ ALIGN_CEIL(alignof(type), offsetof(type, member)) >= sizeof(type), \
+ "Unexpected tail padding in " #type)
+
+/**
+ * @internal
+ * The contortions here allow static_assert() to be used in expressions, rather
+ * than just declarations.
+ */
+#define ASSERT_FLEX_ABI_(...) \
+ ((void)sizeof(struct { char _; static_assert(__VA_ARGS__); }))
+
+/**
* Saturating flexible struct size.
*
* @align
* Struct alignment.
- * @min
- * Minimum struct size.
* @offset
* Flexible array member offset.
* @size
@@ -79,17 +97,10 @@ static inline size_t size_mul(size_t size, size_t count) {
* The size of the struct with count flexible array elements. Saturates
* to the maximum aligned value on overflow.
*/
-static inline size_t flex_size(size_t align, size_t min, size_t offset, size_t size, size_t count) {
+static inline size_t flex_size(size_t align, size_t offset, size_t size, size_t count) {
size_t ret = size_mul(size, count);
ret = size_add(ret, offset + align - 1);
ret = align_floor(align, ret);
-
- // Make sure flex_sizeof(type, member, 0) >= sizeof(type), even if the
- // type has more padding than necessary for alignment
- if (min > align_ceil(align, offset)) {
- ret = ret < min ? min : ret;
- }
-
return ret;
}
@@ -107,7 +118,8 @@ static inline size_t flex_size(size_t align, size_t min, size_t offset, size_t s
* to the maximum aligned value on overflow.
*/
#define sizeof_flex(type, member, count) \
- flex_size(alignof(type), sizeof(type), offsetof(type, member), sizeof_member(type, member[0]), count)
+ (ASSERT_FLEX_ABI(type, member), flex_size( \
+ alignof(type), offsetof(type, member), sizeof_member(type, member[0]), count))
/**
* General memory allocator.
@@ -298,14 +310,12 @@ struct varena {
* The varena to initialize.
* @align
* alignof(type)
- * @min
- * sizeof(type)
* @offset
* offsetof(type, flexible_array)
* @size
* sizeof(flexible_array[i])
*/
-void varena_init(struct varena *varena, size_t align, size_t min, size_t offset, size_t size);
+void varena_init(struct varena *varena, size_t align, size_t offset, size_t size);
/**
* Initialize a varena for the given type and flexible array.
@@ -318,7 +328,8 @@ void varena_init(struct varena *varena, size_t align, size_t min, size_t offset,
* The name of the flexible array member.
*/
#define VARENA_INIT(varena, type, member) \
- varena_init(varena, alignof(type), sizeof(type), offsetof(type, member), sizeof_member(type, member[0]))
+ (ASSERT_FLEX_ABI(type, member), varena_init( \
+ varena, alignof(type), offsetof(type, member), sizeof_member(type, member[0])))
/**
* Free an arena-allocated flexible struct.
diff --git a/tests/alloc.c b/tests/alloc.c
index 046613a..5fc934b 100644
--- a/tests/alloc.c
+++ b/tests/alloc.c
@@ -30,10 +30,6 @@ void check_alloc(void) {
size_t too_many = SIZE_MAX / sizeof(int) + 1;
bfs_check(sizeof_flex(struct flexible, bar, too_many) == align_floor(alignof(struct flexible), SIZE_MAX));
- // Corner case: sizeof(type) > align_ceil(alignof(type), offsetof(type, member))
- // Doesn't happen in typical ABIs
- bfs_check(flex_size(8, 16, 4, 4, 1) == 16);
-
// Make sure we detect allocation size overflows
#if __GNUC__ && !__clang__
# pragma GCC diagnostic ignored "-Walloc-size-larger-than="