xref: /freebsd/contrib/pkgconf/fuzzer/alloc-inject.c (revision 592efe252472a3385acf36b1f49ecf710a7f3d9c)
1*592efe25SPierre Pronchery /*
2*592efe25SPierre Pronchery  * alloc-inject.c
3*592efe25SPierre Pronchery  * allocator fault injection for fuzzing harnesses
4*592efe25SPierre Pronchery  *
5*592efe25SPierre Pronchery  * SPDX-License-Identifier: pkgconf
6*592efe25SPierre Pronchery  *
7*592efe25SPierre Pronchery  * Copyright (c) 2026 pkgconf authors (see AUTHORS).
8*592efe25SPierre Pronchery  *
9*592efe25SPierre Pronchery  * Permission to use, copy, modify, and/or distribute this software for any
10*592efe25SPierre Pronchery  * purpose with or without fee is hereby granted, provided that the above
11*592efe25SPierre Pronchery  * copyright notice and this permission notice appear in all copies.
12*592efe25SPierre Pronchery  *
13*592efe25SPierre Pronchery  * This software is provided 'as is' and without any warranty, express or
14*592efe25SPierre Pronchery  * implied.  In no event shall the authors be liable for any damages arising
15*592efe25SPierre Pronchery  * from the use of this software.
16*592efe25SPierre Pronchery  */
17*592efe25SPierre Pronchery 
18*592efe25SPierre Pronchery #include <stddef.h>
19*592efe25SPierre Pronchery #include "alloc-inject.h"
20*592efe25SPierre Pronchery 
21*592efe25SPierre Pronchery /* the library's allocator calls are redirected here via -Wl,--wrap, so __real_*
22*592efe25SPierre Pronchery  * reaches the real (sanitizer-instrumented) allocator.  injection is only active
23*592efe25SPierre Pronchery  * while armed, which a harness does exclusively around the code under test.
24*592efe25SPierre Pronchery  */
25*592efe25SPierre Pronchery static bool alloc_armed = false;
26*592efe25SPierre Pronchery static unsigned long alloc_seen = 0;
27*592efe25SPierre Pronchery static unsigned long alloc_fail_at = 0;
28*592efe25SPierre Pronchery static bool alloc_fired = false;
29*592efe25SPierre Pronchery 
30*592efe25SPierre Pronchery void *__real_malloc(size_t size);
31*592efe25SPierre Pronchery void *__real_calloc(size_t nmemb, size_t size);
32*592efe25SPierre Pronchery void *__real_realloc(void *ptr, size_t size);
33*592efe25SPierre Pronchery void *__real_reallocarray(void *ptr, size_t nmemb, size_t size);
34*592efe25SPierre Pronchery char *__real_strdup(const char *s);
35*592efe25SPierre Pronchery char *__real_strndup(const char *s, size_t n);
36*592efe25SPierre Pronchery 
37*592efe25SPierre Pronchery void *__wrap_malloc(size_t size);
38*592efe25SPierre Pronchery void *__wrap_calloc(size_t nmemb, size_t size);
39*592efe25SPierre Pronchery void *__wrap_realloc(void *ptr, size_t size);
40*592efe25SPierre Pronchery void *__wrap_reallocarray(void *ptr, size_t nmemb, size_t size);
41*592efe25SPierre Pronchery char *__wrap_strdup(const char *s);
42*592efe25SPierre Pronchery char *__wrap_strndup(const char *s, size_t n);
43*592efe25SPierre Pronchery 
44*592efe25SPierre Pronchery void
alloc_inject_arm(unsigned long fail_at)45*592efe25SPierre Pronchery alloc_inject_arm(unsigned long fail_at)
46*592efe25SPierre Pronchery {
47*592efe25SPierre Pronchery 	alloc_seen = 0;
48*592efe25SPierre Pronchery 	alloc_fail_at = fail_at;
49*592efe25SPierre Pronchery 	alloc_fired = false;
50*592efe25SPierre Pronchery 	alloc_armed = true;
51*592efe25SPierre Pronchery }
52*592efe25SPierre Pronchery 
53*592efe25SPierre Pronchery void
alloc_inject_disarm(void)54*592efe25SPierre Pronchery alloc_inject_disarm(void)
55*592efe25SPierre Pronchery {
56*592efe25SPierre Pronchery 	alloc_armed = false;
57*592efe25SPierre Pronchery }
58*592efe25SPierre Pronchery 
59*592efe25SPierre Pronchery bool
alloc_inject_fired(void)60*592efe25SPierre Pronchery alloc_inject_fired(void)
61*592efe25SPierre Pronchery {
62*592efe25SPierre Pronchery 	return alloc_fired;
63*592efe25SPierre Pronchery }
64*592efe25SPierre Pronchery 
65*592efe25SPierre Pronchery static bool
alloc_should_fail(void)66*592efe25SPierre Pronchery alloc_should_fail(void)
67*592efe25SPierre Pronchery {
68*592efe25SPierre Pronchery 	if (!alloc_armed)
69*592efe25SPierre Pronchery 		return false;
70*592efe25SPierre Pronchery 
71*592efe25SPierre Pronchery 	if (++alloc_seen != alloc_fail_at)
72*592efe25SPierre Pronchery 		return false;
73*592efe25SPierre Pronchery 
74*592efe25SPierre Pronchery 	alloc_fired = true;
75*592efe25SPierre Pronchery 	return true;
76*592efe25SPierre Pronchery }
77*592efe25SPierre Pronchery 
78*592efe25SPierre Pronchery void *
__wrap_malloc(size_t size)79*592efe25SPierre Pronchery __wrap_malloc(size_t size)
80*592efe25SPierre Pronchery {
81*592efe25SPierre Pronchery 	if (alloc_should_fail())
82*592efe25SPierre Pronchery 		return NULL;
83*592efe25SPierre Pronchery 
84*592efe25SPierre Pronchery 	return __real_malloc(size);
85*592efe25SPierre Pronchery }
86*592efe25SPierre Pronchery 
87*592efe25SPierre Pronchery void *
__wrap_calloc(size_t nmemb,size_t size)88*592efe25SPierre Pronchery __wrap_calloc(size_t nmemb, size_t size)
89*592efe25SPierre Pronchery {
90*592efe25SPierre Pronchery 	if (alloc_should_fail())
91*592efe25SPierre Pronchery 		return NULL;
92*592efe25SPierre Pronchery 
93*592efe25SPierre Pronchery 	return __real_calloc(nmemb, size);
94*592efe25SPierre Pronchery }
95*592efe25SPierre Pronchery 
96*592efe25SPierre Pronchery void *
__wrap_realloc(void * ptr,size_t size)97*592efe25SPierre Pronchery __wrap_realloc(void *ptr, size_t size)
98*592efe25SPierre Pronchery {
99*592efe25SPierre Pronchery 	if (alloc_should_fail())
100*592efe25SPierre Pronchery 		return NULL;
101*592efe25SPierre Pronchery 
102*592efe25SPierre Pronchery 	return __real_realloc(ptr, size);
103*592efe25SPierre Pronchery }
104*592efe25SPierre Pronchery 
105*592efe25SPierre Pronchery void *
__wrap_reallocarray(void * ptr,size_t nmemb,size_t size)106*592efe25SPierre Pronchery __wrap_reallocarray(void *ptr, size_t nmemb, size_t size)
107*592efe25SPierre Pronchery {
108*592efe25SPierre Pronchery 	if (alloc_should_fail())
109*592efe25SPierre Pronchery 		return NULL;
110*592efe25SPierre Pronchery 
111*592efe25SPierre Pronchery 	return __real_reallocarray(ptr, nmemb, size);
112*592efe25SPierre Pronchery }
113*592efe25SPierre Pronchery 
114*592efe25SPierre Pronchery char *
__wrap_strdup(const char * s)115*592efe25SPierre Pronchery __wrap_strdup(const char *s)
116*592efe25SPierre Pronchery {
117*592efe25SPierre Pronchery 	if (alloc_should_fail())
118*592efe25SPierre Pronchery 		return NULL;
119*592efe25SPierre Pronchery 
120*592efe25SPierre Pronchery 	return __real_strdup(s);
121*592efe25SPierre Pronchery }
122*592efe25SPierre Pronchery 
123*592efe25SPierre Pronchery char *
__wrap_strndup(const char * s,size_t n)124*592efe25SPierre Pronchery __wrap_strndup(const char *s, size_t n)
125*592efe25SPierre Pronchery {
126*592efe25SPierre Pronchery 	if (alloc_should_fail())
127*592efe25SPierre Pronchery 		return NULL;
128*592efe25SPierre Pronchery 
129*592efe25SPierre Pronchery 	return __real_strndup(s, n);
130*592efe25SPierre Pronchery }
131