aboutsummaryrefslogtreecommitdiff
path: root/test/asan/TestCases/Posix/start-deactivated.cc
blob: 2870ffb2f4540df96e3d05ed194794377e9642ab (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
// Test for ASAN_OPTIONS=start_deactivated=1 mode.
// Main executable is uninstrumented, but linked to ASan runtime. The shared
// library is instrumented. Memory errors before dlopen are not detected.

// RUN: %clangxx_asan -O0 -DSHARED_LIB %s -std=c++11 -fPIC -shared -o %t-so.so
// RUN: %clangxx -O0 %s -std=c++11 -c -o %t.o
// RUN: %clangxx_asan -O0 %t.o %libdl -o %t
// RUN: %env_asan_opts=start_deactivated=1,allocator_may_return_null=0 \
// RUN:   ASAN_ACTIVATION_OPTIONS=allocator_may_return_null=1 not %run %t 2>&1 | FileCheck %s
// RUN: %env_asan_opts=start_deactivated=1 \
// RUN:   ASAN_ACTIVATION_OPTIONS=help=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-HELP
// RUN: %env_asan_opts=start_deactivated=1,verbosity=1 \
// RUN:   ASAN_ACTIVATION_OPTIONS=help=1,handle_segv=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-UNSUPPORTED
// RUN: %env_asan_opts=start_deactivated=1 \
// RUN:   ASAN_ACTIVATION_OPTIONS=help=1,handle_segv=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-UNSUPPORTED-V0

// Check that verbosity=1 in activation flags affects reporting of unrecognized activation flags.
// RUN: %env_asan_opts=start_deactivated=1 \
// RUN:   ASAN_ACTIVATION_OPTIONS=help=1,handle_segv=0,verbosity=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-UNSUPPORTED

// XFAIL: arm-linux-gnueabi
// UNSUPPORTED: ios

// END.

#if !defined(SHARED_LIB)

#include <assert.h>
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

#include <string>

#include "sanitizer/asan_interface.h"

void test_malloc_shadow(char *p, size_t sz, bool expect_redzones) {
  // Last byte of the left redzone, if present.
  assert((char *)__asan_region_is_poisoned(p - 1, sz + 1) ==
         (expect_redzones ? p - 1 : nullptr));
  // The user memory.
  assert((char *)__asan_region_is_poisoned(p, sz) == nullptr);
  // First byte of the right redzone, if present.
  assert((char *)__asan_region_is_poisoned(p, sz + 1) ==
         (expect_redzones ? p + sz : nullptr));
}

typedef void (*Fn)();

int main(int argc, char *argv[]) {
  constexpr unsigned nPtrs = 200;
  char *ptrs[nPtrs];

  // Before activation: no redzones.
  for (size_t sz = 1; sz < nPtrs; ++sz) {
    ptrs[sz] = (char *)malloc(sz);
    test_malloc_shadow(ptrs[sz], sz, false);
  }

  // Create a honey pot for the future, instrumented, allocations. Since the
  // quarantine is disabled, chunks are going to be recycled right away and
  // reused for the new allocations. New allocations must get the proper
  // redzones anyway, whether it's a fresh or reused allocation.
  constexpr size_t HoneyPotBlockSize = 4096;
  constexpr int HoneyPotSize = 200;
  char *honeyPot[HoneyPotSize];
  for (int i = 1; i < HoneyPotSize; ++i) {
    honeyPot[i] = (char *)malloc(HoneyPotBlockSize);
    test_malloc_shadow(honeyPot[i], HoneyPotBlockSize, false);
  }
  for (int i = 1; i < HoneyPotSize; ++i)
    free(honeyPot[i]);

  std::string path = std::string(argv[0]) + "-so.so";
  void *dso = dlopen(path.c_str(), RTLD_NOW);
  if (!dso) {
    fprintf(stderr, "dlopen failed: %s\n", dlerror());
    return 1;
  }

  // After this line ASan is activated and starts detecting errors.
  void *fn = dlsym(dso, "do_another_bad_thing");
  if (!fn) {
    fprintf(stderr, "dlsym failed: %s\n", dlerror());
    return 1;
  }

  // After activation: redzones.
  for (int i = 1; i < HoneyPotSize; ++i) {
    honeyPot[i] = (char *)malloc(HoneyPotBlockSize);
    test_malloc_shadow(honeyPot[i], HoneyPotBlockSize, true);
  }
  {
    char *p = (char *)malloc(HoneyPotBlockSize);
    test_malloc_shadow(p, HoneyPotBlockSize, true);
    free(p);
  }
  for (int i = 1; i < HoneyPotSize; ++i)
    free(honeyPot[i]);

  // Pre-existing allocations got redzones, too.
  for (size_t sz = 1; sz < nPtrs; ++sz) {
    test_malloc_shadow(ptrs[sz], sz, true);
    free(ptrs[sz]);
  }

  // Test that ASAN_ACTIVATION_OPTIONS=allocator_may_return_null=1 has effect.
  void *p = malloc((unsigned long)-2);
  assert(!p);
  // CHECK: WARNING: AddressSanitizer failed to allocate 0xfff{{.*}} bytes

  ((Fn)fn)();
  // CHECK: AddressSanitizer: heap-buffer-overflow
  // CHECK: READ of size 1
  // CHECK: {{#0 .* in do_another_bad_thing}}
  // CHECK: is located 5 bytes to the right of 100-byte region
  // CHECK: in do_another_bad_thing

  return 0;
}

#else  // SHARED_LIB

#include <stdio.h>
#include <stdlib.h>

extern "C" void do_another_bad_thing() {
  char *volatile p = (char *)malloc(100);
  printf("%hhx\n", p[105]);
}

#endif  // SHARED_LIB

// help=1 in activation flags lists only flags are are supported at activation
// CHECK-HELP: Available flags for {{.*}}Sanitizer:
// CHECK-HELP-NOT: handle_segv
// CHECK-HELP: max_redzone
// CHECK-HELP-NOT: handle_segv

// unsupported activation flags produce a warning ...
// CHECK-UNSUPPORTED: WARNING: found 1 unrecognized
// CHECK-UNSUPPORTED:   handle_segv

// ... but not at verbosity=0
// CHECK-UNSUPPORTED-V0-NOT: WARNING: found {{.*}} unrecognized