aboutsummaryrefslogtreecommitdiff
path: root/lib/asan/lit_tests/TestCases/Linux
diff options
context:
space:
mode:
Diffstat (limited to 'lib/asan/lit_tests/TestCases/Linux')
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/asan_prelink_test.cc28
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/clone_test.cc44
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/coverage.cc45
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/glob.cc29
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/glob_test_root/aa0
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/glob_test_root/ab0
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/glob_test_root/ba0
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/heap-overflow-large.cc23
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/heavy_uar_test.cc54
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/initialization-bug-any-order.cc36
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/interception_failure_test.cc22
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/interception_malloc_test.cc23
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc59
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/interception_test.cc22
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c35
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/lit.local.cfg9
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/malloc-in-qsort.cc56
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc31
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/overflow-in-qsort.cc51
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/preinit_test.cc27
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/ptrace.cc52
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/rlimit_mmap_test.cc16
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/swapcontext_test.cc90
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/syscalls.cc22
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/time_null_regtest.cc20
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/tsd_dtor_leak.cc39
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/uar_signals.cc70
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/unpoison_tls.cc35
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/zero-base-shadow32.cc24
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/zero-base-shadow64.cc24
30 files changed, 986 insertions, 0 deletions
diff --git a/lib/asan/lit_tests/TestCases/Linux/asan_prelink_test.cc b/lib/asan/lit_tests/TestCases/Linux/asan_prelink_test.cc
new file mode 100644
index 000000000000..0f158c1bb3dd
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/asan_prelink_test.cc
@@ -0,0 +1,28 @@
+// Test if asan works with prelink.
+// It does not actually use prelink, but relies on ld's flag -Ttext-segment
+// or gold's flag -Ttext (we try the first flag first, if that fails we
+// try the second flag).
+//
+// RUN: %clangxx_asan -c %s -o %t.o
+// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext-segment=0x3600000000 ||\
+// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t.so -Wl,-Ttext=0x3600000000
+// RUN: %clangxx_asan %t.o %t.so -Wl,-R. -o %t
+// RUN: ASAN_OPTIONS=verbosity=1 %t 2>&1 | FileCheck %s
+
+// REQUIRES: x86_64-supported-target, asan-64-bits
+#if BUILD_SO
+int G;
+int *getG() {
+ return &G;
+}
+#else
+#include <stdio.h>
+extern int *getG();
+int main(int argc, char **argv) {
+ long p = (long)getG();
+ printf("SO mapped at %lx\n", p & ~0xffffffffUL);
+ *getG() = 0;
+}
+#endif
+// CHECK: 0x003000000000, 0x004fffffffff{{.*}} MidMem
+// CHECK: SO mapped at 3600000000
diff --git a/lib/asan/lit_tests/TestCases/Linux/clone_test.cc b/lib/asan/lit_tests/TestCases/Linux/clone_test.cc
new file mode 100644
index 000000000000..0e12f35b400a
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/clone_test.cc
@@ -0,0 +1,44 @@
+// Regression test for:
+// http://code.google.com/p/address-sanitizer/issues/detail?id=37
+
+// RUN: %clangxx_asan -O0 %s -o %t && %t | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && %t | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && %t | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && %t | FileCheck %s
+
+#include <stdio.h>
+#include <sched.h>
+#include <sys/syscall.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+int Child(void *arg) {
+ char x[32] = {0}; // Stack gets poisoned.
+ printf("Child: %p\n", x);
+ _exit(1); // NoReturn, stack will remain unpoisoned unless we do something.
+}
+
+int main(int argc, char **argv) {
+ const int kStackSize = 1 << 20;
+ char child_stack[kStackSize + 1];
+ char *sp = child_stack + kStackSize; // Stack grows down.
+ printf("Parent: %p\n", sp);
+ pid_t clone_pid = clone(Child, sp, CLONE_FILES | CLONE_VM, NULL, 0, 0, 0);
+ int status;
+ pid_t wait_result = waitpid(clone_pid, &status, __WCLONE);
+ if (wait_result < 0) {
+ perror("waitpid");
+ return 0;
+ }
+ if (wait_result == clone_pid && WIFEXITED(status)) {
+ // Make sure the child stack was indeed unpoisoned.
+ for (int i = 0; i < kStackSize; i++)
+ child_stack[i] = i;
+ int ret = child_stack[argc - 1];
+ printf("PASSED\n");
+ // CHECK: PASSED
+ return ret;
+ }
+ return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/coverage.cc b/lib/asan/lit_tests/TestCases/Linux/coverage.cc
new file mode 100644
index 000000000000..4373e9b13c68
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/coverage.cc
@@ -0,0 +1,45 @@
+// RUN: %clangxx_asan -mllvm -asan-coverage=1 -DSHARED %s -shared -o %t.so -fPIC
+// RUN: %clangxx_asan -mllvm -asan-coverage=1 %s -o %t -Wl,-R. %t.so
+// RUN: export ASAN_OPTIONS=coverage=1:verbosity=1
+// RUN: %t 2>&1 | FileCheck %s --check-prefix=CHECK-main
+// RUN: %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-foo
+// RUN: %t bar 2>&1 | FileCheck %s --check-prefix=CHECK-bar
+// RUN: %t foo bar 2>&1 | FileCheck %s --check-prefix=CHECK-foo-bar
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef SHARED
+void bar() { printf("bar\n"); }
+#else
+__attribute__((noinline))
+void foo() { printf("foo\n"); }
+extern void bar();
+
+int main(int argc, char **argv) {
+ fprintf(stderr, "PID: %d\n", getpid());
+ for (int i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "foo"))
+ foo();
+ if (!strcmp(argv[i], "bar"))
+ bar();
+ }
+}
+#endif
+
+// CHECK-main: PID: [[PID:[0-9]+]]
+// CHECK-main: [[PID]].sancov: 1 PCs written
+// CHECK-main-NOT: .so.[[PID]]
+//
+// CHECK-foo: PID: [[PID:[0-9]+]]
+// CHECK-foo: [[PID]].sancov: 2 PCs written
+// CHECK-foo-NOT: .so.[[PID]]
+//
+// CHECK-bar: PID: [[PID:[0-9]+]]
+// CHECK-bar: [[PID]].sancov: 1 PCs written
+// CHECK-bar: .so.[[PID]].sancov: 1 PCs written
+//
+// CHECK-foo-bar: PID: [[PID:[0-9]+]]
+// CHECK-foo-bar: [[PID]].sancov: 2 PCs written
+// CHECK-foo-bar: so.[[PID]].sancov: 1 PCs written
diff --git a/lib/asan/lit_tests/TestCases/Linux/glob.cc b/lib/asan/lit_tests/TestCases/Linux/glob.cc
new file mode 100644
index 000000000000..123768b099ed
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/glob.cc
@@ -0,0 +1,29 @@
+// RUN: %clangxx_asan -O0 %s -o %t && %t %p 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && %t %p 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <glob.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <string>
+
+
+int main(int argc, char *argv[]) {
+ std::string path = argv[1];
+ std::string pattern = path + "/glob_test_root/*a";
+ printf("pattern: %s\n", pattern.c_str());
+
+ glob_t globbuf;
+ int res = glob(pattern.c_str(), 0, 0, &globbuf);
+
+ printf("%d %s\n", errno, strerror(errno));
+ assert(res == 0);
+ assert(globbuf.gl_pathc == 2);
+ printf("%zu\n", strlen(globbuf.gl_pathv[0]));
+ printf("%zu\n", strlen(globbuf.gl_pathv[1]));
+ globfree(&globbuf);
+ printf("PASS\n");
+ // CHECK: PASS
+ return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/glob_test_root/aa b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/aa
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/aa
diff --git a/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ab b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ab
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ab
diff --git a/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ba b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ba
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/glob_test_root/ba
diff --git a/lib/asan/lit_tests/TestCases/Linux/heap-overflow-large.cc b/lib/asan/lit_tests/TestCases/Linux/heap-overflow-large.cc
new file mode 100644
index 000000000000..67e9c3718d59
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/heap-overflow-large.cc
@@ -0,0 +1,23 @@
+// Regression test for
+// https://code.google.com/p/address-sanitizer/issues/detail?id=183
+
+// RUN: %clangxx_asan -O2 %s -o %t
+// RUN: not %t 12 2>&1 | FileCheck %s
+// RUN: not %t 100 2>&1 | FileCheck %s
+// RUN: not %t 10000 2>&1 | FileCheck %s
+
+#include <stdlib.h>
+#include <string.h>
+
+int main(int argc, char *argv[]) {
+ int *x = new int[5];
+ memset(x, 0, sizeof(x[0]) * 5);
+ int index = atoi(argv[1]);
+ int res = x[index];
+ // CHECK: AddressSanitizer: {{(heap-buffer-overflow|SEGV)}}
+ // CHECK: #0 0x{{.*}} in main {{.*}}heap-overflow-large.cc:[[@LINE-2]]
+ // CHECK: AddressSanitizer can not {{(provide additional info|describe address in more detail \(wild memory access suspected\))}}
+ // CHECK: SUMMARY: AddressSanitizer: {{(heap-buffer-overflow|SEGV)}}
+ delete[] x;
+ return res;
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/heavy_uar_test.cc b/lib/asan/lit_tests/TestCases/Linux/heavy_uar_test.cc
new file mode 100644
index 000000000000..27b179e83624
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/heavy_uar_test.cc
@@ -0,0 +1,54 @@
+// RUN: export ASAN_OPTIONS=detect_stack_use_after_return=1
+// RUN: %clangxx_asan -O0 %s -o %t && \
+// RUN: not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && \
+// RUN: not %t 2>&1 | FileCheck %s
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+__attribute__((noinline))
+char *pretend_to_do_something(char *x) {
+ __asm__ __volatile__("" : : "r" (x) : "memory");
+ return x;
+}
+
+__attribute__((noinline))
+char *LeakStack() {
+ char x[1024];
+ memset(x, 0, sizeof(x));
+ return pretend_to_do_something(x);
+}
+
+template<size_t kFrameSize>
+__attribute__((noinline))
+void RecuriveFunctionWithStackFrame(int depth) {
+ if (depth <= 0) return;
+ char x[kFrameSize];
+ x[0] = depth;
+ pretend_to_do_something(x);
+ RecuriveFunctionWithStackFrame<kFrameSize>(depth - 1);
+}
+
+int main(int argc, char **argv) {
+ int n_iter = argc >= 2 ? atoi(argv[1]) : 1000;
+ int depth = argc >= 3 ? atoi(argv[2]) : 500;
+ for (int i = 0; i < n_iter; i++) {
+ RecuriveFunctionWithStackFrame<10>(depth);
+ RecuriveFunctionWithStackFrame<100>(depth);
+ RecuriveFunctionWithStackFrame<500>(depth);
+ RecuriveFunctionWithStackFrame<1024>(depth);
+ RecuriveFunctionWithStackFrame<2000>(depth);
+ RecuriveFunctionWithStackFrame<5000>(depth);
+ RecuriveFunctionWithStackFrame<10000>(depth);
+ }
+ char *stale_stack = LeakStack();
+ RecuriveFunctionWithStackFrame<1024>(10);
+ stale_stack[100]++;
+ // CHECK: ERROR: AddressSanitizer: stack-use-after-return on address
+ // CHECK: is located in stack of thread T0 at offset 132 in frame
+ // CHECK: in LeakStack(){{.*}}heavy_uar_test.cc:
+ // CHECK: [32, 1056) 'x'
+ return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/initialization-bug-any-order.cc b/lib/asan/lit_tests/TestCases/Linux/initialization-bug-any-order.cc
new file mode 100644
index 000000000000..042a07e428d9
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/initialization-bug-any-order.cc
@@ -0,0 +1,36 @@
+// Test to make sure basic initialization order errors are caught.
+// Check that on Linux initialization order bugs are caught
+// independently on order in which we list source files (if we specify
+// strict init-order checking).
+
+// RUN: %clangxx_asan -O0 %s %p/../Helpers/initialization-bug-extra.cc -o %t
+// RUN: ASAN_OPTIONS=strict_init_order=true not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O0 %p/../Helpers/initialization-bug-extra.cc %s -o %t
+// RUN: ASAN_OPTIONS=strict_init_order=true not %t 2>&1 | FileCheck %s
+
+// Do not test with optimization -- the error may be optimized away.
+
+#include <cstdio>
+
+// 'y' is a dynamically initialized global residing in a different TU. This
+// dynamic initializer will read the value of 'y' before main starts. The
+// result is undefined behavior, which should be caught by initialization order
+// checking.
+extern int y;
+int __attribute__((noinline)) initX() {
+ return y + 1;
+ // CHECK: {{AddressSanitizer: initialization-order-fiasco}}
+ // CHECK: {{READ of size .* at 0x.* thread T0}}
+ // CHECK: {{#0 0x.* in .*initX.* .*initialization-bug-any-order.cc:}}[[@LINE-3]]
+ // CHECK: {{0x.* is located 0 bytes inside of global variable .*y.*}}
+}
+
+// This initializer begins our initialization order problems.
+static int x = initX();
+
+int main() {
+ // ASan should have caused an exit before main runs.
+ printf("PASS\n");
+ // CHECK-NOT: PASS
+ return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/interception_failure_test.cc b/lib/asan/lit_tests/TestCases/Linux/interception_failure_test.cc
new file mode 100644
index 000000000000..9d161aa2dccb
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/interception_failure_test.cc
@@ -0,0 +1,22 @@
+// If user provides his own libc functions, ASan doesn't
+// intercept these functions.
+
+// RUN: %clangxx_asan -O0 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && %t 2>&1 | FileCheck %s
+#include <stdlib.h>
+#include <stdio.h>
+
+extern "C" long strtol(const char *nptr, char **endptr, int base) {
+ fprintf(stderr, "my_strtol_interceptor\n");
+ return 0;
+}
+
+int main() {
+ char *x = (char*)malloc(10 * sizeof(char));
+ free(x);
+ return (int)strtol(x, 0, 10);
+ // CHECK: my_strtol_interceptor
+ // CHECK-NOT: heap-use-after-free
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/interception_malloc_test.cc b/lib/asan/lit_tests/TestCases/Linux/interception_malloc_test.cc
new file mode 100644
index 000000000000..cdd7239ab7bc
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/interception_malloc_test.cc
@@ -0,0 +1,23 @@
+// ASan interceptor can be accessed with __interceptor_ prefix.
+
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+
+extern "C" void *__interceptor_malloc(size_t size);
+extern "C" void *malloc(size_t size) {
+ write(2, "malloc call\n", sizeof("malloc call\n") - 1);
+ return __interceptor_malloc(size);
+}
+
+int main() {
+ char *x = (char*)malloc(10 * sizeof(char));
+ free(x);
+ return (int)strtol(x, 0, 10);
+ // CHECK: malloc call
+ // CHECK: heap-use-after-free
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc b/lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc
new file mode 100644
index 000000000000..198e1f3884dd
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/interception_readdir_r_test.cc
@@ -0,0 +1,59 @@
+// RUN: %clangxx_asan -O0 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
+//
+// RUN: %clangxx_asan -O0 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %t 2>&1 | FileCheck %s
+
+#include <dirent.h>
+#include <memory.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+
+int main() {
+ // Ensure the readdir_r interceptor doesn't erroneously mark the entire dirent
+ // as written when the end of the directory pointer is reached.
+ fputs("test1: reading the " TEMP_DIR " directory...\n", stderr);
+ DIR *d = opendir(TEMP_DIR);
+ struct dirent *result = (struct dirent *)(0xfeedbeef);
+ // We assume the temp dir for this test doesn't have crazy long file names.
+ char entry_buffer[4096];
+ memset(entry_buffer, 0xab, sizeof(entry_buffer));
+ unsigned count = 0;
+ do {
+ // Stamp the entry struct to try to trick the interceptor.
+ ((struct dirent *)entry_buffer)->d_reclen = 9999;
+ if (readdir_r(d, (struct dirent *)entry_buffer, &result) != 0)
+ abort();
+ ++count;
+ } while (result != NULL);
+ fprintf(stderr, "read %d entries\n", count);
+ closedir(d);
+ // CHECK: test1: reading the {{.*}} directory...
+ // CHECK-NOT: stack-buffer-overflow
+ // CHECK: read {{.*}} entries
+
+ // Ensure the readdir64_r interceptor doesn't have the bug either.
+ fputs("test2: reading the " TEMP_DIR " directory...\n", stderr);
+ d = opendir(TEMP_DIR);
+ struct dirent64 *result64;
+ memset(entry_buffer, 0xab, sizeof(entry_buffer));
+ count = 0;
+ do {
+ // Stamp the entry struct to try to trick the interceptor.
+ ((struct dirent64 *)entry_buffer)->d_reclen = 9999;
+ if (readdir64_r(d, (struct dirent64 *)entry_buffer, &result64) != 0)
+ abort();
+ ++count;
+ } while (result64 != NULL);
+ fprintf(stderr, "read %d entries\n", count);
+ closedir(d);
+ // CHECK: test2: reading the {{.*}} directory...
+ // CHECK-NOT: stack-buffer-overflow
+ // CHECK: read {{.*}} entries
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/interception_test.cc b/lib/asan/lit_tests/TestCases/Linux/interception_test.cc
new file mode 100644
index 000000000000..2b3316d7dc8a
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/interception_test.cc
@@ -0,0 +1,22 @@
+// ASan interceptor can be accessed with __interceptor_ prefix.
+
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
+#include <stdlib.h>
+#include <stdio.h>
+
+extern "C" long __interceptor_strtol(const char *nptr, char **endptr, int base);
+extern "C" long strtol(const char *nptr, char **endptr, int base) {
+ fprintf(stderr, "my_strtol_interceptor\n");
+ return __interceptor_strtol(nptr, endptr, base);
+}
+
+int main() {
+ char *x = (char*)malloc(10 * sizeof(char));
+ free(x);
+ return (int)strtol(x, 0, 10);
+ // CHECK: my_strtol_interceptor
+ // CHECK: heap-use-after-free
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c b/lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c
new file mode 100644
index 000000000000..d6ceda7af8b6
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c
@@ -0,0 +1,35 @@
+// Check the presense of interface symbols in compiled file.
+
+// RUN: %clang_asan -O2 %s -o %t.exe
+// RUN: nm -D %t.exe | grep " T " | sed "s/.* T //" \
+// RUN: | grep "__asan_" | sed "s/___asan_/__asan_/" \
+// RUN: | grep -v "__asan_malloc_hook" \
+// RUN: | grep -v "__asan_free_hook" \
+// RUN: | grep -v "__asan_symbolize" \
+// RUN: | grep -v "__asan_default_options" \
+// RUN: | grep -v "__asan_stack_" \
+// RUN: | grep -v "__asan_on_error" > %t.symbols
+// RUN: cat %p/../../../asan_interface_internal.h \
+// RUN: | sed "s/\/\/.*//" | sed "s/typedef.*//" \
+// RUN: | grep -v "OPTIONAL" \
+// RUN: | grep "__asan_.*(" | sed "s/.* __asan_/__asan_/;s/(.*//" \
+// RUN: > %t.interface
+// RUN: echo __asan_report_load1 >> %t.interface
+// RUN: echo __asan_report_load2 >> %t.interface
+// RUN: echo __asan_report_load4 >> %t.interface
+// RUN: echo __asan_report_load8 >> %t.interface
+// RUN: echo __asan_report_load16 >> %t.interface
+// RUN: echo __asan_report_store1 >> %t.interface
+// RUN: echo __asan_report_store2 >> %t.interface
+// RUN: echo __asan_report_store4 >> %t.interface
+// RUN: echo __asan_report_store8 >> %t.interface
+// RUN: echo __asan_report_store16 >> %t.interface
+// RUN: echo __asan_report_load_n >> %t.interface
+// RUN: echo __asan_report_store_n >> %t.interface
+// RUN: cat %t.interface | sort -u | diff %t.symbols -
+
+// FIXME: nm -D on powerpc somewhy shows ASan interface symbols residing
+// in "initialized data section".
+// REQUIRES: x86_64-supported-target,i386-supported-target
+
+int main() { return 0; }
diff --git a/lib/asan/lit_tests/TestCases/Linux/lit.local.cfg b/lib/asan/lit_tests/TestCases/Linux/lit.local.cfg
new file mode 100644
index 000000000000..57271b8078a4
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/lit.local.cfg
@@ -0,0 +1,9 @@
+def getRoot(config):
+ if not config.parent:
+ return config
+ return getRoot(config.parent)
+
+root = getRoot(config)
+
+if root.host_os not in ['Linux']:
+ config.unsupported = True
diff --git a/lib/asan/lit_tests/TestCases/Linux/malloc-in-qsort.cc b/lib/asan/lit_tests/TestCases/Linux/malloc-in-qsort.cc
new file mode 100644
index 000000000000..3251b35e143c
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/malloc-in-qsort.cc
@@ -0,0 +1,56 @@
+// RUN: %clangxx_asan -O2 %s -o %t
+// RUN: ASAN_OPTIONS=fast_unwind_on_malloc=1 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-FAST
+// RUN: ASAN_OPTIONS=fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-SLOW
+
+// Test how well we unwind in presence of qsort in the stack
+// (i.e. if we can unwind through a function compiled w/o frame pointers).
+// https://code.google.com/p/address-sanitizer/issues/detail?id=137
+
+// Fast unwinder is only avaliable on x86_64 and i386.
+// REQUIRES: x86_64-supported-target
+
+// REQUIRES: compiler-rt-optimized
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int *GlobalPtr;
+
+extern "C" {
+int QsortCallback(const void *a, const void *b) {
+ char *x = (char*)a;
+ char *y = (char*)b;
+ printf("Calling QsortCallback\n");
+ GlobalPtr = new int[10];
+ return (int)*x - (int)*y;
+}
+
+__attribute__((noinline))
+void MyQsort(char *a, size_t size) {
+ printf("Calling qsort\n");
+ qsort(a, size, sizeof(char), QsortCallback);
+ printf("Done\n"); // Avoid tail call.
+}
+} // extern "C"
+
+int main() {
+ char a[2] = {1, 2};
+ MyQsort(a, 2);
+ return GlobalPtr[10];
+}
+
+// Fast unwind: can not unwind through qsort.
+// FIXME: this test does not properly work with slow unwind yet.
+
+// CHECK-FAST: ERROR: AddressSanitizer: heap-buffer-overflow
+// CHECK-FAST: is located 0 bytes to the right
+// CHECK-FAST: #0{{.*}}operator new
+// CHECK-FAST-NEXT: #1{{.*}}QsortCallback
+// CHECK-FAST-NOT: MyQsort
+//
+// CHECK-SLOW: ERROR: AddressSanitizer: heap-buffer-overflow
+// CHECK-SLOW: is located 0 bytes to the right
+// CHECK-SLOW: #0{{.*}}operator new
+// CHECK-SLOW-NEXT: #1{{.*}}QsortCallback
+// CHECK-SLOW: #{{.*}}MyQsort
+// CHECK-SLOW-NEXT: #{{.*}}main
diff --git a/lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc b/lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc
new file mode 100644
index 000000000000..7010eb2de2e7
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/malloc_delete_mismatch.cc
@@ -0,0 +1,31 @@
+// Check that we detect malloc/delete mismatch only if the approptiate flag
+// is set.
+
+// RUN: %clangxx_asan -g %s -o %t 2>&1
+
+// Find error and provide malloc context.
+// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1 not %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=ALLOC-STACK
+
+// No error here.
+// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=0 %t
+
+// Also works if no malloc context is available.
+// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1:malloc_context_size=0:fast_unwind_on_malloc=0 not %t 2>&1 | FileCheck %s
+// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1:malloc_context_size=0:fast_unwind_on_malloc=1 not %t 2>&1 | FileCheck %s
+#include <stdlib.h>
+
+static volatile char *x;
+
+int main() {
+ x = (char*)malloc(10);
+ x[0] = 0;
+ delete x;
+}
+// CHECK: ERROR: AddressSanitizer: alloc-dealloc-mismatch (malloc vs operator delete) on 0x
+// CHECK-NEXT: #0{{.*}}operator delete
+// CHECK: #{{.*}}main
+// CHECK: is located 0 bytes inside of 10-byte region
+// CHECK-NEXT: allocated by thread T0 here:
+// ALLOC-STACK-NEXT: #0{{.*}}malloc
+// ALLOC-STACK: #{{.*}}main
+// CHECK: HINT: {{.*}} you may set ASAN_OPTIONS=alloc_dealloc_mismatch=0
diff --git a/lib/asan/lit_tests/TestCases/Linux/overflow-in-qsort.cc b/lib/asan/lit_tests/TestCases/Linux/overflow-in-qsort.cc
new file mode 100644
index 000000000000..139977261ec9
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/overflow-in-qsort.cc
@@ -0,0 +1,51 @@
+// RUN: %clangxx_asan -O2 %s -o %t
+// RUN: ASAN_OPTIONS=fast_unwind_on_fatal=1 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-FAST
+// RUN: ASAN_OPTIONS=fast_unwind_on_fatal=0 not %t 2>&1 | FileCheck %s --check-prefix=CHECK-SLOW
+
+// Test how well we unwind in presence of qsort in the stack
+// (i.e. if we can unwind through a function compiled w/o frame pointers).
+// https://code.google.com/p/address-sanitizer/issues/detail?id=137
+
+// Fast unwinder is only avaliable on x86_64 and i386.
+// REQUIRES: x86_64-supported-target
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int global_array[10];
+volatile int one = 1;
+
+extern "C" {
+int QsortCallback(const void *a, const void *b) {
+ char *x = (char*)a;
+ char *y = (char*)b;
+ printf("Calling QsortCallback\n");
+ global_array[one * 10] = 0; // BOOM
+ return (int)*x - (int)*y;
+}
+
+__attribute__((noinline))
+void MyQsort(char *a, size_t size) {
+ printf("Calling qsort\n");
+ qsort(a, size, sizeof(char), QsortCallback);
+ printf("Done\n"); // Avoid tail call.
+}
+} // extern "C"
+
+int main() {
+ char a[2] = {1, 2};
+ MyQsort(a, 2);
+}
+
+// Fast unwind: can not unwind through qsort.
+
+// CHECK-FAST: ERROR: AddressSanitizer: global-buffer-overflow
+// CHECK-FAST: #0{{.*}} in QsortCallback
+// CHECK-FAST-NOT: MyQsort
+// CHECK-FAST: is located 0 bytes to the right of global variable 'global_array
+
+// CHECK-SLOW: ERROR: AddressSanitizer: global-buffer-overflow
+// CHECK-SLOW: #0{{.*}} in QsortCallback
+// CHECK-SLOW: #{{.*}} in MyQsort
+// CHECK-SLOW: #{{.*}} in main
+// CHECK-SLOW: is located 0 bytes to the right of global variable 'global_array
diff --git a/lib/asan/lit_tests/TestCases/Linux/preinit_test.cc b/lib/asan/lit_tests/TestCases/Linux/preinit_test.cc
new file mode 100644
index 000000000000..28e509472c0c
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/preinit_test.cc
@@ -0,0 +1,27 @@
+// RUN: %clangxx -DFUNC=zzzz %s -shared -o %t.so -fPIC
+// RUN: %clangxx_asan -DFUNC=main %s -o %t -Wl,-R. %t.so
+// RUN: %t
+
+// This test ensures that we call __asan_init early enough.
+// We build a shared library w/o asan instrumentation
+// and the binary with asan instrumentation.
+// Both files include the same header (emulated by -DFUNC here)
+// with C++ template magic which runs global initializer at library load time.
+// The function get() is instrumented with asan, but called
+// before the usual constructors are run.
+// So, we must make sure that __asan_init is executed even earlier.
+//
+// See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=56393
+
+struct A {
+ int foo() const { return 0; }
+};
+A get () { return A(); }
+template <class> struct O {
+ static A const e;
+};
+template <class T> A const O <T>::e = get();
+int FUNC() {
+ return O<int>::e.foo();
+}
+
diff --git a/lib/asan/lit_tests/TestCases/Linux/ptrace.cc b/lib/asan/lit_tests/TestCases/Linux/ptrace.cc
new file mode 100644
index 000000000000..8831b81efa96
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/ptrace.cc
@@ -0,0 +1,52 @@
+// RUN: %clangxx_asan -O0 %s -o %t && %t
+// RUN: %clangxx_asan -DPOSITIVE -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <stdio.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/user.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+int main(void) {
+ pid_t pid;
+ pid = fork();
+ if (pid == 0) { // child
+ ptrace(PTRACE_TRACEME, 0, NULL, NULL);
+ execl("/bin/true", "true", NULL);
+ } else {
+ wait(NULL);
+ user_regs_struct regs;
+ int res;
+ user_regs_struct * volatile pregs = &regs;
+#ifdef POSITIVE
+ ++pregs;
+#endif
+ res = ptrace(PTRACE_GETREGS, pid, NULL, pregs);
+ // CHECK: AddressSanitizer: stack-buffer-overflow
+ // CHECK: {{.*ptrace.cc:}}[[@LINE-2]]
+ assert(!res);
+#if __WORDSIZE == 64
+ printf("%zx\n", regs.rip);
+#else
+ printf("%lx\n", regs.eip);
+#endif
+
+ user_fpregs_struct fpregs;
+ res = ptrace(PTRACE_GETFPREGS, pid, NULL, &fpregs);
+ assert(!res);
+ printf("%lx\n", (unsigned long)fpregs.cwd);
+
+#if __WORDSIZE == 32
+ user_fpxregs_struct fpxregs;
+ res = ptrace(PTRACE_GETFPXREGS, pid, NULL, &fpxregs);
+ assert(!res);
+ printf("%lx\n", (unsigned long)fpxregs.mxcsr);
+#endif
+
+ ptrace(PTRACE_CONT, pid, NULL, NULL);
+ wait(NULL);
+ }
+ return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/rlimit_mmap_test.cc b/lib/asan/lit_tests/TestCases/Linux/rlimit_mmap_test.cc
new file mode 100644
index 000000000000..0d1d4baa7671
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/rlimit_mmap_test.cc
@@ -0,0 +1,16 @@
+// Check that we properly report mmap failure.
+// RUN: %clangxx_asan %s -o %t && not %t 2>&1 | FileCheck %s
+#include <stdlib.h>
+#include <assert.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+static volatile void *x;
+
+int main(int argc, char **argv) {
+ struct rlimit mmap_resource_limit = { 0, 0 };
+ assert(0 == setrlimit(RLIMIT_AS, &mmap_resource_limit));
+ x = malloc(10000000);
+// CHECK: ERROR: Failed to mmap
+ return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/swapcontext_test.cc b/lib/asan/lit_tests/TestCases/Linux/swapcontext_test.cc
new file mode 100644
index 000000000000..6cbb69a35321
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/swapcontext_test.cc
@@ -0,0 +1,90 @@
+// Check that ASan plays well with easy cases of makecontext/swapcontext.
+
+// RUN: %clangxx_asan -O0 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 %s -o %t && %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && %t 2>&1 | FileCheck %s
+//
+// This test is too sublte to try on non-x86 arch for now.
+// REQUIRES: x86_64-supported-target,i386-supported-target
+
+#include <stdio.h>
+#include <ucontext.h>
+#include <unistd.h>
+
+ucontext_t orig_context;
+ucontext_t child_context;
+
+const int kStackSize = 1 << 20;
+
+__attribute__((noinline))
+void Throw() {
+ throw 1;
+}
+
+__attribute__((noinline))
+void ThrowAndCatch() {
+ try {
+ Throw();
+ } catch(int a) {
+ printf("ThrowAndCatch: %d\n", a);
+ }
+}
+
+void Child(int mode) {
+ char x[32] = {0}; // Stack gets poisoned.
+ printf("Child: %p\n", x);
+ ThrowAndCatch(); // Simulate __asan_handle_no_return().
+ // (a) Do nothing, just return to parent function.
+ // (b) Jump into the original function. Stack remains poisoned unless we do
+ // something.
+ if (mode == 1) {
+ if (swapcontext(&child_context, &orig_context) < 0) {
+ perror("swapcontext");
+ _exit(0);
+ }
+ }
+}
+
+int Run(int arg, int mode, char *child_stack) {
+ printf("Child stack: %p\n", child_stack);
+ // Setup child context.
+ getcontext(&child_context);
+ child_context.uc_stack.ss_sp = child_stack;
+ child_context.uc_stack.ss_size = kStackSize / 2;
+ if (mode == 0) {
+ child_context.uc_link = &orig_context;
+ }
+ makecontext(&child_context, (void (*)())Child, 1, mode);
+ if (swapcontext(&orig_context, &child_context) < 0) {
+ perror("swapcontext");
+ return 0;
+ }
+ // Touch childs's stack to make sure it's unpoisoned.
+ for (int i = 0; i < kStackSize; i++) {
+ child_stack[i] = i;
+ }
+ return child_stack[arg];
+}
+
+int main(int argc, char **argv) {
+ char stack[kStackSize + 1];
+ // CHECK: WARNING: ASan doesn't fully support makecontext/swapcontext
+ int ret = 0;
+ ret += Run(argc - 1, 0, stack);
+ printf("Test1 passed\n");
+ // CHECK: Test1 passed
+ ret += Run(argc - 1, 1, stack);
+ printf("Test2 passed\n");
+ // CHECK: Test2 passed
+ char *heap = new char[kStackSize + 1];
+ ret += Run(argc - 1, 0, heap);
+ printf("Test3 passed\n");
+ // CHECK: Test3 passed
+ ret += Run(argc - 1, 1, heap);
+ printf("Test4 passed\n");
+ // CHECK: Test4 passed
+
+ delete [] heap;
+ return ret;
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/syscalls.cc b/lib/asan/lit_tests/TestCases/Linux/syscalls.cc
new file mode 100644
index 000000000000..4bcbe446113e
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/syscalls.cc
@@ -0,0 +1,22 @@
+// RUN: %clangxx_asan -O0 %s -o %t && not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O3 %s -o %t && not %t 2>&1 | FileCheck %s
+
+#include <assert.h>
+#include <errno.h>
+#include <glob.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <sanitizer/linux_syscall_hooks.h>
+
+/* Test the presence of __sanitizer_syscall_ in the tool runtime, and general
+ sanity of their behaviour. */
+
+int main(int argc, char *argv[]) {
+ char buf[1000];
+ __sanitizer_syscall_pre_recvmsg(0, buf - 1, 0);
+ // CHECK: AddressSanitizer: stack-buffer-{{.*}}erflow
+ // CHECK: READ of size {{.*}} at {{.*}} thread T0
+ // CHECK: #0 {{.*}} in __sanitizer_syscall{{.*}}recvmsg
+ return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/time_null_regtest.cc b/lib/asan/lit_tests/TestCases/Linux/time_null_regtest.cc
new file mode 100644
index 000000000000..566409be6a19
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/time_null_regtest.cc
@@ -0,0 +1,20 @@
+// RUN: %clangxx_asan -O0 %s -fsanitize-address-zero-base-shadow -pie -o %t && %t 2>&1 | FileCheck %s
+
+// Zero-base shadow only works on x86_64 and i386.
+// REQUIRES: x86_64-supported-target
+
+// A regression test for time(NULL), which caused ASan to crash in the
+// zero-based shadow mode on Linux.
+// FIXME: this test does not work on Darwin, because the code pages of the
+// executable interleave with the zero-based shadow.
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <time.h>
+
+int main() {
+ time_t t = time(NULL);
+ fprintf(stderr, "Time: %s\n", ctime(&t)); // NOLINT
+ // CHECK: {{Time: .* .* .*}}
+ return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/tsd_dtor_leak.cc b/lib/asan/lit_tests/TestCases/Linux/tsd_dtor_leak.cc
new file mode 100644
index 000000000000..a1d89ee437d4
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/tsd_dtor_leak.cc
@@ -0,0 +1,39 @@
+// Regression test for a leak in tsd:
+// https://code.google.com/p/address-sanitizer/issues/detail?id=233
+// RUN: %clangxx_asan -O1 %s -o %t
+// RUN: ASAN_OPTIONS=quarantine_size=1 %t
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+
+extern "C" size_t __asan_get_heap_size();
+static pthread_key_t tsd_key;
+
+void *Thread(void *) {
+ pthread_setspecific(tsd_key, malloc(10));
+ return 0;
+}
+
+static volatile void *v;
+
+void Dtor(void *tsd) {
+ v = malloc(10000);
+ free(tsd);
+ free((void*)v); // The bug was that this was leaking.
+}
+
+int main() {
+ assert(0 == pthread_key_create(&tsd_key, Dtor));
+ size_t old_heap_size = 0;
+ for (int i = 0; i < 10; i++) {
+ pthread_t t;
+ pthread_create(&t, 0, Thread, 0);
+ pthread_join(t, 0);
+ size_t new_heap_size = __asan_get_heap_size();
+ fprintf(stderr, "heap size: new: %zd old: %zd\n", new_heap_size, old_heap_size);
+ if (old_heap_size)
+ assert(old_heap_size == new_heap_size);
+ old_heap_size = new_heap_size;
+ }
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/uar_signals.cc b/lib/asan/lit_tests/TestCases/Linux/uar_signals.cc
new file mode 100644
index 000000000000..9663859dfefd
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/uar_signals.cc
@@ -0,0 +1,70 @@
+// This test shows that the current implementation of use-after-return is
+// not signal-safe.
+// RUN: %clangxx_asan -O1 %s -o %t -lpthread && %t
+// RUN: %clangxx_asan -O1 %s -o %t -lpthread && %t
+#include <signal.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <sys/time.h>
+#include <pthread.h>
+
+int *g;
+int n_signals;
+
+typedef void (*Sigaction)(int, siginfo_t *, void *);
+
+void SignalHandler(int, siginfo_t*, void*) {
+ int local;
+ g = &local;
+ n_signals++;
+ // printf("s: %p\n", &local);
+}
+
+static void EnableSigprof(Sigaction SignalHandler) {
+ struct sigaction sa;
+ sa.sa_sigaction = SignalHandler;
+ sa.sa_flags = SA_RESTART | SA_SIGINFO;
+ sigemptyset(&sa.sa_mask);
+ if (sigaction(SIGPROF, &sa, NULL) != 0) {
+ perror("sigaction");
+ abort();
+ }
+ struct itimerval timer;
+ timer.it_interval.tv_sec = 0;
+ timer.it_interval.tv_usec = 1;
+ timer.it_value = timer.it_interval;
+ if (setitimer(ITIMER_PROF, &timer, 0) != 0) {
+ perror("setitimer");
+ abort();
+ }
+}
+
+void RecursiveFunction(int depth) {
+ if (depth == 0) return;
+ int local;
+ g = &local;
+ // printf("r: %p\n", &local);
+ // printf("[%2d] n_signals: %d\n", depth, n_signals);
+ RecursiveFunction(depth - 1);
+ RecursiveFunction(depth - 1);
+}
+
+void *Thread(void *) {
+ RecursiveFunction(18);
+ return NULL;
+}
+
+int main(int argc, char **argv) {
+ EnableSigprof(SignalHandler);
+
+ for (int i = 0; i < 4; i++) {
+ fprintf(stderr, ".");
+ const int kNumThread = sizeof(void*) == 8 ? 16 : 8;
+ pthread_t t[kNumThread];
+ for (int i = 0; i < kNumThread; i++)
+ pthread_create(&t[i], 0, Thread, 0);
+ for (int i = 0; i < kNumThread; i++)
+ pthread_join(t[i], 0);
+ }
+ fprintf(stderr, "\n");
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/unpoison_tls.cc b/lib/asan/lit_tests/TestCases/Linux/unpoison_tls.cc
new file mode 100644
index 000000000000..d67c4f954e43
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/unpoison_tls.cc
@@ -0,0 +1,35 @@
+// Test that TLS is unpoisoned on thread death.
+// REQUIRES: x86_64-supported-target,i386-supported-target
+
+// RUN: %clangxx_asan -O1 %s -o %t && %t 2>&1
+
+#include <assert.h>
+#include <pthread.h>
+#include <stdio.h>
+
+#include <sanitizer/asan_interface.h>
+
+__thread int64_t tls_var[2];
+
+volatile int64_t *p_tls_var;
+
+void *first(void *arg) {
+ ASAN_POISON_MEMORY_REGION(&tls_var, sizeof(tls_var));
+ p_tls_var = tls_var;
+ return 0;
+}
+
+void *second(void *arg) {
+ assert(tls_var == p_tls_var);
+ *p_tls_var = 1;
+ return 0;
+}
+
+int main(int argc, char *argv[]) {
+ pthread_t p;
+ assert(0 == pthread_create(&p, 0, first, 0));
+ assert(0 == pthread_join(p, 0));
+ assert(0 == pthread_create(&p, 0, second, 0));
+ assert(0 == pthread_join(p, 0));
+ return 0;
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow32.cc b/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow32.cc
new file mode 100644
index 000000000000..e6bcc5597471
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow32.cc
@@ -0,0 +1,24 @@
+// RUN: %clangxx_asan -O0 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
+// RUN: not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
+// RUN: not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
+// RUN: not %t 2>&1 | FileCheck %s
+
+// Zero-base shadow only works on x86_64 and i386.
+// REQUIRES: i386-supported-target, asan-32-bits
+
+#include <string.h>
+int main(int argc, char **argv) {
+ char x[10];
+ memset(x, 0, 10);
+ int res = x[argc * 10]; // BOOOM
+ // CHECK: {{READ of size 1 at 0x.* thread T0}}
+ // CHECK: {{ #0 0x.* in main .*zero-base-shadow32.cc:}}[[@LINE-2]]
+ // CHECK: {{Address 0x.* is .* frame}}
+ // CHECK: main
+
+ // Check that shadow for stack memory occupies lower part of address space.
+ // CHECK: =>0x1
+ return res;
+}
diff --git a/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow64.cc b/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow64.cc
new file mode 100644
index 000000000000..1db725c95752
--- /dev/null
+++ b/lib/asan/lit_tests/TestCases/Linux/zero-base-shadow64.cc
@@ -0,0 +1,24 @@
+// RUN: %clangxx_asan -O0 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
+// RUN: not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O1 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
+// RUN: not %t 2>&1 | FileCheck %s
+// RUN: %clangxx_asan -O2 -fsanitize-address-zero-base-shadow -fPIE -pie %s -o %t
+// RUN: not %t 2>&1 | FileCheck %s
+
+// Zero-base shadow only works on x86_64 and i386.
+// REQUIRES: x86_64-supported-target, asan-64-bits
+
+#include <string.h>
+int main(int argc, char **argv) {
+ char x[10];
+ memset(x, 0, 10);
+ int res = x[argc * 10]; // BOOOM
+ // CHECK: {{READ of size 1 at 0x.* thread T0}}
+ // CHECK: {{ #0 0x.* in main .*zero-base-shadow64.cc:}}[[@LINE-2]]
+ // CHECK: {{Address 0x.* is .* frame}}
+ // CHECK: main
+
+ // Check that shadow for stack memory occupies lower part of address space.
+ // CHECK: =>0x0f
+ return res;
+}