summaryrefslogtreecommitdiff
path: root/fuzzer/alloc-inject.c
diff options
context:
space:
mode:
Diffstat (limited to 'fuzzer/alloc-inject.c')
-rw-r--r--fuzzer/alloc-inject.c130
1 files changed, 130 insertions, 0 deletions
diff --git a/fuzzer/alloc-inject.c b/fuzzer/alloc-inject.c
new file mode 100644
index 000000000000..05642ac43e61
--- /dev/null
+++ b/fuzzer/alloc-inject.c
@@ -0,0 +1,130 @@
+/*
+ * alloc-inject.c
+ * allocator fault injection for fuzzing harnesses
+ *
+ * SPDX-License-Identifier: pkgconf
+ *
+ * Copyright (c) 2026 pkgconf authors (see AUTHORS).
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * This software is provided 'as is' and without any warranty, express or
+ * implied. In no event shall the authors be liable for any damages arising
+ * from the use of this software.
+ */
+
+#include <stddef.h>
+#include "alloc-inject.h"
+
+/* the library's allocator calls are redirected here via -Wl,--wrap, so __real_*
+ * reaches the real (sanitizer-instrumented) allocator. injection is only active
+ * while armed, which a harness does exclusively around the code under test.
+ */
+static bool alloc_armed = false;
+static unsigned long alloc_seen = 0;
+static unsigned long alloc_fail_at = 0;
+static bool alloc_fired = false;
+
+void *__real_malloc(size_t size);
+void *__real_calloc(size_t nmemb, size_t size);
+void *__real_realloc(void *ptr, size_t size);
+void *__real_reallocarray(void *ptr, size_t nmemb, size_t size);
+char *__real_strdup(const char *s);
+char *__real_strndup(const char *s, size_t n);
+
+void *__wrap_malloc(size_t size);
+void *__wrap_calloc(size_t nmemb, size_t size);
+void *__wrap_realloc(void *ptr, size_t size);
+void *__wrap_reallocarray(void *ptr, size_t nmemb, size_t size);
+char *__wrap_strdup(const char *s);
+char *__wrap_strndup(const char *s, size_t n);
+
+void
+alloc_inject_arm(unsigned long fail_at)
+{
+ alloc_seen = 0;
+ alloc_fail_at = fail_at;
+ alloc_fired = false;
+ alloc_armed = true;
+}
+
+void
+alloc_inject_disarm(void)
+{
+ alloc_armed = false;
+}
+
+bool
+alloc_inject_fired(void)
+{
+ return alloc_fired;
+}
+
+static bool
+alloc_should_fail(void)
+{
+ if (!alloc_armed)
+ return false;
+
+ if (++alloc_seen != alloc_fail_at)
+ return false;
+
+ alloc_fired = true;
+ return true;
+}
+
+void *
+__wrap_malloc(size_t size)
+{
+ if (alloc_should_fail())
+ return NULL;
+
+ return __real_malloc(size);
+}
+
+void *
+__wrap_calloc(size_t nmemb, size_t size)
+{
+ if (alloc_should_fail())
+ return NULL;
+
+ return __real_calloc(nmemb, size);
+}
+
+void *
+__wrap_realloc(void *ptr, size_t size)
+{
+ if (alloc_should_fail())
+ return NULL;
+
+ return __real_realloc(ptr, size);
+}
+
+void *
+__wrap_reallocarray(void *ptr, size_t nmemb, size_t size)
+{
+ if (alloc_should_fail())
+ return NULL;
+
+ return __real_reallocarray(ptr, nmemb, size);
+}
+
+char *
+__wrap_strdup(const char *s)
+{
+ if (alloc_should_fail())
+ return NULL;
+
+ return __real_strdup(s);
+}
+
+char *
+__wrap_strndup(const char *s, size_t n)
+{
+ if (alloc_should_fail())
+ return NULL;
+
+ return __real_strndup(s, n);
+}