| // Copyright 2022 Code Intelligence GmbH |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| /* |
| * Dynamically exported definitions of fuzzer hooks and libc functions that |
| * forward to the symbols provided by the Jazzer driver JNI library once it has |
| * been loaded. |
| * |
| * Native libraries instrumented for fuzzing include references to fuzzer hooks |
| * that are resolved by the dynamic linker. Sanitizers such as ASan provide weak |
| * definitions of these symbols, but the dynamic linker doesn't distinguish |
| * between weak and strong symbols and thus wouldn't ever resolve them against |
| * the strong definitions provided by the Jazzer driver JNI library. |
| * Furthermore, libc functions can only be overridden in the native driver |
| * executable, which is the only binary that comes before the actual libc in the |
| * dynamic linker search order. |
| */ |
| |
| #define _GNU_SOURCE // for RTLD_NEXT |
| #include <dlfcn.h> |
| #include <stdatomic.h> |
| #include <stddef.h> |
| #include <string.h> |
| |
| #define GET_CALLER_PC() __builtin_return_address(0) |
| #define LIKELY(x) __builtin_expect(!!(x), 1) |
| #define UNLIKELY(x) __builtin_expect(!!(x), 0) |
| |
| typedef int (*bcmp_t)(const void *, const void *, size_t); |
| static _Atomic bcmp_t bcmp_real; |
| typedef void (*bcmp_hook_t)(void *, const void *, const void *, size_t, int); |
| static _Atomic bcmp_hook_t bcmp_hook; |
| |
| typedef int (*memcmp_t)(const void *, const void *, size_t); |
| static _Atomic memcmp_t memcmp_real; |
| typedef void (*memcmp_hook_t)(void *, const void *, const void *, size_t, int); |
| static _Atomic memcmp_hook_t memcmp_hook; |
| |
| typedef int (*strncmp_t)(const char *, const char *, size_t); |
| static _Atomic strncmp_t strncmp_real; |
| typedef void (*strncmp_hook_t)(void *, const char *, const char *, size_t, int); |
| static _Atomic strncmp_hook_t strncmp_hook; |
| |
| typedef int (*strcmp_t)(const char *, const char *); |
| static _Atomic strcmp_t strcmp_real; |
| typedef void (*strcmp_hook_t)(void *, const char *, const char *, int); |
| static _Atomic strcmp_hook_t strcmp_hook; |
| |
| typedef int (*strncasecmp_t)(const char *, const char *, size_t); |
| static _Atomic strncasecmp_t strncasecmp_real; |
| typedef void (*strncasecmp_hook_t)(void *, const char *, const char *, size_t, |
| int); |
| static _Atomic strncasecmp_hook_t strncasecmp_hook; |
| |
| typedef int (*strcasecmp_t)(const char *, const char *); |
| static _Atomic strcasecmp_t strcasecmp_real; |
| typedef void (*strcasecmp_hook_t)(void *, const char *, const char *, int); |
| static _Atomic strcasecmp_hook_t strcasecmp_hook; |
| |
| typedef char *(*strstr_t)(const char *, const char *); |
| static _Atomic strstr_t strstr_real; |
| typedef void (*strstr_hook_t)(void *, const char *, const char *, char *); |
| static _Atomic strstr_hook_t strstr_hook; |
| |
| typedef char *(*strcasestr_t)(const char *, const char *); |
| static _Atomic strcasestr_t strcasestr_real; |
| typedef void (*strcasestr_hook_t)(void *, const char *, const char *, char *); |
| static _Atomic strcasestr_hook_t strcasestr_hook; |
| |
| typedef void *(*memmem_t)(const void *, size_t, const void *, size_t); |
| static _Atomic memmem_t memmem_real; |
| typedef void (*memmem_hook_t)(void *, const void *, size_t, const void *, |
| size_t, void *); |
| static _Atomic memmem_hook_t memmem_hook; |
| |
| typedef void (*cov_8bit_counters_init_t)(uint8_t *, uint8_t *); |
| static _Atomic cov_8bit_counters_init_t cov_8bit_counters_init; |
| typedef void (*cov_pcs_init_t)(const uintptr_t *, const uintptr_t *); |
| static _Atomic cov_pcs_init_t cov_pcs_init; |
| |
| typedef void (*trace_cmp1_t)(void *, uint8_t, uint8_t); |
| static _Atomic trace_cmp1_t trace_cmp1_with_pc; |
| typedef void (*trace_cmp2_t)(void *, uint16_t, uint16_t); |
| static _Atomic trace_cmp2_t trace_cmp2_with_pc; |
| typedef void (*trace_cmp4_t)(void *, uint32_t, uint32_t); |
| static _Atomic trace_cmp4_t trace_cmp4_with_pc; |
| typedef void (*trace_cmp8_t)(void *, uint64_t, uint64_t); |
| static _Atomic trace_cmp8_t trace_cmp8_with_pc; |
| |
| typedef void (*trace_const_cmp1_t)(void *, uint8_t, uint8_t); |
| static _Atomic trace_const_cmp1_t trace_const_cmp1_with_pc; |
| typedef void (*trace_const_cmp2_t)(void *, uint16_t, uint16_t); |
| static _Atomic trace_const_cmp2_t trace_const_cmp2_with_pc; |
| typedef void (*trace_const_cmp4_t)(void *, uint32_t, uint32_t); |
| static _Atomic trace_const_cmp4_t trace_const_cmp4_with_pc; |
| typedef void (*trace_const_cmp8_t)(void *, uint64_t, uint64_t); |
| static _Atomic trace_const_cmp8_t trace_const_cmp8_with_pc; |
| |
| typedef void (*trace_switch_t)(void *, uint64_t, uint64_t *); |
| static _Atomic trace_switch_t trace_switch_with_pc; |
| |
| typedef void (*trace_div4_t)(void *, uint32_t); |
| static _Atomic trace_div4_t trace_div4_with_pc; |
| typedef void (*trace_div8_t)(void *, uint64_t); |
| static _Atomic trace_div8_t trace_div8_with_pc; |
| |
| typedef void (*trace_gep_t)(void *, uintptr_t); |
| static _Atomic trace_gep_t trace_gep_with_pc; |
| |
| typedef void (*trace_pc_indir_t)(void *, uintptr_t); |
| static _Atomic trace_pc_indir_t trace_pc_indir_with_pc; |
| |
| __attribute__((visibility("default"))) void jazzer_initialize_native_hooks( |
| void *handle) { |
| atomic_store(&bcmp_hook, dlsym(handle, "__sanitizer_weak_hook_bcmp")); |
| atomic_store(&memcmp_hook, dlsym(handle, "__sanitizer_weak_hook_memcmp")); |
| atomic_store(&strncmp_hook, dlsym(handle, "__sanitizer_weak_hook_strncmp")); |
| atomic_store(&strcmp_hook, dlsym(handle, "__sanitizer_weak_hook_strcmp")); |
| atomic_store(&strncasecmp_hook, |
| dlsym(handle, "__sanitizer_weak_hook_strncasecmp")); |
| atomic_store(&strcasecmp_hook, |
| dlsym(handle, "__sanitizer_weak_hook_strcasecmp")); |
| atomic_store(&strstr_hook, dlsym(handle, "__sanitizer_weak_hook_strstr")); |
| atomic_store(&strcasestr_hook, |
| dlsym(handle, "__sanitizer_weak_hook_strcasestr")); |
| atomic_store(&memmem_hook, dlsym(handle, "__sanitizer_weak_hook_memmem")); |
| |
| atomic_store(&cov_8bit_counters_init, |
| dlsym(handle, "__sanitizer_cov_8bit_counters_init")); |
| atomic_store(&cov_pcs_init, dlsym(handle, "__sanitizer_cov_pcs_init")); |
| |
| atomic_store(&trace_cmp1_with_pc, |
| dlsym(handle, "__sanitizer_cov_trace_cmp1_with_pc")); |
| atomic_store(&trace_cmp2_with_pc, |
| dlsym(handle, "__sanitizer_cov_trace_cmp2_with_pc")); |
| atomic_store(&trace_cmp4_with_pc, |
| dlsym(handle, "__sanitizer_cov_trace_cmp4_with_pc")); |
| atomic_store(&trace_cmp8_with_pc, |
| dlsym(handle, "__sanitizer_cov_trace_cmp8_with_pc")); |
| |
| atomic_store(&trace_const_cmp1_with_pc, |
| dlsym(handle, "__sanitizer_cov_trace_const_cmp1_with_pc")); |
| atomic_store(&trace_const_cmp2_with_pc, |
| dlsym(handle, "__sanitizer_cov_trace_const_cmp2_with_pc")); |
| atomic_store(&trace_const_cmp4_with_pc, |
| dlsym(handle, "__sanitizer_cov_trace_const_cmp4_with_pc")); |
| atomic_store(&trace_const_cmp8_with_pc, |
| dlsym(handle, "__sanitizer_cov_trace_const_cmp8_with_pc")); |
| |
| atomic_store(&trace_switch_with_pc, |
| dlsym(handle, "__sanitizer_cov_trace_switch_with_pc")); |
| |
| atomic_store(&trace_div4_with_pc, |
| dlsym(handle, "__sanitizer_cov_trace_div4_with_pc")); |
| atomic_store(&trace_div8_with_pc, |
| dlsym(handle, "__sanitizer_cov_trace_div8_with_pc")); |
| |
| atomic_store(&trace_gep_with_pc, |
| dlsym(handle, "__sanitizer_cov_trace_gep_with_pc")); |
| |
| atomic_store(&trace_pc_indir_with_pc, |
| dlsym(handle, "__sanitizer_cov_trace_pc_indir_with_pc")); |
| } |
| |
| // Alternate definitions for libc functions mimicking those that libFuzzer would |
| // provide if it were part of the native driver executable. All these functions |
| // invoke the real libc function loaded from the next library in search order |
| // (usually libc itself). |
| // Function pointers have to be loaded and stored atomically even if libc |
| // functions are invoked from different threads, but we do not need any |
| // synchronization guarantees - in the worst case, we will non-deterministically |
| // lose a few hook invocations. |
| |
| __attribute__((visibility("default"))) int bcmp(const void *s1, const void *s2, |
| size_t n) { |
| bcmp_t bcmp_real_local = |
| atomic_load_explicit(&bcmp_real, memory_order_relaxed); |
| if (UNLIKELY(bcmp_real_local == NULL)) { |
| bcmp_real_local = dlsym(RTLD_NEXT, "bcmp"); |
| atomic_store_explicit(&bcmp_real, bcmp_real_local, memory_order_relaxed); |
| } |
| |
| int result = bcmp_real_local(s1, s2, n); |
| bcmp_hook_t hook = atomic_load_explicit(&bcmp_hook, memory_order_relaxed); |
| if (LIKELY(hook != NULL)) { |
| hook(GET_CALLER_PC(), s1, s2, n, result); |
| } |
| return result; |
| } |
| |
| __attribute__((visibility("default"))) int memcmp(const void *s1, |
| const void *s2, size_t n) { |
| memcmp_t memcmp_real_local = |
| atomic_load_explicit(&memcmp_real, memory_order_relaxed); |
| if (UNLIKELY(memcmp_real_local == NULL)) { |
| memcmp_real_local = dlsym(RTLD_NEXT, "memcmp"); |
| atomic_store_explicit(&memcmp_real, memcmp_real_local, |
| memory_order_relaxed); |
| } |
| |
| int result = memcmp_real_local(s1, s2, n); |
| memcmp_hook_t hook = atomic_load_explicit(&memcmp_hook, memory_order_relaxed); |
| if (LIKELY(hook != NULL)) { |
| hook(GET_CALLER_PC(), s1, s2, n, result); |
| } |
| return result; |
| } |
| |
| __attribute__((visibility("default"))) int strncmp(const char *s1, |
| const char *s2, size_t n) { |
| strncmp_t strncmp_real_local = |
| atomic_load_explicit(&strncmp_real, memory_order_relaxed); |
| if (UNLIKELY(strncmp_real_local == NULL)) { |
| strncmp_real_local = dlsym(RTLD_NEXT, "strncmp"); |
| atomic_store_explicit(&strncmp_real, strncmp_real_local, |
| memory_order_relaxed); |
| } |
| |
| int result = strncmp_real_local(s1, s2, n); |
| strncmp_hook_t hook = |
| atomic_load_explicit(&strncmp_hook, memory_order_relaxed); |
| if (LIKELY(hook != NULL)) { |
| hook(GET_CALLER_PC(), s1, s2, n, result); |
| } |
| return result; |
| } |
| |
| __attribute__((visibility("default"))) int strncasecmp(const char *s1, |
| const char *s2, |
| size_t n) { |
| strncasecmp_t strncasecmp_real_local = |
| atomic_load_explicit(&strncasecmp_real, memory_order_relaxed); |
| if (UNLIKELY(strncasecmp_real_local == NULL)) { |
| strncasecmp_real_local = dlsym(RTLD_NEXT, "strncasecmp"); |
| atomic_store_explicit(&strncasecmp_real, strncasecmp_real_local, |
| memory_order_relaxed); |
| } |
| |
| int result = strncasecmp_real_local(s1, s2, n); |
| strncasecmp_hook_t hook = |
| atomic_load_explicit(&strncasecmp_hook, memory_order_relaxed); |
| if (LIKELY(hook != NULL)) { |
| hook(GET_CALLER_PC(), s1, s2, n, result); |
| } |
| return result; |
| } |
| |
| __attribute__((visibility("default"))) int strcmp(const char *s1, |
| const char *s2) { |
| strcmp_t strcmp_real_local = |
| atomic_load_explicit(&strcmp_real, memory_order_relaxed); |
| if (UNLIKELY(strcmp_real_local == NULL)) { |
| strcmp_real_local = dlsym(RTLD_NEXT, "strcmp"); |
| atomic_store_explicit(&strcmp_real, strcmp_real_local, |
| memory_order_relaxed); |
| } |
| |
| int result = strcmp_real_local(s1, s2); |
| strcmp_hook_t hook = atomic_load_explicit(&strcmp_hook, memory_order_relaxed); |
| if (LIKELY(hook != NULL)) { |
| hook(GET_CALLER_PC(), s1, s2, result); |
| } |
| return result; |
| } |
| |
| __attribute__((visibility("default"))) int strcasecmp(const char *s1, |
| const char *s2) { |
| strcasecmp_t strcasecmp_real_local = |
| atomic_load_explicit(&strcasecmp_real, memory_order_relaxed); |
| if (UNLIKELY(strcasecmp_real_local == NULL)) { |
| strcasecmp_real_local = dlsym(RTLD_NEXT, "strcasecmp"); |
| atomic_store_explicit(&strcasecmp_real, strcasecmp_real_local, |
| memory_order_relaxed); |
| } |
| |
| int result = strcasecmp_real_local(s1, s2); |
| strcasecmp_hook_t hook = |
| atomic_load_explicit(&strcasecmp_hook, memory_order_relaxed); |
| if (LIKELY(hook != NULL)) { |
| hook(GET_CALLER_PC(), s1, s2, result); |
| } |
| return result; |
| } |
| |
| __attribute__((visibility("default"))) char *strstr(const char *s1, |
| const char *s2) { |
| strstr_t strstr_real_local = |
| atomic_load_explicit(&strstr_real, memory_order_relaxed); |
| if (UNLIKELY(strstr_real_local == NULL)) { |
| strstr_real_local = dlsym(RTLD_NEXT, "strstr"); |
| atomic_store_explicit(&strstr_real, strstr_real_local, |
| memory_order_relaxed); |
| } |
| |
| char *result = strstr_real_local(s1, s2); |
| strstr_hook_t hook = atomic_load_explicit(&strstr_hook, memory_order_relaxed); |
| if (LIKELY(hook != NULL)) { |
| hook(GET_CALLER_PC(), s1, s2, result); |
| } |
| return result; |
| } |
| |
| __attribute__((visibility("default"))) char *strcasestr(const char *s1, |
| const char *s2) { |
| strcasestr_t strcasestr_real_local = |
| atomic_load_explicit(&strcasestr_real, memory_order_relaxed); |
| if (UNLIKELY(strcasestr_real_local == NULL)) { |
| strcasestr_real_local = dlsym(RTLD_NEXT, "strcasestr"); |
| atomic_store_explicit(&strcasestr_real, strcasestr_real_local, |
| memory_order_relaxed); |
| } |
| |
| char *result = strcasestr_real_local(s1, s2); |
| strcasestr_hook_t hook = |
| atomic_load_explicit(&strcasestr_hook, memory_order_relaxed); |
| if (LIKELY(hook != NULL)) { |
| hook(GET_CALLER_PC(), s1, s2, result); |
| } |
| return result; |
| } |
| |
| __attribute__((visibility("default"))) void *memmem(const void *s1, size_t n1, |
| const void *s2, size_t n2) { |
| memmem_t memmem_real_local = |
| atomic_load_explicit(&memmem_real, memory_order_relaxed); |
| if (UNLIKELY(memmem_real_local == NULL)) { |
| memmem_real_local = dlsym(RTLD_NEXT, "memmem"); |
| atomic_store_explicit(&memmem_real, memmem_real_local, |
| memory_order_relaxed); |
| } |
| |
| void *result = memmem_real_local(s1, n1, s2, n2); |
| memmem_hook_t hook = atomic_load_explicit(&memmem_hook, memory_order_relaxed); |
| if (LIKELY(hook != NULL)) { |
| hook(GET_CALLER_PC(), s1, n1, s2, n2, result); |
| } |
| return result; |
| } |
| |
| // The __sanitizer_cov_trace_* family of functions is only invoked from code |
| // compiled with -fsanitize=fuzzer. We can assume that the Jazzer JNI library |
| // has been loaded before any such code, which necessarily belongs to the fuzz |
| // target, is executed and thus don't need NULL checks. |
| |
| __attribute__((visibility("default"))) void __sanitizer_cov_trace_cmp1( |
| uint8_t arg1, uint8_t arg2) { |
| trace_cmp1_t hook = |
| atomic_load_explicit(&trace_cmp1_with_pc, memory_order_relaxed); |
| hook(GET_CALLER_PC(), arg1, arg2); |
| } |
| |
| __attribute__((visibility("default"))) void __sanitizer_cov_trace_cmp2( |
| uint16_t arg1, uint16_t arg2) { |
| trace_cmp2_t hook = |
| atomic_load_explicit(&trace_cmp2_with_pc, memory_order_relaxed); |
| hook(GET_CALLER_PC(), arg1, arg2); |
| } |
| |
| __attribute__((visibility("default"))) void __sanitizer_cov_trace_cmp4( |
| uint32_t arg1, uint32_t arg2) { |
| trace_cmp4_t hook = |
| atomic_load_explicit(&trace_cmp4_with_pc, memory_order_relaxed); |
| hook(GET_CALLER_PC(), arg1, arg2); |
| } |
| |
| __attribute__((visibility("default"))) void __sanitizer_cov_trace_cmp8( |
| uint64_t arg1, uint64_t arg2) { |
| trace_cmp8_t hook = |
| atomic_load_explicit(&trace_cmp8_with_pc, memory_order_relaxed); |
| hook(GET_CALLER_PC(), arg1, arg2); |
| } |
| |
| __attribute__((visibility("default"))) void __sanitizer_cov_trace_const_cmp1( |
| uint8_t arg1, uint8_t arg2) { |
| trace_const_cmp1_t hook = |
| atomic_load_explicit(&trace_const_cmp1_with_pc, memory_order_relaxed); |
| hook(GET_CALLER_PC(), arg1, arg2); |
| } |
| |
| __attribute__((visibility("default"))) void __sanitizer_cov_trace_const_cmp2( |
| uint16_t arg1, uint16_t arg2) { |
| trace_const_cmp2_t hook = |
| atomic_load_explicit(&trace_const_cmp2_with_pc, memory_order_relaxed); |
| hook(GET_CALLER_PC(), arg1, arg2); |
| } |
| |
| __attribute__((visibility("default"))) void __sanitizer_cov_trace_const_cmp4( |
| uint32_t arg1, uint32_t arg2) { |
| trace_const_cmp4_t hook = |
| atomic_load_explicit(&trace_const_cmp4_with_pc, memory_order_relaxed); |
| hook(GET_CALLER_PC(), arg1, arg2); |
| } |
| |
| __attribute__((visibility("default"))) void __sanitizer_cov_trace_const_cmp8( |
| uint64_t arg1, uint64_t arg2) { |
| trace_const_cmp8_t hook = |
| atomic_load_explicit(&trace_const_cmp8_with_pc, memory_order_relaxed); |
| hook(GET_CALLER_PC(), arg1, arg2); |
| } |
| |
| __attribute__((visibility("default"))) void __sanitizer_cov_trace_switch( |
| uint64_t val, uint64_t *cases) { |
| trace_switch_t hook = |
| atomic_load_explicit(&trace_switch_with_pc, memory_order_relaxed); |
| hook(GET_CALLER_PC(), val, cases); |
| } |
| |
| __attribute__((visibility("default"))) void __sanitizer_cov_trace_div4( |
| uint32_t val) { |
| trace_div4_t hook = |
| atomic_load_explicit(&trace_div4_with_pc, memory_order_relaxed); |
| hook(GET_CALLER_PC(), val); |
| } |
| |
| __attribute__((visibility("default"))) void __sanitizer_cov_trace_div8( |
| uint64_t val) { |
| trace_div8_t hook = |
| atomic_load_explicit(&trace_div8_with_pc, memory_order_relaxed); |
| hook(GET_CALLER_PC(), val); |
| } |
| |
| __attribute__((visibility("default"))) void __sanitizer_cov_trace_gep( |
| uintptr_t idx) { |
| trace_gep_t hook = |
| atomic_load_explicit(&trace_gep_with_pc, memory_order_relaxed); |
| hook(GET_CALLER_PC(), idx); |
| } |
| |
| __attribute__((visibility("default"))) void __sanitizer_cov_trace_pc_indir( |
| uintptr_t callee) { |
| trace_pc_indir_t hook = |
| atomic_load_explicit(&trace_pc_indir_with_pc, memory_order_relaxed); |
| hook(GET_CALLER_PC(), callee); |
| } |
| |
| __attribute__((visibility("default"))) void __sanitizer_cov_8bit_counters_init( |
| uint8_t *start, uint8_t *end) { |
| cov_8bit_counters_init_t init = |
| atomic_load_explicit(&cov_8bit_counters_init, memory_order_relaxed); |
| init(start, end); |
| } |
| |
| __attribute__((visibility("default"))) void __sanitizer_cov_pcs_init( |
| const uintptr_t *pcs_beg, const uintptr_t *pcs_end) { |
| cov_pcs_init_t init = |
| atomic_load_explicit(&cov_pcs_init, memory_order_relaxed); |
| init(pcs_beg, pcs_end); |
| } |
| |
| // The __sanitizer_weak_hook_* family of functions can be invoked early on macOS |
| // and thus requires NULL checks. |
| |
| __attribute__((visibility("default"))) void __sanitizer_weak_hook_memcmp( |
| void *called_pc, const void *s1, const void *s2, size_t n, int result) { |
| memcmp_hook_t hook = atomic_load_explicit(&memcmp_hook, memory_order_relaxed); |
| if (LIKELY(hook != NULL)) { |
| hook(called_pc, s1, s2, n, result); |
| } |
| } |
| |
| __attribute__((visibility("default"))) void __sanitizer_weak_hook_strncmp( |
| void *called_pc, const void *s1, const void *s2, size_t n, int result) { |
| strncmp_hook_t hook = |
| atomic_load_explicit(&strncmp_hook, memory_order_relaxed); |
| if (LIKELY(hook != NULL)) { |
| hook(called_pc, s1, s2, n, result); |
| } |
| } |
| |
| __attribute__((visibility("default"))) void __sanitizer_weak_hook_strcmp( |
| void *called_pc, const void *s1, const void *s2, int result) { |
| strcmp_hook_t hook = atomic_load_explicit(&strcmp_hook, memory_order_relaxed); |
| if (LIKELY(hook != NULL)) { |
| hook(called_pc, s1, s2, result); |
| } |
| } |
| |
| __attribute__((visibility("default"))) void __sanitizer_weak_hook_strncasecmp( |
| void *called_pc, const void *s1, const void *s2, size_t n, int result) { |
| strncasecmp_hook_t hook = |
| atomic_load_explicit(&strncasecmp_hook, memory_order_relaxed); |
| if (LIKELY(hook != NULL)) { |
| hook(called_pc, s1, s2, n, result); |
| } |
| } |
| |
| __attribute__((visibility("default"))) void __sanitizer_weak_hook_strcasecmp( |
| void *called_pc, const void *s1, const void *s2, int result) { |
| strcasecmp_hook_t hook = |
| atomic_load_explicit(&strcasecmp_hook, memory_order_relaxed); |
| if (LIKELY(hook != NULL)) { |
| hook(called_pc, s1, s2, result); |
| } |
| } |
| |
| __attribute__((visibility("default"))) void __sanitizer_weak_hook_strstr( |
| void *called_pc, const void *s1, const void *s2, char *result) { |
| strstr_hook_t hook = atomic_load_explicit(&strstr_hook, memory_order_relaxed); |
| if (LIKELY(hook != NULL)) { |
| hook(called_pc, s1, s2, result); |
| } |
| } |
| |
| __attribute__((visibility("default"))) void __sanitizer_weak_hook_strcasestr( |
| void *called_pc, const void *s1, const void *s2, char *result) { |
| strcasestr_hook_t hook = |
| atomic_load_explicit(&strstr_hook, memory_order_relaxed); |
| hook(called_pc, s1, s2, result); |
| } |
| |
| __attribute__((visibility("default"))) void __sanitizer_weak_hook_memmem( |
| void *called_pc, const void *s1, size_t len1, const void *s2, size_t len2, |
| void *result) { |
| memmem_hook_t hook = atomic_load_explicit(&memmem_hook, memory_order_relaxed); |
| hook(called_pc, s1, len1, s2, len2, result); |
| } |