[DominatorTree] Add support for mixed pre/post CFG views.
[llvm-project.git] / compiler-rt / lib / fuzzer / FuzzerInterceptors.cpp
blobb87798603fda5bacdbc88c10a4b3b2a956ebc0fc
1 //===-- FuzzerInterceptors.cpp --------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 // Intercept certain libc functions to aid fuzzing.
9 // Linked only when other RTs that define their own interceptors are not linked.
10 //===----------------------------------------------------------------------===//
12 #include "FuzzerPlatform.h"
14 #if LIBFUZZER_LINUX
16 #define GET_CALLER_PC() __builtin_return_address(0)
18 #define PTR_TO_REAL(x) real_##x
19 #define REAL(x) __interception::PTR_TO_REAL(x)
20 #define FUNC_TYPE(x) x##_type
21 #define DEFINE_REAL(ret_type, func, ...) \
22 typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \
23 namespace __interception { \
24 FUNC_TYPE(func) PTR_TO_REAL(func); \
27 #include <cassert>
28 #include <cstdint>
29 #include <dlfcn.h> // for dlsym()
31 static void *getFuncAddr(const char *name, uintptr_t wrapper_addr) {
32 void *addr = dlsym(RTLD_NEXT, name);
33 if (!addr) {
34 // If the lookup using RTLD_NEXT failed, the sanitizer runtime library is
35 // later in the library search order than the DSO that we are trying to
36 // intercept, which means that we cannot intercept this function. We still
37 // want the address of the real definition, though, so look it up using
38 // RTLD_DEFAULT.
39 addr = dlsym(RTLD_DEFAULT, name);
41 // In case `name' is not loaded, dlsym ends up finding the actual wrapper.
42 // We don't want to intercept the wrapper and have it point to itself.
43 if (reinterpret_cast<uintptr_t>(addr) == wrapper_addr)
44 addr = nullptr;
46 return addr;
49 static int FuzzerInited = 0;
50 static bool FuzzerInitIsRunning;
52 static void fuzzerInit();
54 static void ensureFuzzerInited() {
55 assert(!FuzzerInitIsRunning);
56 if (!FuzzerInited) {
57 fuzzerInit();
61 static int internal_strcmp_strncmp(const char *s1, const char *s2, bool strncmp,
62 size_t n) {
63 size_t i = 0;
64 while (true) {
65 if (strncmp) {
66 if (i == n)
67 break;
68 i++;
70 unsigned c1 = *s1;
71 unsigned c2 = *s2;
72 if (c1 != c2)
73 return (c1 < c2) ? -1 : 1;
74 if (c1 == 0)
75 break;
76 s1++;
77 s2++;
79 return 0;
82 static int internal_strncmp(const char *s1, const char *s2, size_t n) {
83 return internal_strcmp_strncmp(s1, s2, true, n);
86 static int internal_strcmp(const char *s1, const char *s2) {
87 return internal_strcmp_strncmp(s1, s2, false, 0);
90 static int internal_memcmp(const void *s1, const void *s2, size_t n) {
91 const uint8_t *t1 = static_cast<const uint8_t *>(s1);
92 const uint8_t *t2 = static_cast<const uint8_t *>(s2);
93 for (size_t i = 0; i < n; ++i, ++t1, ++t2)
94 if (*t1 != *t2)
95 return *t1 < *t2 ? -1 : 1;
96 return 0;
99 static size_t internal_strlen(const char *s) {
100 size_t i = 0;
101 while (s[i])
102 i++;
103 return i;
106 static char *internal_strstr(const char *haystack, const char *needle) {
107 // This is O(N^2), but we are not using it in hot places.
108 size_t len1 = internal_strlen(haystack);
109 size_t len2 = internal_strlen(needle);
110 if (len1 < len2)
111 return nullptr;
112 for (size_t pos = 0; pos <= len1 - len2; pos++) {
113 if (internal_memcmp(haystack + pos, needle, len2) == 0)
114 return const_cast<char *>(haystack) + pos;
116 return nullptr;
119 extern "C" {
121 // Weak hooks forward-declared to avoid dependency on
122 // <sanitizer/common_interface_defs.h>.
123 void __sanitizer_weak_hook_memcmp(void *called_pc, const void *s1,
124 const void *s2, size_t n, int result);
125 void __sanitizer_weak_hook_strncmp(void *called_pc, const char *s1,
126 const char *s2, size_t n, int result);
127 void __sanitizer_weak_hook_strncasecmp(void *called_pc, const char *s1,
128 const char *s2, size_t n, int result);
129 void __sanitizer_weak_hook_strcmp(void *called_pc, const char *s1,
130 const char *s2, int result);
131 void __sanitizer_weak_hook_strcasecmp(void *called_pc, const char *s1,
132 const char *s2, int result);
133 void __sanitizer_weak_hook_strstr(void *called_pc, const char *s1,
134 const char *s2, char *result);
135 void __sanitizer_weak_hook_strcasestr(void *called_pc, const char *s1,
136 const char *s2, char *result);
137 void __sanitizer_weak_hook_memmem(void *called_pc, const void *s1, size_t len1,
138 const void *s2, size_t len2, void *result);
140 DEFINE_REAL(int, bcmp, const void *, const void *, size_t)
141 DEFINE_REAL(int, memcmp, const void *, const void *, size_t)
142 DEFINE_REAL(int, strncmp, const char *, const char *, size_t)
143 DEFINE_REAL(int, strcmp, const char *, const char *)
144 DEFINE_REAL(int, strncasecmp, const char *, const char *, size_t)
145 DEFINE_REAL(int, strcasecmp, const char *, const char *)
146 DEFINE_REAL(char *, strstr, const char *, const char *)
147 DEFINE_REAL(char *, strcasestr, const char *, const char *)
148 DEFINE_REAL(void *, memmem, const void *, size_t, const void *, size_t)
150 ATTRIBUTE_INTERFACE int bcmp(const char *s1, const char *s2, size_t n) {
151 if (!FuzzerInited)
152 return internal_memcmp(s1, s2, n);
153 int result = REAL(bcmp)(s1, s2, n);
154 __sanitizer_weak_hook_memcmp(GET_CALLER_PC(), s1, s2, n, result);
155 return result;
158 ATTRIBUTE_INTERFACE int memcmp(const void *s1, const void *s2, size_t n) {
159 if (!FuzzerInited)
160 return internal_memcmp(s1, s2, n);
161 int result = REAL(memcmp)(s1, s2, n);
162 __sanitizer_weak_hook_memcmp(GET_CALLER_PC(), s1, s2, n, result);
163 return result;
166 ATTRIBUTE_INTERFACE int strncmp(const char *s1, const char *s2, size_t n) {
167 if (!FuzzerInited)
168 return internal_strncmp(s1, s2, n);
169 int result = REAL(strncmp)(s1, s2, n);
170 __sanitizer_weak_hook_strncmp(GET_CALLER_PC(), s1, s2, n, result);
171 return result;
174 ATTRIBUTE_INTERFACE int strcmp(const char *s1, const char *s2) {
175 if (!FuzzerInited)
176 return internal_strcmp(s1, s2);
177 int result = REAL(strcmp)(s1, s2);
178 __sanitizer_weak_hook_strcmp(GET_CALLER_PC(), s1, s2, result);
179 return result;
182 ATTRIBUTE_INTERFACE int strncasecmp(const char *s1, const char *s2, size_t n) {
183 ensureFuzzerInited();
184 int result = REAL(strncasecmp)(s1, s2, n);
185 __sanitizer_weak_hook_strncasecmp(GET_CALLER_PC(), s1, s2, n, result);
186 return result;
189 ATTRIBUTE_INTERFACE int strcasecmp(const char *s1, const char *s2) {
190 ensureFuzzerInited();
191 int result = REAL(strcasecmp)(s1, s2);
192 __sanitizer_weak_hook_strcasecmp(GET_CALLER_PC(), s1, s2, result);
193 return result;
196 ATTRIBUTE_INTERFACE char *strstr(const char *s1, const char *s2) {
197 if (!FuzzerInited)
198 return internal_strstr(s1, s2);
199 char *result = REAL(strstr)(s1, s2);
200 __sanitizer_weak_hook_strstr(GET_CALLER_PC(), s1, s2, result);
201 return result;
204 ATTRIBUTE_INTERFACE char *strcasestr(const char *s1, const char *s2) {
205 ensureFuzzerInited();
206 char *result = REAL(strcasestr)(s1, s2);
207 __sanitizer_weak_hook_strcasestr(GET_CALLER_PC(), s1, s2, result);
208 return result;
211 ATTRIBUTE_INTERFACE
212 void *memmem(const void *s1, size_t len1, const void *s2, size_t len2) {
213 ensureFuzzerInited();
214 void *result = REAL(memmem)(s1, len1, s2, len2);
215 __sanitizer_weak_hook_memmem(GET_CALLER_PC(), s1, len1, s2, len2, result);
216 return result;
219 __attribute__((section(".preinit_array"),
220 used)) static void (*__local_fuzzer_preinit)(void) = fuzzerInit;
222 } // extern "C"
224 static void fuzzerInit() {
225 assert(!FuzzerInitIsRunning);
226 if (FuzzerInited)
227 return;
228 FuzzerInitIsRunning = true;
230 REAL(bcmp) = reinterpret_cast<memcmp_type>(
231 getFuncAddr("bcmp", reinterpret_cast<uintptr_t>(&bcmp)));
232 REAL(memcmp) = reinterpret_cast<memcmp_type>(
233 getFuncAddr("memcmp", reinterpret_cast<uintptr_t>(&memcmp)));
234 REAL(strncmp) = reinterpret_cast<strncmp_type>(
235 getFuncAddr("strncmp", reinterpret_cast<uintptr_t>(&strncmp)));
236 REAL(strcmp) = reinterpret_cast<strcmp_type>(
237 getFuncAddr("strcmp", reinterpret_cast<uintptr_t>(&strcmp)));
238 REAL(strncasecmp) = reinterpret_cast<strncasecmp_type>(
239 getFuncAddr("strncasecmp", reinterpret_cast<uintptr_t>(&strncasecmp)));
240 REAL(strcasecmp) = reinterpret_cast<strcasecmp_type>(
241 getFuncAddr("strcasecmp", reinterpret_cast<uintptr_t>(&strcasecmp)));
242 REAL(strstr) = reinterpret_cast<strstr_type>(
243 getFuncAddr("strstr", reinterpret_cast<uintptr_t>(&strstr)));
244 REAL(strcasestr) = reinterpret_cast<strcasestr_type>(
245 getFuncAddr("strcasestr", reinterpret_cast<uintptr_t>(&strcasestr)));
246 REAL(memmem) = reinterpret_cast<memmem_type>(
247 getFuncAddr("memmem", reinterpret_cast<uintptr_t>(&memmem)));
249 FuzzerInitIsRunning = false;
250 FuzzerInited = 1;
253 #endif