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