summaryrefslogtreecommitdiff
path: root/test/hwasan/TestCases
diff options
context:
space:
mode:
authorEvgeniy Stepanov <eugeni.stepanov@gmail.com>2018-09-24 23:03:34 +0000
committerEvgeniy Stepanov <eugeni.stepanov@gmail.com>2018-09-24 23:03:34 +0000
commit17003a1299e8670aaf77a567e1c2b830d398b9fc (patch)
tree4507d593f5b67fd3a248cd16bb7fbd364002c39f /test/hwasan/TestCases
parente266b158acecc1e724b61cd236bd24d2e36a9709 (diff)
downloadcompiler-rt-17003a1299e8670aaf77a567e1c2b830d398b9fc.tar.gz
[hwasan] Record and display stack history in stack-based reports.
Summary: Display a list of recent stack frames (not a stack trace!) when tag-mismatch is detected on a stack address. The implementation uses alignment tricks to get both the address of the history buffer, and the base address of the shadow with a single 8-byte load. See the comment in hwasan_thread_list.h for more details. Developed in collaboration with Kostya Serebryany. Reviewers: kcc Subscribers: srhines, kubamracek, mgorny, hiraditya, jfb, llvm-commits Differential Revision: https://reviews.llvm.org/D52249 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@342923 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/hwasan/TestCases')
-rw-r--r--test/hwasan/TestCases/deep-recursion.c73
-rw-r--r--test/hwasan/TestCases/rich-stack.c66
-rw-r--r--test/hwasan/TestCases/stack-history-length.c36
3 files changed, 175 insertions, 0 deletions
diff --git a/test/hwasan/TestCases/deep-recursion.c b/test/hwasan/TestCases/deep-recursion.c
new file mode 100644
index 000000000..1ac0f5b15
--- /dev/null
+++ b/test/hwasan/TestCases/deep-recursion.c
@@ -0,0 +1,73 @@
+// RUN: %clang_hwasan -O1 %s -o %t
+// RUN: %env_hwasan_opts=stack_history_size=1 not %run %t 2>&1 | FileCheck %s --check-prefix=D1
+// RUN: %env_hwasan_opts=stack_history_size=2 not %run %t 2>&1 | FileCheck %s --check-prefix=D2
+// RUN: %env_hwasan_opts=stack_history_size=3 not %run %t 2>&1 | FileCheck %s --check-prefix=D3
+// RUN: %env_hwasan_opts=stack_history_size=5 not %run %t 2>&1 | FileCheck %s --check-prefix=D5
+// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=DEFAULT
+
+// REQUIRES: stable-runtime
+
+#include <stdlib.h>
+// At least -O1 is needed for this function to not have a stack frame on
+// AArch64.
+void USE(void *x) { // pretend_to_do_something(void *x)
+ __asm__ __volatile__("" : : "r" (x) : "memory");
+}
+
+volatile int four = 4;
+
+__attribute__((noinline)) void OOB() { int x[4]; x[four] = 0; USE(&x[0]); }
+__attribute__((noinline)) void FUNC1() { int x; USE(&x); OOB(); }
+__attribute__((noinline)) void FUNC2() { int x; USE(&x); FUNC1(); }
+__attribute__((noinline)) void FUNC3() { int x; USE(&x); FUNC2(); }
+__attribute__((noinline)) void FUNC4() { int x; USE(&x); FUNC3(); }
+__attribute__((noinline)) void FUNC5() { int x; USE(&x); FUNC4(); }
+__attribute__((noinline)) void FUNC6() { int x; USE(&x); FUNC5(); }
+__attribute__((noinline)) void FUNC7() { int x; USE(&x); FUNC6(); }
+__attribute__((noinline)) void FUNC8() { int x; USE(&x); FUNC7(); }
+__attribute__((noinline)) void FUNC9() { int x; USE(&x); FUNC8(); }
+__attribute__((noinline)) void FUNC10() { int x; USE(&x); FUNC9(); }
+
+int main() { FUNC10(); }
+
+// D1: Previosly allocated frames
+// D1: in OOB
+// D1-NOT: in FUNC
+// D1: Memory tags around the buggy address
+
+// D2: Previosly allocated frames
+// D2: in OOB
+// D2: in FUNC1
+// D2-NOT: in FUNC
+// D2: Memory tags around the buggy address
+
+// D3: Previosly allocated frames
+// D3: in OOB
+// D3: in FUNC1
+// D3: in FUNC2
+// D3-NOT: in FUNC
+// D3: Memory tags around the buggy address
+
+// D5: Previosly allocated frames
+// D5: in OOB
+// D5: in FUNC1
+// D5: in FUNC2
+// D5: in FUNC3
+// D5: in FUNC4
+// D5-NOT: in FUNC
+// D5: Memory tags around the buggy address
+
+// DEFAULT: Previosly allocated frames
+// DEFAULT: in OOB
+// DEFAULT: in FUNC1
+// DEFAULT: in FUNC2
+// DEFAULT: in FUNC3
+// DEFAULT: in FUNC4
+// DEFAULT: in FUNC5
+// DEFAULT: in FUNC6
+// DEFAULT: in FUNC7
+// DEFAULT: in FUNC8
+// DEFAULT: in FUNC9
+// DEFAULT: in FUNC10
+// DEFAULT-NOT: in FUNC
+// DEFAULT: Memory tags around the buggy address
diff --git a/test/hwasan/TestCases/rich-stack.c b/test/hwasan/TestCases/rich-stack.c
new file mode 100644
index 000000000..6787d5776
--- /dev/null
+++ b/test/hwasan/TestCases/rich-stack.c
@@ -0,0 +1,66 @@
+// Test how stack frames are reported (not fully implemented yet).
+// RUN: %clang_hwasan %s -o %t
+// RUN: not %run %t 3 2 -1 2>&1 | FileCheck %s --check-prefix=R321
+// REQUIRES: stable-runtime
+#include <stdint.h>
+#include <stdlib.h>
+void USE(void *x) { // pretend_to_do_something(void *x)
+ __asm__ __volatile__("" : : "r" (x) : "memory");
+}
+void USE2(void *a, void *b) { USE(a); USE(b); }
+void USE4(void *a, void *b, void *c, void *d) { USE2(a, b); USE2(c, d); }
+
+void BAR(int depth, int err_depth, int offset);
+
+uint64_t *leaked_ptr;
+
+void FOO(int depth, int err_depth, int offset) {
+ uint8_t v1;
+ uint16_t v2;
+ uint32_t v4;
+ uint64_t v8;
+ uint64_t v16[2];
+ uint64_t v32[4];
+ uint64_t v48[3];
+ USE4(&v1, &v2, &v4, &v8); USE4(&v16, &v32, &v48, 0);
+ leaked_ptr = &v16[0];
+ if (depth)
+ BAR(depth - 1, err_depth, offset);
+
+ if (err_depth == depth)
+ v16[offset] = 0; // maybe OOB.
+ if (err_depth == -depth)
+ leaked_ptr[offset] = 0; // maybe UAR.
+ USE(&v16);
+}
+
+void BAR(int depth, int err_depth, int offset) {
+ uint64_t x16[2];
+ uint64_t x32[4];
+ USE2(&x16, &x32);
+ leaked_ptr = &x16[0];
+ if (depth)
+ FOO(depth - 1, err_depth, offset);
+ if (err_depth == depth)
+ x16[offset] = 0; // maybe OOB
+ if (err_depth == -depth)
+ leaked_ptr[offset] = 0; // maybe UAR
+ USE(&x16);
+}
+
+
+int main(int argc, char **argv) {
+ if (argc != 4) return -1;
+ int depth = atoi(argv[1]);
+ int err_depth = atoi(argv[2]);
+ int offset = atoi(argv[3]);
+ FOO(depth, err_depth, offset);
+ return 0;
+}
+
+// R321: HWAddressSanitizer: tag-mismatch
+// R321-NEXT: WRITE of size 8
+// R321-NEXT: in BAR
+// R321-NEXT: in FOO
+// R321-NEXT: in main
+// R321: is located in stack of thread T0
diff --git a/test/hwasan/TestCases/stack-history-length.c b/test/hwasan/TestCases/stack-history-length.c
new file mode 100644
index 000000000..f4c0b036f
--- /dev/null
+++ b/test/hwasan/TestCases/stack-history-length.c
@@ -0,0 +1,36 @@
+// RUN: %clang_hwasan -O1 -DX=2046 %s -o %t.2046
+// RUN: %clang_hwasan -O1 -DX=2047 %s -o %t.2047
+// RUN: %env_hwasan_opts=stack_history_size=2048 not %run %t.2046 2>&1 | FileCheck %s --check-prefix=YES
+// RUN: %env_hwasan_opts=stack_history_size=2048 not %run %t.2047 2>&1 | FileCheck %s --check-prefix=NO
+
+// REQUIRES: stable-runtime
+
+#include <stdlib.h>
+
+void USE(void *x) { // pretend_to_do_something(void *x)
+ __asm__ __volatile__("" : : "r" (x) : "memory");
+}
+
+volatile int four = 4;
+__attribute__((noinline)) void FUNC0() { int x[4]; USE(&x[0]); }
+__attribute__((noinline)) void FUNC() { int x[4]; USE(&x[0]); }
+__attribute__((noinline)) void OOB() { int x[4]; x[four] = 0; USE(&x[0]); }
+
+int main() {
+ // FUNC0 is X+2's element of the ring buffer.
+ // If runtime buffer size is less than it, FUNC0 record will be lost.
+ FUNC0();
+ for (int i = 0; i < X; ++i)
+ FUNC();
+ OOB();
+}
+
+// YES: Previosly allocated frames
+// YES: OOB
+// YES: FUNC
+// YES: FUNC0
+
+// NO: Previosly allocated frames
+// NO: OOB
+// NO: FUNC
+// NO-NOT: FUNC0