1// RUN: %clang_hwasan -O1 %s -o %t
2// RUN: %env_hwasan_opts=stack_history_size=1 not %run %t 2>&1 | FileCheck %s --check-prefix=D1
3// RUN: %env_hwasan_opts=stack_history_size=2 not %run %t 2>&1 | FileCheck %s --check-prefix=D2
4// RUN: %env_hwasan_opts=stack_history_size=3 not %run %t 2>&1 | FileCheck %s --check-prefix=D3
5// RUN: %env_hwasan_opts=stack_history_size=5 not %run %t 2>&1 | FileCheck %s --check-prefix=D5
6// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=DEFAULT
7
8// Run the same tests as above, but using the __hwasan_add_frame_record libcall.
9// The output should be the exact same.
10// RUN: %clang_hwasan -O1 %s -o %t -mllvm -hwasan-record-stack-history=libcall
11// RUN: %env_hwasan_opts=stack_history_size=1 not %run %t 2>&1 | FileCheck %s --check-prefix=D1
12// RUN: %env_hwasan_opts=stack_history_size=2 not %run %t 2>&1 | FileCheck %s --check-prefix=D2
13// RUN: %env_hwasan_opts=stack_history_size=3 not %run %t 2>&1 | FileCheck %s --check-prefix=D3
14// RUN: %env_hwasan_opts=stack_history_size=5 not %run %t 2>&1 | FileCheck %s --check-prefix=D5
15// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=DEFAULT
16
17// Stack histories are currently not recorded on x86.
18// XFAIL: target=x86_64{{.*}}
19
20#include <assert.h>
21#include <sanitizer/hwasan_interface.h>
22#include <stdlib.h>
23
24// At least -O1 is needed for this function to not have a stack frame on
25// AArch64.
26void USE(void *x) { // pretend_to_do_something(void *x)
27 __asm__ __volatile__("" : : "r" (x) : "memory");
28}
29
30volatile int four = 4;
31
32__attribute__((noinline)) void OOB() {
33 int x[4];
34 int y[4];
35
36 // Tags for stack-allocated variables can occasionally be zero, resulting in
37 // a false negative for this test. The tag allocation algorithm is not easy
38 // to fix, hence we work around it: if the tag is zero, we use the
39 // neighboring variable instead, which must have a different (hence non-zero)
40 // tag.
41 if (__hwasan_tag_pointer(p: x, tag: 0) == x) {
42 assert(__hwasan_tag_pointer(y, 0) != y);
43 y[four] = 0;
44 } else {
45 x[four] = 0;
46 }
47 USE(x: &x[0]);
48 USE(x: &y[0]);
49}
50__attribute__((noinline)) void FUNC1() { int x; USE(x: &x); OOB(); }
51__attribute__((noinline)) void FUNC2() { int x; USE(x: &x); FUNC1(); }
52__attribute__((noinline)) void FUNC3() { int x; USE(x: &x); FUNC2(); }
53__attribute__((noinline)) void FUNC4() { int x; USE(x: &x); FUNC3(); }
54__attribute__((noinline)) void FUNC5() { int x; USE(x: &x); FUNC4(); }
55__attribute__((noinline)) void FUNC6() { int x; USE(x: &x); FUNC5(); }
56__attribute__((noinline)) void FUNC7() { int x; USE(x: &x); FUNC6(); }
57__attribute__((noinline)) void FUNC8() { int x; USE(x: &x); FUNC7(); }
58__attribute__((noinline)) void FUNC9() { int x; USE(x: &x); FUNC8(); }
59__attribute__((noinline)) void FUNC10() { int x; USE(x: &x); FUNC9(); }
60
61int main() { FUNC10(); }
62
63// D1: Previously allocated frames
64// D1: in OOB
65// D1-NOT: in FUNC
66// D1: Memory tags around the buggy address
67
68// D2: Previously allocated frames
69// D2: in OOB
70// D2: in FUNC1
71// D2-NOT: in FUNC
72// D2: Memory tags around the buggy address
73
74// D3: Previously allocated frames
75// D3: in OOB
76// D3: in FUNC1
77// D3: in FUNC2
78// D3-NOT: in FUNC
79// D3: Memory tags around the buggy address
80
81// D5: Previously allocated frames
82// D5: in OOB
83// D5: in FUNC1
84// D5: in FUNC2
85// D5: in FUNC3
86// D5: in FUNC4
87// D5-NOT: in FUNC
88// D5: Memory tags around the buggy address
89
90// DEFAULT: Previously allocated frames
91// DEFAULT: in OOB
92// DEFAULT: in FUNC1
93// DEFAULT: in FUNC2
94// DEFAULT: in FUNC3
95// DEFAULT: in FUNC4
96// DEFAULT: in FUNC5
97// DEFAULT: in FUNC6
98// DEFAULT: in FUNC7
99// DEFAULT: in FUNC8
100// DEFAULT: in FUNC9
101// DEFAULT: in FUNC10
102// DEFAULT-NOT: in FUNC
103// DEFAULT: Memory tags around the buggy address
104

source code of compiler-rt/test/hwasan/TestCases/deep-recursion.c