1 // Test for ASAN_OPTIONS=start_deactivated=1 mode. 2 // Main executable is uninstrumented, but linked to ASan runtime. The shared 3 // library is instrumented. Memory errors before dlopen are not detected. 4 // Fails with debug checks: https://bugs.llvm.org/show_bug.cgi?id=46862 5 // XFAIL: !compiler-rt-optimized 6 7 // RUN: %clangxx_asan -O0 -DSHARED_LIB %s -std=c++11 -fPIC -shared -o %t-so.so 8 // RUN: %clangxx -O0 %s -std=c++11 -c -o %t.o 9 // RUN: %clangxx_asan -O0 %t.o %libdl -o %t 10 // RUN: %env_asan_opts=start_deactivated=1,allocator_may_return_null=0 \ 11 // RUN: ASAN_ACTIVATION_OPTIONS=allocator_may_return_null=1 not %run %t 2>&1 | FileCheck %s 12 // RUN: %env_asan_opts=start_deactivated=1 \ 13 // RUN: ASAN_ACTIVATION_OPTIONS=help=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-HELP 14 // RUN: %env_asan_opts=start_deactivated=1,verbosity=1 \ 15 // RUN: ASAN_ACTIVATION_OPTIONS=help=1,handle_segv=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-UNSUPPORTED 16 // RUN: %env_asan_opts=start_deactivated=1 \ 17 // RUN: ASAN_ACTIVATION_OPTIONS=help=1,handle_segv=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-UNSUPPORTED-V0 18 19 // Check that verbosity=1 in activation flags affects reporting of unrecognized activation flags. 20 // RUN: %env_asan_opts=start_deactivated=1 \ 21 // RUN: ASAN_ACTIVATION_OPTIONS=help=1,handle_segv=0,verbosity=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-UNSUPPORTED 22 23 24 // END. 25 26 #if !defined(SHARED_LIB) 27 28 #include <assert.h> 29 #include <dlfcn.h> 30 #include <stdio.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <unistd.h> 34 35 #include <string> 36 37 #include "sanitizer/asan_interface.h" 38 39 void test_malloc_shadow(char *p, size_t sz, bool expect_redzones) { 40 // Last byte of the left redzone, if present. 41 assert((char *)__asan_region_is_poisoned(p - 1, sz + 1) == 42 (expect_redzones ? p - 1 : nullptr)); 43 // The user memory. 44 assert((char *)__asan_region_is_poisoned(p, sz) == nullptr); 45 // First byte of the right redzone, if present. 46 assert((char *)__asan_region_is_poisoned(p, sz + 1) == 47 (expect_redzones ? p + sz : nullptr)); 48 } 49 50 typedef void (*Fn)(); 51 52 int main(int argc, char *argv[]) { 53 constexpr unsigned nPtrs = 200; 54 char *ptrs[nPtrs]; 55 56 // Before activation: no redzones. 57 for (size_t sz = 1; sz < nPtrs; ++sz) { 58 ptrs[sz] = (char *)malloc(sz); 59 test_malloc_shadow(ptrs[sz], sz, false); 60 } 61 62 // Create a honey pot for the future, instrumented, allocations. Since the 63 // quarantine is disabled, chunks are going to be recycled right away and 64 // reused for the new allocations. New allocations must get the proper 65 // redzones anyway, whether it's a fresh or reused allocation. 66 constexpr size_t HoneyPotBlockSize = 4096; 67 constexpr int HoneyPotSize = 200; 68 char *honeyPot[HoneyPotSize]; 69 for (int i = 1; i < HoneyPotSize; ++i) { 70 honeyPot[i] = (char *)malloc(HoneyPotBlockSize); 71 test_malloc_shadow(honeyPot[i], HoneyPotBlockSize, false); 72 } 73 for (int i = 1; i < HoneyPotSize; ++i) 74 free(honeyPot[i]); 75 76 std::string path = std::string(argv[0]) + "-so.so"; 77 void *dso = dlopen(path.c_str(), RTLD_NOW); 78 if (!dso) { 79 fprintf(stderr, "dlopen failed: %s\n", dlerror()); 80 return 1; 81 } 82 83 // After this line ASan is activated and starts detecting errors. 84 void *fn = dlsym(dso, "do_another_bad_thing"); 85 if (!fn) { 86 fprintf(stderr, "dlsym failed: %s\n", dlerror()); 87 return 1; 88 } 89 90 // After activation: redzones. 91 for (int i = 1; i < HoneyPotSize; ++i) { 92 honeyPot[i] = (char *)malloc(HoneyPotBlockSize); 93 test_malloc_shadow(honeyPot[i], HoneyPotBlockSize, true); 94 } 95 { 96 char *p = (char *)malloc(HoneyPotBlockSize); 97 test_malloc_shadow(p, HoneyPotBlockSize, true); 98 free(p); 99 } 100 for (int i = 1; i < HoneyPotSize; ++i) 101 free(honeyPot[i]); 102 103 // Pre-existing allocations got redzones, too. 104 for (size_t sz = 1; sz < nPtrs; ++sz) { 105 test_malloc_shadow(ptrs[sz], sz, true); 106 free(ptrs[sz]); 107 } 108 109 // Test that ASAN_ACTIVATION_OPTIONS=allocator_may_return_null=1 has effect. 110 void *p = malloc((unsigned long)-2); 111 assert(!p); 112 // CHECK: WARNING: AddressSanitizer failed to allocate 0xfff{{.*}} bytes 113 114 ((Fn)fn)(); 115 // CHECK: AddressSanitizer: heap-buffer-overflow 116 // CHECK: READ of size 1 117 // CHECK: {{#0 .* in do_another_bad_thing}} 118 // CHECK: is located 5 bytes to the right of 100-byte region 119 // CHECK: in do_another_bad_thing 120 121 return 0; 122 } 123 124 #else // SHARED_LIB 125 126 #include <stdio.h> 127 #include <stdlib.h> 128 129 extern "C" void do_another_bad_thing() { 130 char *volatile p = (char *)malloc(100); 131 printf("%hhx\n", p[105]); 132 } 133 134 #endif // SHARED_LIB 135 136 // help=1 in activation flags lists only flags are are supported at activation 137 // CHECK-HELP: Available flags for {{.*}}Sanitizer: 138 // CHECK-HELP-NOT: handle_segv 139 // CHECK-HELP: max_redzone 140 // CHECK-HELP-NOT: handle_segv 141 142 // unsupported activation flags produce a warning ... 143 // CHECK-UNSUPPORTED: WARNING: found 1 unrecognized 144 // CHECK-UNSUPPORTED: handle_segv 145 146 // ... but not at verbosity=0 147 // CHECK-UNSUPPORTED-V0-NOT: WARNING: found {{.*}} unrecognized 148