summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2023-11-09 15:16:04 -0500
committerTavian Barnes <tavianator@tavianator.com>2023-11-09 15:35:40 -0500
commite25261a90222de75781726a93ab809c660208afd (patch)
treeeed200bdebfd981821754a6bb154e3db30a109f5
parentc745df94a182b8a569cb833ecfbe8da33bf01f98 (diff)
downloadbfs-e25261a90222de75781726a93ab809c660208afd.tar.xz
config: Add (de)allocator attributes
-rw-r--r--src/alloc.h40
-rw-r--r--src/config.h49
-rw-r--r--src/dstring.h21
-rw-r--r--tests/alloc.c4
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 <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) {
@@ -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.
@@ -243,6 +248,18 @@ void varena_init(struct varena *varena, size_t align, size_t min, size_t offset,
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.
*
* @param varena
@@ -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);
/**
@@ -285,18 +303,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.
*/
void varena_clear(struct varena *varena);
diff --git a/src/config.h b/src/config.h
index b95abaa..db62ef8 100644
--- a/src/config.h
+++ b/src/config.h
@@ -185,6 +185,17 @@
#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.
*/
#if __has_attribute(noinline)
@@ -212,6 +223,44 @@
#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.
*/
#ifndef BFS_USE_TARGET_CLONES
diff --git a/src/dstring.h b/src/dstring.h
index fd98df8..07b4ee9 100644
--- a/src/dstring.h
+++ b/src/dstring.h
@@ -28,11 +28,20 @@ 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);