1// RUN: %clangxx_asan -O2 %s -o %t -DTEST=basic_hook_works && not %run %t \
2// RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-BASIC
3// RUN: %clangxx_asan -O2 %s -o %t -DTEST=ignore && %run %t \
4// RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-IGNORE
5// RUN: %clangxx_asan -O2 %s -o %t -DTEST=ignore_twice && not %run %t \
6// RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-IGNORE-2
7// RUN: %clangxx_asan -O2 %s -o %t -DTEST=mismatch && %env_asan_opts=alloc_dealloc_mismatch=1 not %run %t \
8// RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-MISMATCH
9// RUN: %clangxx_asan -O2 %s -o %t -DTEST=ignore_mismatch && %env_asan_opts=alloc_dealloc_mismatch=1 %run %t \
10// RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-IGNORE-MISMATCH
11// RUN: %clangxx_asan -O2 %s -o %t -DTEST=double_delete && not %run %t \
12// RUN: 2>&1 | FileCheck %s -check-prefix=CHECK-DOUBLE-DELETE
13
14#include <stdio.h>
15#include <stdlib.h>
16
17static char *volatile glob_ptr;
18bool ignore_free = false;
19
20#if (__APPLE__)
21// Required for dyld macOS 12.0+
22# define WEAK_ON_APPLE __attribute__((weak))
23#else // !(__APPLE__)
24# define WEAK_ON_APPLE
25#endif // (__APPLE__)
26
27extern "C" {
28WEAK_ON_APPLE void __sanitizer_free_hook(const volatile void *ptr) {
29 if (ptr == glob_ptr)
30 fprintf(stderr, format: "Free Hook\n");
31}
32
33WEAK_ON_APPLE int __sanitizer_ignore_free_hook(const volatile void *ptr) {
34 if (ptr != glob_ptr)
35 return 0;
36 fprintf(stderr, format: ignore_free ? "Free Ignored\n" : "Free Respected\n");
37 return ignore_free;
38}
39} // extern "C"
40
41void allocate() { glob_ptr = reinterpret_cast<char *volatile>(malloc(size: 100)); }
42void deallocate() { free(ptr: reinterpret_cast<void *>(glob_ptr)); }
43
44void basic_hook_works() {
45 allocate();
46 deallocate(); // CHECK-BASIC-NOT: Free Ignored
47 // CHECK-BASIC: Free Respected
48 // CHECK-BASIC: Free Hook
49 *glob_ptr = 0; // CHECK-BASIC: AddressSanitizer: heap-use-after-free
50}
51
52void ignore() {
53 allocate();
54 ignore_free = true;
55 deallocate();
56 // CHECK-IGNORE: Free Ignored
57 // CHECK-IGNORE-NOT: Free Respected
58 // CHECK-IGNORE-NOT: Free Hook
59 // CHECK-IGNORE-NOT: AddressSanitizer
60 *glob_ptr = 0;
61}
62
63void ignore_twice() {
64 allocate();
65 ignore_free = true;
66 deallocate(); // CHECK-IGNORE-2: Free Ignored
67 *glob_ptr = 0;
68 ignore_free = false;
69 deallocate(); // CHECK-IGNORE-2-NOT: Free Ignored
70 // CHECK-IGNORE-2: Free Respected
71 // CHECK-IGNORE-2: Free Hook
72 *glob_ptr = 0; // CHECK-IGNORE-2: AddressSanitizer: heap-use-after-free
73}
74
75void ignore_a_lot() {
76 allocate();
77 ignore_free = true;
78 for (int i = 0; i < 10000; ++i) {
79 deallocate(); // CHECK-IGNORE-3: Free Ignored
80 *glob_ptr = 0;
81 }
82 ignore_free = false;
83 deallocate(); // CHECK-IGNORE-3: Free Respected
84 // CHECK-IGNORE-3: Free Hook
85 *glob_ptr = 0; // CHECK-IGNORE-3: AddressSanitizer: heap-use-after-free
86}
87
88void mismatch() {
89 glob_ptr = new char;
90 deallocate(); // CHECK-MISMATCH: AddressSanitizer: alloc-dealloc-mismatch
91}
92
93void ignore_mismatch() {
94 glob_ptr = new char;
95 ignore_free = true;
96 // Mismatch isn't detected when the free() is ignored.
97 deallocate();
98 deallocate();
99 ignore_free = false;
100 // And also isn't detected when the memory is free()-d for real.
101 deallocate(); // CHECK-IGNORE-MISMATCH-NOT: AddressSanitizer: alloc-dealloc-mismatch
102}
103
104void double_delete() {
105 allocate();
106 ignore_free = true;
107 deallocate(); // CHECK-DOUBLE-DELETE: Free Ignored
108 deallocate(); // CHECK-DOUBLE-DELETE: Free Ignored
109 ignore_free = false;
110 deallocate(); // CHECK-DOUBLE-DELETE: Free Respected
111 // CHECK-DOUBLE-DELETE: Free Hook
112 deallocate(); // CHECK-DOUBLE-DELETE: AddressSanitizer: attempting double-free
113}
114
115int main() {
116 TEST();
117 return 0;
118}
119

source code of compiler-rt/test/asan/TestCases/Posix/ignore_free_hook.cpp