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
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
17 // Stack histories are currently not recorded on x86.
18 // XFAIL: target=x86_64{{.*}}
21 #include <sanitizer/hwasan_interface.h>
24 // At least -O1 is needed for this function to not have a stack frame on
26 void USE(void *x
) { // pretend_to_do_something(void *x)
27 __asm__
__volatile__("" : : "r" (x
) : "memory");
30 volatile int four
= 4;
32 __attribute__((noinline
)) void OOB() {
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)
41 if (__hwasan_tag_pointer(x
, 0) == x
) {
42 assert(__hwasan_tag_pointer(y
, 0) != y
);
50 __attribute__((noinline
)) void FUNC1() { int x
; USE(&x
); OOB(); }
51 __attribute__((noinline
)) void FUNC2() { int x
; USE(&x
); FUNC1(); }
52 __attribute__((noinline
)) void FUNC3() { int x
; USE(&x
); FUNC2(); }
53 __attribute__((noinline
)) void FUNC4() { int x
; USE(&x
); FUNC3(); }
54 __attribute__((noinline
)) void FUNC5() { int x
; USE(&x
); FUNC4(); }
55 __attribute__((noinline
)) void FUNC6() { int x
; USE(&x
); FUNC5(); }
56 __attribute__((noinline
)) void FUNC7() { int x
; USE(&x
); FUNC6(); }
57 __attribute__((noinline
)) void FUNC8() { int x
; USE(&x
); FUNC7(); }
58 __attribute__((noinline
)) void FUNC9() { int x
; USE(&x
); FUNC8(); }
59 __attribute__((noinline
)) void FUNC10() { int x
; USE(&x
); FUNC9(); }
61 int main() { FUNC10(); }
63 // D1: Previously allocated frames
66 // D1: Memory tags around the buggy address
68 // D2: Previously allocated frames
72 // D2: Memory tags around the buggy address
74 // D3: Previously allocated frames
79 // D3: Memory tags around the buggy address
81 // D5: Previously allocated frames
88 // D5: Memory tags around the buggy address
90 // DEFAULT: Previously allocated frames
101 // DEFAULT: in FUNC10
102 // DEFAULT-NOT: in FUNC
103 // DEFAULT: Memory tags around the buggy address