From e25261a90222de75781726a93ab809c660208afd Mon Sep 17 00:00:00 2001 From: Tavian Barnes Date: Thu, 9 Nov 2023 15:16:04 -0500 Subject: config: Add (de)allocator attributes --- src/alloc.h | 40 +++++++++++++++++++++++----------------- src/config.h | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ src/dstring.h | 21 +++++++++++++-------- tests/alloc.c | 4 ++++ 4 files changed, 89 insertions(+), 25 deletions(-) diff --git a/src/alloc.h b/src/alloc.h index fd3e5f0..34f6949 100644 --- a/src/alloc.h +++ b/src/alloc.h @@ -9,7 +9,7 @@ #define BFS_ALLOC_H #include "config.h" -#include +#include /** Round down to a multiple of an alignment. */ static inline size_t align_floor(size_t align, size_t size) { @@ -108,6 +108,8 @@ static inline size_t flex_size(size_t align, size_t min, size_t offset, size_t s * @return * The allocated memory, or NULL on failure. */ +attr_malloc(free, 1) +attr_aligned_alloc(1, 2) void *alloc(size_t align, size_t size); /** @@ -120,6 +122,8 @@ void *alloc(size_t align, size_t size); * @return * The allocated memory, or NULL on failure. */ +attr_malloc(free, 1) +attr_aligned_alloc(1, 2) void *zalloc(size_t align, size_t size); /** Allocate memory for the given type. */ @@ -176,14 +180,15 @@ void arena_init(struct arena *arena, size_t align, size_t size); arena_init((arena), alignof(type), sizeof(type)) /** - * Allocate an object out of the arena. + * Free an object from the arena. */ -void *arena_alloc(struct arena *arena); +void arena_free(struct arena *arena, void *ptr); /** - * Free an object from the arena. + * Allocate an object out of the arena. */ -void arena_free(struct arena *arena, void *ptr); +attr_malloc(arena_free, 2) +void *arena_alloc(struct arena *arena); /** * Free all allocations from an arena. @@ -242,6 +247,18 @@ void varena_init(struct varena *varena, size_t align, size_t min, size_t offset, #define VARENA_INIT(varena, type, member) \ varena_init(varena, alignof(type), sizeof(type), offsetof(type, member), sizeof_member(type, member[0])) +/** + * Free an arena-allocated flexible struct. + * + * @param varena + * The that allocated the object. + * @param ptr + * The object to free. + * @param count + * The length of the flexible array. + */ +void varena_free(struct varena *varena, void *ptr, size_t count); + /** * Arena-allocate a flexible struct. * @@ -252,6 +269,7 @@ void varena_init(struct varena *varena, size_t align, size_t min, size_t offset, * @return * The allocated struct, or NULL on failure. */ +attr_malloc(varena_free, 2) void *varena_alloc(struct varena *varena, size_t count); /** @@ -284,18 +302,6 @@ void *varena_realloc(struct varena *varena, void *ptr, size_t old_count, size_t */ void *varena_grow(struct varena *varena, void *ptr, size_t *count); -/** - * Free an arena-allocated flexible struct. - * - * @param varena - * The that allocated the object. - * @param ptr - * The object to free. - * @param count - * The length of the flexible array. - */ -void varena_free(struct varena *varena, void *ptr, size_t count); - /** * Free all allocations from a varena. */ diff --git a/src/config.h b/src/config.h index b95abaa..db62ef8 100644 --- a/src/config.h +++ b/src/config.h @@ -184,6 +184,17 @@ # define fallthru ((void)0) #endif +/** + * Warn if a value is unused. + */ +#if __has_c_attribute(nodiscard) +# define attr_nodiscard [[nodiscard]] +#elif __has_attribute(nodiscard) +# define attr_nodiscard __attribute__((nodiscard)) +#else +# define attr_nodiscard +#endif + /** * Hint to avoid inlining a function. */ @@ -211,6 +222,44 @@ # define attr_format(fmt, args) #endif +/** + * Annotates allocator-like functions. + */ +#if __has_attribute(malloc) +# if __clang__ +# define attr_malloc(...) attr_nodiscard __attribute__((malloc)) +# else +# define attr_malloc(...) attr_nodiscard __attribute__((malloc(__VA_ARGS__))) +# endif +#else +# define attr_malloc(...) attr_nodiscard +#endif + +/** + * Specifies that a function returns allocations with a given alignment. + */ +#if __has_attribute(alloc_align) +# define attr_alloc_align(param) __attribute__((alloc_align(param))) +#else +# define attr_alloc_align(param) +#endif + +/** + * Specifies that a function returns allocations with a given size. + */ +#if __has_attribute(alloc_size) +# define attr_alloc_size(...) __attribute__((alloc_size(__VA_ARGS__))) +#else +# define attr_alloc_size(...) +#endif + +/** + * Shorthand for attr_alloc_align() and attr_alloc_size(). + */ +#define attr_aligned_alloc(align, ...) \ + attr_alloc_align(align) \ + attr_alloc_size(__VA_ARGS__) + /** * Check if function multiversioning via GNU indirect functions (ifunc) is supported. */ diff --git a/src/dstring.h b/src/dstring.h index fd98df8..07b4ee9 100644 --- a/src/dstring.h +++ b/src/dstring.h @@ -27,12 +27,21 @@ typedef __attribute__((aligned(alignof(size_t)))) char dchar; typedef char dchar; #endif +/** + * Free a dynamic string. + * + * @param dstr + * The string to free. + */ +void dstrfree(dchar *dstr); + /** * Allocate a dynamic string. * * @param capacity * The initial capacity of the string. */ +attr_malloc(dstrfree, 1) dchar *dstralloc(size_t capacity); /** @@ -41,6 +50,7 @@ dchar *dstralloc(size_t capacity); * @param str * The NUL-terminated string to copy. */ +attr_malloc(dstrfree, 1) dchar *dstrdup(const char *str); /** @@ -51,6 +61,7 @@ dchar *dstrdup(const char *str); * @param n * The maximum number of characters to copy from str. */ +attr_malloc(dstrfree, 1) dchar *dstrndup(const char *str, size_t n); /** @@ -59,6 +70,7 @@ dchar *dstrndup(const char *str, size_t n); * @param dstr * The dynamic string to copy. */ +attr_malloc(dstrfree, 1) dchar *dstrddup(const dchar *dstr); /** @@ -69,6 +81,7 @@ dchar *dstrddup(const dchar *dstr); * @param len * The length of the string, which may include internal NUL bytes. */ +attr_malloc(dstrfree, 1) dchar *dstrxdup(const char *str, size_t len); /** @@ -306,12 +319,4 @@ int dstrescat(dchar **dest, const char *str, enum wesc_flags flags); */ int dstrnescat(dchar **dest, const char *str, size_t n, enum wesc_flags flags); -/** - * Free a dynamic string. - * - * @param dstr - * The string to free. - */ -void dstrfree(dchar *dstr); - #endif // BFS_DSTRING_H diff --git a/tests/alloc.c b/tests/alloc.c index 2334241..37b70bf 100644 --- a/tests/alloc.c +++ b/tests/alloc.c @@ -24,6 +24,10 @@ int main(void) { bfs_verify(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=" +#endif + bfs_verify(ALLOC_ARRAY(int, too_many) == NULL && errno == EOVERFLOW); bfs_verify(ZALLOC_ARRAY(int, too_many) == NULL && errno == EOVERFLOW); bfs_verify(ALLOC_FLEX(struct flexible, bar, too_many) == NULL && errno == EOVERFLOW); -- cgit v1.2.3