Skip to content

Commit

Permalink
config: Add (de)allocator attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
tavianator committed Nov 9, 2023
1 parent c745df9 commit e25261a
Show file tree
Hide file tree
Showing 4 changed files with 89 additions and 25 deletions.
40 changes: 23 additions & 17 deletions src/alloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
#define BFS_ALLOC_H

#include "config.h"
#include <stddef.h>
#include <stdlib.h>

/** Round down to a multiple of an alignment. */
static inline size_t align_floor(size_t align, size_t size) {
Expand Down Expand Up @@ -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);

/**
Expand All @@ -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. */
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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.
*
Expand All @@ -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);

/**
Expand Down Expand Up @@ -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.
*/
Expand Down
49 changes: 49 additions & 0 deletions src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
*/
Expand Down Expand Up @@ -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.
*/
Expand Down
21 changes: 13 additions & 8 deletions src/dstring.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);

/**
Expand All @@ -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);

/**
Expand All @@ -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);

/**
Expand All @@ -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);

/**
Expand All @@ -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);

/**
Expand Down Expand Up @@ -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
4 changes: 4 additions & 0 deletions tests/alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit e25261a

Please sign in to comment.