xref: /llvm-project/compiler-rt/test/hwasan/TestCases/deep-recursion.c (revision ddf1de20a3f7db3bca1ef6ba7e6cbb90aac5fd2d)
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.
USE(void * x)26 void USE(void *x) { // pretend_to_do_something(void *x)
27   __asm__ __volatile__("" : : "r" (x) : "memory");
28 }
29 
30 volatile int four = 4;
31 
OOB()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(x, 0) == x) {
42     assert(__hwasan_tag_pointer(y, 0) != y);
43     y[four] = 0;
44   } else {
45     x[four] = 0;
46   }
47   USE(&x[0]);
48   USE(&y[0]);
49 }
FUNC1()50 __attribute__((noinline)) void FUNC1() { int x; USE(&x); OOB(); }
FUNC2()51 __attribute__((noinline)) void FUNC2() { int x; USE(&x); FUNC1(); }
FUNC3()52 __attribute__((noinline)) void FUNC3() { int x; USE(&x); FUNC2(); }
FUNC4()53 __attribute__((noinline)) void FUNC4() { int x; USE(&x); FUNC3(); }
FUNC5()54 __attribute__((noinline)) void FUNC5() { int x; USE(&x); FUNC4(); }
FUNC6()55 __attribute__((noinline)) void FUNC6() { int x; USE(&x); FUNC5(); }
FUNC7()56 __attribute__((noinline)) void FUNC7() { int x; USE(&x); FUNC6(); }
FUNC8()57 __attribute__((noinline)) void FUNC8() { int x; USE(&x); FUNC7(); }
FUNC9()58 __attribute__((noinline)) void FUNC9() { int x; USE(&x); FUNC8(); }
FUNC10()59 __attribute__((noinline)) void FUNC10() { int x; USE(&x); FUNC9(); }
60 
main()61 int 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