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