summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTavian Barnes <tavianator@tavianator.com>2023-06-19 12:11:36 -0400
committerTavian Barnes <tavianator@tavianator.com>2023-06-20 14:26:09 -0400
commit90ded13e589b0089167ef25ca3d26be599dfec9b (patch)
treed5a007948587f62fff62c851ddd3886b5a5e78ed
parent9ceb2b27577f1be3f30edb40a45117066fc78c51 (diff)
downloadbfs-90ded13e589b0089167ef25ca3d26be599dfec9b.tar.xz
alloc: New header for memory allocation utilities
-rw-r--r--Makefile3
-rw-r--r--src/alloc.c50
-rw-r--r--src/alloc.h149
-rw-r--r--src/bfstd.c13
-rw-r--r--src/bfstd.h12
-rw-r--r--src/bftw.c5
-rw-r--r--src/color.c5
-rw-r--r--src/config.h50
-rw-r--r--src/ctx.c31
-rw-r--r--src/dstring.c3
-rw-r--r--src/exec.c26
-rw-r--r--src/ioq.c26
-rw-r--r--src/ioq.h4
-rw-r--r--src/main.c1
-rw-r--r--src/mtab.c5
-rw-r--r--src/parse.c28
-rw-r--r--src/pwcache.c5
-rw-r--r--src/trie.c7
-rw-r--r--src/xregex.c3
-rw-r--r--src/xspawn.c3
-rw-r--r--tests/alloc.c24
-rw-r--r--tests/bfstd.c13
22 files changed, 271 insertions, 195 deletions
diff --git a/Makefile b/Makefile
index fb28e29..d38f581 100644
--- a/Makefile
+++ b/Makefile
@@ -217,6 +217,7 @@ $(OBJ)/FLAGS: $(OBJ)/FLAGS.new
# All object files except the entry point
LIBBFS := \
+ $(OBJ)/src/alloc.o \
$(OBJ)/src/bar.o \
$(OBJ)/src/bfstd.o \
$(OBJ)/src/bftw.o \
@@ -246,7 +247,7 @@ LIBBFS := \
$(BIN)/bfs: $(OBJ)/src/main.o $(LIBBFS)
# Standalone unit tests
-UNITS := bfstd bit trie xtimegm
+UNITS := alloc bfstd bit trie xtimegm
UNIT_TESTS := $(UNITS:%=$(BIN)/tests/%)
UNIT_CHECKS := $(UNITS:%=check-%)
diff --git a/src/alloc.c b/src/alloc.c
new file mode 100644
index 0000000..0003108
--- /dev/null
+++ b/src/alloc.c
@@ -0,0 +1,50 @@
+// Copyright © Tavian Barnes <tavianator@tavianator.com>
+// SPDX-License-Identifier: 0BSD
+
+#include "alloc.h"
+#include "bit.h"
+#include "diag.h"
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+/** Portable aligned_alloc()/posix_memalign(). */
+static void *xmemalign(size_t align, size_t size) {
+ bfs_assert(has_single_bit(align));
+ bfs_assert(align >= sizeof(void *));
+ bfs_assert((size & (align - 1)) == 0);
+
+#if __APPLE__
+ void *ptr = NULL;
+ errno = posix_memalign(&ptr, align, size);
+ return ptr;
+#else
+ return aligned_alloc(align, size);
+#endif
+}
+
+void *alloc(size_t align, size_t size) {
+ bfs_assert(has_single_bit(align));
+ bfs_assert((size & (align - 1)) == 0);
+
+ if (align <= alignof(max_align_t)) {
+ return malloc(size);
+ } else {
+ return xmemalign(align, size);
+ }
+}
+
+void *zalloc(size_t align, size_t size) {
+ bfs_assert(has_single_bit(align));
+ bfs_assert((size & (align - 1)) == 0);
+
+ if (align <= alignof(max_align_t)) {
+ return calloc(1, size);
+ }
+
+ void *ret = xmemalign(align, size);
+ if (ret) {
+ memset(ret, 0, size);
+ }
+ return ret;
+}
diff --git a/src/alloc.h b/src/alloc.h
new file mode 100644
index 0000000..899a4ec
--- /dev/null
+++ b/src/alloc.h
@@ -0,0 +1,149 @@
+// Copyright © Tavian Barnes <tavianator@tavianator.com>
+// SPDX-License-Identifier: 0BSD
+
+/**
+ * Memory allocation.
+ */
+
+#ifndef BFS_ALLOC_H
+#define BFS_ALLOC_H
+
+#include "config.h"
+#include <stddef.h>
+
+/** Round down to a multiple of an alignment. */
+static inline size_t align_floor(size_t align, size_t size) {
+ return size & ~(align - 1);
+}
+
+/** Round up to a multiple of an alignment. */
+static inline size_t align_ceil(size_t align, size_t size) {
+ return align_floor(align, size + align - 1);
+}
+
+/**
+ * Saturating array size.
+ *
+ * @param align
+ * Array element alignment.
+ * @param size
+ * Array element size.
+ * @param count
+ * Array element count.
+ * @return
+ * size * count, saturating to the maximum aligned value on overflow.
+ */
+static inline size_t array_size(size_t align, size_t size, size_t count) {
+ size_t ret = size * count;
+ return ret / size == count ? ret : ~(align - 1);
+}
+
+/** Saturating array sizeof. */
+#define sizeof_array(type, count) \
+ array_size(alignof(type), sizeof(type), count)
+
+/** Size of a struct/union field. */
+#define sizeof_member(type, member) \
+ sizeof(((type *)NULL)->member)
+
+/**
+ * Saturating flexible struct size.
+ *
+ * @param align
+ * Struct alignment.
+ * @param min
+ * Minimum struct size.
+ * @param offset
+ * Flexible array member offset.
+ * @param size
+ * Flexible array element size.
+ * @param count
+ * Flexible array element count.
+ * @return
+ * 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) {
+ size_t ret = size * count;
+ size_t overflow = ret / size != count;
+
+ size_t extra = offset + align - 1;
+ ret += extra;
+ overflow |= ret < extra;
+ ret |= -overflow;
+ 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;
+}
+
+/**
+ * Computes the size of a flexible struct.
+ *
+ * @param type
+ * The type of the struct containing the flexible array.
+ * @param member
+ * The name of the flexible array member.
+ * @param count
+ * The length of the flexible array.
+ * @return
+ * The size of the struct with count flexible array elements. Saturates
+ * 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)
+
+/**
+ * General memory allocator.
+ *
+ * @param align
+ * The required alignment.
+ * @param size
+ * The size of the allocation.
+ * @return
+ * The allocated memory, or NULL on failure.
+ */
+void *alloc(size_t align, size_t size);
+
+/**
+ * Zero-initialized memory allocator.
+ *
+ * @param align
+ * The required alignment.
+ * @param size
+ * The size of the allocation.
+ * @return
+ * The allocated memory, or NULL on failure.
+ */
+void *zalloc(size_t align, size_t size);
+
+/** Allocate memory for the given type. */
+#define ALLOC(type) \
+ (type *)alloc(alignof(type), sizeof(type))
+
+/** Allocate zeroed memory for the given type. */
+#define ZALLOC(type) \
+ (type *)zalloc(alignof(type), sizeof(type))
+
+/** Allocate memory for an array. */
+#define ALLOC_ARRAY(type, count) \
+ (type *)alloc(alignof(type), sizeof_array(type, count));
+
+/** Allocate zeroed memory for an array. */
+#define ZALLOC_ARRAY(type, count) \
+ (type *)zalloc(alignof(type), sizeof_array(type, count));
+
+/** Allocate memory for a flexible struct. */
+#define ALLOC_FLEX(type, member, count) \
+ (type *)alloc(alignof(type), sizeof_flex(type, member, count))
+
+/** Allocate zeroed memory for a flexible struct. */
+#define ZALLOC_FLEX(type, member, count) \
+ (type *)zalloc(alignof(type), sizeof_flex(type, member, count))
+
+#endif // BFS_ALLOC_H
diff --git a/src/bfstd.c b/src/bfstd.c
index 856c76c..0e8ba5f 100644
--- a/src/bfstd.c
+++ b/src/bfstd.c
@@ -143,19 +143,6 @@ char *xgetdelim(FILE *file, char delim) {
}
}
-void *xmemalign(size_t align, size_t size) {
- bfs_assert(has_single_bit(align));
- bfs_assert((size & (align - 1)) == 0);
-
-#if __APPLE__
- void *ptr = NULL;
- errno = posix_memalign(&ptr, align, size);
- return ptr;
-#else
- return aligned_alloc(align, size);
-#endif
-}
-
/** Compile and execute a regular expression for xrpmatch(). */
static int xrpregex(nl_item item, const char *response) {
const char *pattern = nl_langinfo(item);
diff --git a/src/bfstd.h b/src/bfstd.h
index 6f2e21e..cafe28f 100644
--- a/src/bfstd.h
+++ b/src/bfstd.h
@@ -106,18 +106,6 @@ char *xgetdelim(FILE *file, char delim);
// #include <stdlib.h>
/**
- * Portable version of aligned_alloc()/posix_memalign().
- *
- * @param align
- * The allocation's alignment.
- * @param size
- * The allocation's size.
- * @return
- * The allocation, or NULL on failure.
- */
-void *xmemalign(size_t align, size_t size);
-
-/**
* Process a yes/no prompt.
*
* @return 1 for yes, 0 for no, and -1 for unknown.
diff --git a/src/bftw.c b/src/bftw.c
index e711963..7ab14c7 100644
--- a/src/bftw.c
+++ b/src/bftw.c
@@ -17,6 +17,7 @@
*/
#include "bftw.h"
+#include "alloc.h"
#include "bfstd.h"
#include "config.h"
#include "diag.h"
@@ -241,9 +242,7 @@ static void bftw_cache_destroy(struct bftw_cache *cache) {
/** Create a new bftw_file. */
static struct bftw_file *bftw_file_new(struct bftw_file *parent, const char *name) {
size_t namelen = strlen(name);
- size_t size = flex_sizeof(struct bftw_file, name, namelen + 1);
-
- struct bftw_file *file = malloc(size);
+ struct bftw_file *file = ALLOC_FLEX(struct bftw_file, name, namelen + 1);
if (!file) {
return NULL;
}
diff --git a/src/color.c b/src/color.c
index 1edd8b5..b54ad53 100644
--- a/src/color.c
+++ b/src/color.c
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: 0BSD
#include "color.h"
+#include "alloc.h"
#include "bfstd.h"
#include "bftw.h"
#include "config.h"
@@ -404,7 +405,7 @@ static void parse_gnu_ls_colors(struct colors *colors, const char *ls_colors) {
}
struct colors *parse_colors(void) {
- struct colors *colors = malloc(sizeof(struct colors));
+ struct colors *colors = ALLOC(struct colors);
if (!colors) {
return NULL;
}
@@ -497,7 +498,7 @@ void free_colors(struct colors *colors) {
}
CFILE *cfwrap(FILE *file, const struct colors *colors, bool close) {
- CFILE *cfile = malloc(sizeof(*cfile));
+ CFILE *cfile = ALLOC(CFILE);
if (!cfile) {
return NULL;
}
diff --git a/src/config.h b/src/config.h
index 73348ac..1671a0d 100644
--- a/src/config.h
+++ b/src/config.h
@@ -142,56 +142,6 @@
#define countof(array) (sizeof(array) / sizeof(0[array]))
/**
- * Round down to a multiple of an alignment.
- */
-static inline size_t align_floor(size_t align, size_t size) {
- return size & ~(align - 1);
-}
-
-/**
- * Round up to a multiple of an alignment.
- */
-static inline size_t align_ceil(size_t align, size_t size) {
- return align_floor(align, size + align - 1);
-}
-
-/**
- * Computes the size of a struct containing a flexible array member of the given
- * length.
- *
- * @param type
- * The type of the struct containing the flexible array.
- * @param member
- * The name of the flexible array member.
- * @param count
- * The length of the flexible array.
- */
-#define flex_sizeof(type, member, count) \
- flex_sizeof_impl(alignof(type), sizeof(type), offsetof(type, member), sizeof(((type *)NULL)->member[0]), count)
-
-static inline size_t flex_sizeof_impl(size_t align, size_t min, size_t offset, size_t size, size_t count) {
- size_t ret = size * count;
- size_t overflow = ret / size != count;
-
- ret += offset;
- overflow |= ret < offset;
-
- size_t mask = align - 1;
- ret += mask;
- overflow |= ret < mask;
- ret |= -overflow;
- ret &= ~mask;
-
- // 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 < min) {
- ret = min;
- }
-
- return ret;
-}
-
-/**
* False sharing/destructive interference/largest cache line size.
*/
#ifdef __GCC_DESTRUCTIVE_SIZE
diff --git a/src/ctx.c b/src/ctx.c
index e8ce0e8..a940bed 100644
--- a/src/ctx.c
+++ b/src/ctx.c
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: 0BSD
#include "ctx.h"
+#include "alloc.h"
#include "color.h"
#include "darray.h"
#include "diag.h"
@@ -42,43 +43,17 @@ const char *debug_flag_name(enum debug_flags flag) {
}
struct bfs_ctx *bfs_ctx_new(void) {
- struct bfs_ctx *ctx = malloc(sizeof(*ctx));
+ struct bfs_ctx *ctx = ZALLOC(struct bfs_ctx);
if (!ctx) {
return NULL;
}
- ctx->argv = NULL;
- ctx->paths = NULL;
- ctx->expr = NULL;
- ctx->exclude = NULL;
-
- ctx->mindepth = 0;
ctx->maxdepth = INT_MAX;
ctx->flags = BFTW_RECOVER;
ctx->strategy = BFTW_BFS;
- ctx->threads = 0;
ctx->optlevel = 3;
- ctx->debug = 0;
- ctx->ignore_races = false;
- ctx->posixly_correct = false;
- ctx->status = false;
- ctx->unique = false;
- ctx->warn = false;
- ctx->xargs_safe = false;
-
- ctx->colors = NULL;
- ctx->colors_error = 0;
- ctx->cout = NULL;
- ctx->cerr = NULL;
-
- ctx->users = NULL;
- ctx->groups = NULL;
-
- ctx->mtab = NULL;
- ctx->mtab_error = 0;
trie_init(&ctx->files);
- ctx->nfiles = 0;
struct rlimit rl;
if (getrlimit(RLIMIT_NOFILE, &rl) != 0) {
@@ -155,7 +130,7 @@ CFILE *bfs_ctx_dedup(struct bfs_ctx *ctx, CFILE *cfile, const char *path) {
return ctx_file->cfile;
}
- leaf->value = ctx_file = malloc(sizeof(*ctx_file));
+ leaf->value = ctx_file = ALLOC(struct bfs_ctx_file);
if (!ctx_file) {
trie_remove(&ctx->files, leaf);
return NULL;
diff --git a/src/dstring.c b/src/dstring.c
index 2c9869d..7ca74d0 100644
--- a/src/dstring.c
+++ b/src/dstring.c
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: 0BSD
#include "dstring.h"
+#include "alloc.h"
#include "diag.h"
#include <stdarg.h>
#include <stdio.h>
@@ -24,7 +25,7 @@ static struct dstring *dstrheader(const char *dstr) {
/** Get the correct size for a dstring with the given capacity. */
static size_t dstrsize(size_t capacity) {
- return flex_sizeof(struct dstring, data, capacity + 1);
+ return sizeof_flex(struct dstring, data, capacity + 1);
}
/** Allocate a dstring with the given contents. */
diff --git a/src/exec.c b/src/exec.c
index 5912ad6..ea7f897 100644
--- a/src/exec.c
+++ b/src/exec.c
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: 0BSD
#include "exec.h"
+#include "alloc.h"
#include "bfstd.h"
#include "bftw.h"
#include "ctx.h"
@@ -124,26 +125,16 @@ static void bfs_exec_parse_error(const struct bfs_ctx *ctx, const struct bfs_exe
}
struct bfs_exec *bfs_exec_parse(const struct bfs_ctx *ctx, char **argv, enum bfs_exec_flags flags) {
- struct bfs_exec *execbuf = malloc(sizeof(*execbuf));
+ struct bfs_exec *execbuf = ZALLOC(struct bfs_exec);
if (!execbuf) {
- bfs_perror(ctx, "malloc()");
+ bfs_perror(ctx, "zalloc()");
goto fail;
}
execbuf->flags = flags;
execbuf->ctx = ctx;
execbuf->tmpl_argv = argv + 1;
- execbuf->tmpl_argc = 0;
- execbuf->argv = NULL;
- execbuf->argc = 0;
- execbuf->argv_cap = 0;
- execbuf->arg_size = 0;
- execbuf->arg_max = 0;
- execbuf->arg_min = 0;
execbuf->wd_fd = -1;
- execbuf->wd_path = NULL;
- execbuf->wd_len = 0;
- execbuf->ret = 0;
while (true) {
const char *arg = execbuf->tmpl_argv[execbuf->tmpl_argc];
@@ -176,9 +167,9 @@ struct bfs_exec *bfs_exec_parse(const struct bfs_ctx *ctx, char **argv, enum bfs
}
execbuf->argv_cap = execbuf->tmpl_argc + 1;
- execbuf->argv = malloc(execbuf->argv_cap*sizeof(*execbuf->argv));
+ execbuf->argv = ALLOC_ARRAY(char *, execbuf->argv_cap);
if (!execbuf->argv) {
- bfs_perror(ctx, "malloc()");
+ bfs_perror(ctx, "alloc()");
goto fail;
}
@@ -224,9 +215,8 @@ static char *bfs_exec_format_path(const struct bfs_exec *execbuf, const struct B
return NULL;
}
- strcpy(path, "./");
- strcpy(path + 2, name);
-
+ char *cur = stpcpy(path, "./");
+ cur = stpcpy(cur, name);
return path;
}
@@ -612,7 +602,7 @@ static int bfs_exec_push(struct bfs_exec *execbuf, char *arg) {
if (execbuf->argc + 1 >= execbuf->argv_cap) {
size_t cap = 2*execbuf->argv_cap;
- char **argv = realloc(execbuf->argv, cap*sizeof(*argv));
+ char **argv = realloc(execbuf->argv, sizeof_array(char *, cap));
if (!argv) {
return -1;
}
diff --git a/src/ioq.c b/src/ioq.c
index 5550c91..3e304ce 100644
--- a/src/ioq.c
+++ b/src/ioq.c
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: 0BSD
#include "ioq.h"
+#include "alloc.h"
#include "atomic.h"
#include "bfstd.h"
#include "bit.h"
@@ -114,7 +115,7 @@ static struct ioqq *ioqq_create(size_t size) {
// Circular buffer size must be a power of two
size = bit_ceil(size);
- struct ioqq *ioqq = xmemalign(alignof(struct ioqq), flex_sizeof(struct ioqq, slots, size));
+ struct ioqq *ioqq = ALLOC_FLEX(struct ioqq, slots, size);
if (!ioqq) {
return NULL;
}
@@ -124,7 +125,7 @@ static struct ioqq *ioqq_create(size_t size) {
// Use a pool of monitors
size_t nmonitors = size < 64 ? size : 64;
- ioqq->monitors = xmemalign(alignof(struct ioq_monitor), nmonitors * sizeof(struct ioq_monitor));
+ ioqq->monitors = ALLOC_ARRAY(struct ioq_monitor, nmonitors);
if (!ioqq->monitors) {
ioqq_destroy(ioqq);
return NULL;
@@ -273,7 +274,7 @@ struct ioq {
/** The number of background threads. */
size_t nthreads;
/** The background threads themselves. */
- pthread_t *threads;
+ pthread_t threads[];
};
/** Background thread entry point. */
@@ -303,18 +304,13 @@ static void *ioq_work(void *ptr) {
return NULL;
}
-struct ioq *ioq_create(size_t depth, size_t threads) {
- struct ioq *ioq = malloc(sizeof(*ioq));
+struct ioq *ioq_create(size_t depth, size_t nthreads) {
+ struct ioq *ioq = ZALLOC_FLEX(struct ioq, threads, nthreads);
if (!ioq) {
goto fail;
}
ioq->depth = depth;
- ioq->size = 0;
-
- ioq->pending = NULL;
- ioq->ready = NULL;
- ioq->nthreads = 0;
ioq->pending = ioqq_create(depth);
if (!ioq->pending) {
@@ -326,12 +322,7 @@ struct ioq *ioq_create(size_t depth, size_t threads) {
goto fail;
}
- ioq->threads = malloc(threads * sizeof(ioq->threads[0]));
- if (!ioq->threads) {
- goto fail;
- }
-
- for (size_t i = 0; i < threads; ++i) {
+ for (size_t i = 0; i < nthreads; ++i) {
errno = pthread_create(&ioq->threads[i], NULL, ioq_work, ioq);
if (errno != 0) {
goto fail;
@@ -354,7 +345,7 @@ int ioq_opendir(struct ioq *ioq, int dfd, const char *path, void *ptr) {
return -1;
}
- union ioq_cmd *cmd = malloc(sizeof(*cmd));
+ union ioq_cmd *cmd = ALLOC(union ioq_cmd);
if (!cmd) {
return -1;
}
@@ -412,7 +403,6 @@ void ioq_destroy(struct ioq *ioq) {
abort();
}
}
- free(ioq->threads);
ioqq_destroy(ioq->ready);
ioqq_destroy(ioq->pending);
diff --git a/src/ioq.h b/src/ioq.h
index 9492034..0af5779 100644
--- a/src/ioq.h
+++ b/src/ioq.h
@@ -33,12 +33,12 @@ struct ioq_res {
*
* @param depth
* The maximum depth of the queue.
- * @param threads
+ * @param nthreads
* The maximum number of background threads.
* @return
* The new I/O queue, or NULL on failure.
*/
-struct ioq *ioq_create(size_t depth, size_t threads);
+struct ioq *ioq_create(size_t depth, size_t nthreads);
/**
* Asynchronous bfs_opendir().
diff --git a/src/main.c b/src/main.c
index 76dde86..b7a08c1 100644
--- a/src/main.c
+++ b/src/main.c
@@ -20,6 +20,7 @@
* - bftw.[ch] (an extended version of nftw(3))
*
* - Utilities:
+ * - alloc.[ch] (memory allocation)
* - atomic.h (atomic operations)
* - bar.[ch] (a terminal status bar)
* - bit.h (bit manipulation)
diff --git a/src/mtab.c b/src/mtab.c
index 1d1ad94..e5c25ba 100644
--- a/src/mtab.c
+++ b/src/mtab.c
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: 0BSD
#include "mtab.h"
+#include "alloc.h"
#include "bfstd.h"
#include "config.h"
#include "darray.h"
@@ -87,15 +88,13 @@ fail:
}
struct bfs_mtab *bfs_mtab_parse(void) {
- struct bfs_mtab *mtab = malloc(sizeof(*mtab));
+ struct bfs_mtab *mtab = ZALLOC(struct bfs_mtab);
if (!mtab) {
return NULL;
}
- mtab->entries = NULL;
trie_init(&mtab->names);
trie_init(&mtab->types);
- mtab->types_filled = false;
int error = 0;
diff --git a/src/parse.c b/src/parse.c
index 64e08cd..cf4f696 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -9,6 +9,7 @@
*/
#include "parse.h"
+#include "alloc.h"
#include "bfstd.h"
#include "bftw.h"
#include "color.h"
@@ -55,39 +56,16 @@ static char *fake_print_arg = "-print";
static char *fake_true_arg = "-true";
struct bfs_expr *bfs_expr_new(bfs_eval_fn *eval_fn, size_t argc, char **argv) {
- struct bfs_expr *expr = malloc(sizeof(*expr));
+ struct bfs_expr *expr = ZALLOC(struct bfs_expr);
if (!expr) {
- perror("malloc()");
+ perror("zalloc()");
return NULL;
}
expr->eval_fn = eval_fn;
expr->argc = argc;
expr->argv = argv;
- expr->persistent_fds = 0;
- expr->ephemeral_fds = 0;
- expr->pure = false;
- expr->always_true = false;
- expr->always_false = false;
- expr->cost = 0.0;
expr->probability = 0.5;
- expr->evaluations = 0;
- expr->successes = 0;
- expr->elapsed.tv_sec = 0;
- expr->elapsed.tv_nsec = 0;
-
- // Prevent bfs_expr_free() from freeing uninitialized pointers on error paths
- if (bfs_expr_is_parent(expr)) {
- expr->lhs = NULL;
- expr->rhs = NULL;
- } else if (eval_fn == eval_exec) {
- expr->exec = NULL;
- } else if (eval_fn == eval_fprintf) {
- expr->printf = NULL;
- } else if (eval_fn == eval_regex) {
- expr->regex = NULL;
- }
-
return expr;
}
diff --git a/src/pwcache.c b/src/pwcache.c
index f52e4e1..9f32eb0 100644
--- a/src/pwcache.c
+++ b/src/pwcache.c
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: 0BSD
#include "pwcache.h"
+#include "alloc.h"
#include "config.h"
#include "darray.h"
#include "trie.h"
@@ -71,7 +72,7 @@ struct bfs_users {
};
struct bfs_users *bfs_users_new(void) {
- struct bfs_users *users = malloc(sizeof(*users));
+ struct bfs_users *users = ALLOC(struct bfs_users);
if (!users) {
return NULL;
}
@@ -144,7 +145,7 @@ struct bfs_groups {
};
struct bfs_groups *bfs_groups_new(void) {
- struct bfs_groups *groups = malloc(sizeof(*groups));
+ struct bfs_groups *groups = ALLOC(struct bfs_groups);
if (!groups) {
return NULL;
}
diff --git a/src/trie.c b/src/trie.c
index 8543eb1..19423cf 100644
--- a/src/trie.c
+++ b/src/trie.c
@@ -82,6 +82,7 @@
*/
#include "trie.h"
+#include "alloc.h"
#include "bit.h"
#include "config.h"
#include "diag.h"
@@ -317,7 +318,7 @@ struct trie_leaf *trie_find_prefix(const struct trie *trie, const char *key) {
/** Create a new leaf, holding a copy of the given key. */
static struct trie_leaf *trie_leaf_alloc(struct trie *trie, const void *key, size_t length) {
- struct trie_leaf *leaf = malloc(flex_sizeof(struct trie_leaf, key, length));
+ struct trie_leaf *leaf = ALLOC_FLEX(struct trie_leaf, key, length);
if (!leaf) {
return NULL;
}
@@ -339,12 +340,10 @@ static void trie_leaf_free(struct trie *trie, struct trie_leaf *leaf) {
/** Compute the size of a trie node with a certain number of children. */
static size_t trie_node_size(unsigned int size) {
- // Empty nodes aren't supported
- bfs_assert(size > 0);
// Node size must be a power of two
bfs_assert(has_single_bit(size));
- return flex_sizeof(struct trie_node, children, size);
+ return sizeof_flex(struct trie_node, children, size);
}
#if ENDIAN_NATIVE == ENDIAN_LITTLE
diff --git a/src/xregex.c b/src/xregex.c
index 89c2e90..ab5f793 100644
--- a/src/xregex.c
+++ b/src/xregex.c
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: 0BSD
#include "xregex.h"
+#include "alloc.h"
#include "config.h"
#include "diag.h"
#include "sanity.h"
@@ -115,7 +116,7 @@ static int bfs_onig_initialize(OnigEncoding *enc) {
#endif
int bfs_regcomp(struct bfs_regex **preg, const char *pattern, enum bfs_regex_type type, enum bfs_regcomp_flags flags) {
- struct bfs_regex *regex = *preg = malloc(sizeof(*regex));
+ struct bfs_regex *regex = *preg = ALLOC(struct bfs_regex);
if (!regex) {
return -1;
}
diff --git a/src/xspawn.c b/src/xspawn.c
index 740e38e..2cabdcc 100644
--- a/src/xspawn.c
+++ b/src/xspawn.c
@@ -2,6 +2,7 @@
// SPDX-License-Identifier: 0BSD
#include "xspawn.h"
+#include "alloc.h"
#include "bfstd.h"
#include "config.h"
#include "list.h"
@@ -62,7 +63,7 @@ int bfs_spawn_setflags(struct bfs_spawn *ctx, enum bfs_spawn_flags flags) {
/** Add a spawn action to the chain. */
static struct bfs_spawn_action *bfs_spawn_add(struct bfs_spawn *ctx, enum bfs_spawn_op op) {
- struct bfs_spawn_action *action = malloc(sizeof(*action));
+ struct bfs_spawn_action *action = ALLOC(struct bfs_spawn_action);
if (!action) {
return NULL;
}
diff --git a/tests/alloc.c b/tests/alloc.c
new file mode 100644
index 0000000..91b1b43
--- /dev/null
+++ b/tests/alloc.c
@@ -0,0 +1,24 @@
+// Copyright © Tavian Barnes <tavianator@tavianator.com>
+// SPDX-License-Identifier: 0BSD
+
+#include "../src/alloc.h"
+#include "../src/diag.h"
+#include <stdlib.h>
+
+int main(void) {
+ // Check sizeof_flex()
+ struct flexible {
+ alignas(64) int foo;
+ int bar[];
+ };
+ bfs_verify(sizeof_flex(struct flexible, bar, 0) >= sizeof(struct flexible));
+ bfs_verify(sizeof_flex(struct flexible, bar, 16) % alignof(struct flexible) == 0);
+ bfs_verify(sizeof_flex(struct flexible, bar, SIZE_MAX / sizeof(int) + 1)
+ == 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_verify(flex_size(8, 16, 4, 4, 1) == 16);
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/bfstd.c b/tests/bfstd.c
index 7fea9b5..fa854a8 100644
--- a/tests/bfstd.c
+++ b/tests/bfstd.c
@@ -24,17 +24,6 @@ static void check_base_dir(const char *path, const char *dir, const char *base)
}
int main(void) {
- // Check flex_sizeof()
- struct flexible {
- alignas(64) int foo;
- int bar[];
- };
- bfs_verify(flex_sizeof(struct flexible, bar, 0) >= sizeof(struct flexible));
- bfs_verify(flex_sizeof(struct flexible, bar, 16) % alignof(struct flexible) == 0);
- bfs_verify(flex_sizeof(struct flexible, bar, SIZE_MAX / sizeof(int) + 1)
- == align_floor(alignof(struct flexible), SIZE_MAX));
- bfs_verify(flex_sizeof_impl(8, 16, 4, 4, 1) == 16);
-
// From man 3p basename
check_base_dir("usr", ".", "usr");
check_base_dir("usr/", ".", "usr");
@@ -46,4 +35,6 @@ int main(void) {
check_base_dir("/usr/lib", "/usr", "lib");
check_base_dir("//usr//lib//", "//usr", "lib");
check_base_dir("/home//dwc//test", "/home//dwc", "test");
+
+ return EXIT_SUCCESS;
}