aboutsummaryrefslogtreecommitdiff
path: root/test/asan/TestCases/stack-use-after-return.cc
diff options
context:
space:
mode:
Diffstat (limited to 'test/asan/TestCases/stack-use-after-return.cc')
-rw-r--r--test/asan/TestCases/stack-use-after-return.cc80
1 files changed, 80 insertions, 0 deletions
diff --git a/test/asan/TestCases/stack-use-after-return.cc b/test/asan/TestCases/stack-use-after-return.cc
new file mode 100644
index 000000000000..437c457748c4
--- /dev/null
+++ b/test/asan/TestCases/stack-use-after-return.cc
@@ -0,0 +1,80 @@
+// RUN: export ASAN_OPTIONS=detect_stack_use_after_return=1
+// RUN: %clangxx_asan -O0 %s -pthread -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -pthread -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -pthread -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -pthread -o %t && not %run %t 2>&1 | FileCheck %s
+// RUN: env ASAN_OPTIONS=detect_stack_use_after_return=0 %run %t
+// Regression test for a CHECK failure with small stack size and large frame.
+// RUN: %clangxx_asan -O3 %s -pthread -o %t -DkSize=10000 -DUseThread -DkStackSize=65536 && not %run %t 2>&1 | FileCheck --check-prefix=THREAD %s
+//
+// Test that we can find UAR in a thread other than main:
+// RUN: %clangxx_asan -DUseThread -O2 %s -pthread -o %t && not %run %t 2>&1 | FileCheck --check-prefix=THREAD %s
+//
+// Test the max_uar_stack_size_log/min_uar_stack_size_log flag.
+//
+// RUN: env ASAN_OPTIONS=$ASAN_OPTIONS:max_uar_stack_size_log=20:verbosity=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-20 %s
+// RUN: env ASAN_OPTIONS=$ASAN_OPTIONS:min_uar_stack_size_log=24:max_uar_stack_size_log=24:verbosity=1 not %run %t 2>&1 | FileCheck --check-prefix=CHECK-24 %s
+
+#include <stdio.h>
+#include <pthread.h>
+
+#ifndef kSize
+# define kSize 1
+#endif
+
+#ifndef UseThread
+# define UseThread 0
+#endif
+
+#ifndef kStackSize
+# define kStackSize 0
+#endif
+
+__attribute__((noinline))
+char *Ident(char *x) {
+ fprintf(stderr, "1: %p\n", x);
+ return x;
+}
+
+__attribute__((noinline))
+char *Func1() {
+ char local[kSize];
+ return Ident(local);
+}
+
+__attribute__((noinline))
+void Func2(char *x) {
+ fprintf(stderr, "2: %p\n", x);
+ *x = 1;
+ // CHECK: WRITE of size 1 {{.*}} thread T0
+ // CHECK: #0{{.*}}Func2{{.*}}stack-use-after-return.cc:[[@LINE-2]]
+ // CHECK: is located in stack of thread T0 at offset
+ // CHECK: 'local' <== Memory access at offset {{16|32}} is inside this variable
+ // THREAD: WRITE of size 1 {{.*}} thread T{{[1-9]}}
+ // THREAD: #0{{.*}}Func2{{.*}}stack-use-after-return.cc:[[@LINE-6]]
+ // THREAD: is located in stack of thread T{{[1-9]}} at offset
+ // THREAD: 'local' <== Memory access at offset {{16|32}} is inside this variable
+ // CHECK-20: T0: FakeStack created:{{.*}} stack_size_log: 20
+ // CHECK-24: T0: FakeStack created:{{.*}} stack_size_log: 24
+}
+
+void *Thread(void *unused) {
+ Func2(Func1());
+ return NULL;
+}
+
+int main(int argc, char **argv) {
+#if UseThread
+ pthread_attr_t attr;
+ pthread_attr_init(&attr);
+ if (kStackSize > 0)
+ pthread_attr_setstacksize(&attr, kStackSize);
+ pthread_t t;
+ pthread_create(&t, &attr, Thread, 0);
+ pthread_attr_destroy(&attr);
+ pthread_join(t, 0);
+#else
+ Func2(Func1());
+#endif
+ return 0;
+}