diff options
| author | Dimitry Andric <dim@FreeBSD.org> | 2015-01-07 19:55:37 +0000 |
|---|---|---|
| committer | Dimitry Andric <dim@FreeBSD.org> | 2015-01-07 19:55:37 +0000 |
| commit | ca9211ecdede9bdedb812b2243a4abdb8dacd1b9 (patch) | |
| tree | 9b19e801150082c33e9152275829a6ce90614b55 /test/asan/TestCases/Linux | |
| parent | 8ef50bf3d1c287b5013c3168de77a462dfce3495 (diff) | |
Notes
Diffstat (limited to 'test/asan/TestCases/Linux')
49 files changed, 1962 insertions, 0 deletions
diff --git a/test/asan/TestCases/Linux/asan-asm-stacktrace-test.cc b/test/asan/TestCases/Linux/asan-asm-stacktrace-test.cc new file mode 100644 index 000000000000..5332c992a0db --- /dev/null +++ b/test/asan/TestCases/Linux/asan-asm-stacktrace-test.cc @@ -0,0 +1,33 @@ +// Check that a stack unwinding algorithm works corretly even with the assembly +// instrumentation. + +// REQUIRES: x86_64-supported-target +// RUN: %clangxx_asan -g -O1 %s -fno-inline-functions -fno-omit-frame-pointer -mno-omit-leaf-frame-pointer -mllvm -asan-instrument-assembly -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -g -O1 %s -fno-inline-functions -fomit-frame-pointer -momit-leaf-frame-pointer -mllvm -asan-instrument-assembly -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -g0 -O1 %s -fno-unwind-tables -fno-asynchronous-unwind-tables -fno-exceptions -fno-inline-functions -fomit-frame-pointer -momit-leaf-frame-pointer -mllvm -asan-instrument-assembly -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-nounwind + +#include <cstddef> + +// CHECK: READ of size 4 +// CHECK-NEXT: {{#0 0x[0-9a-fA-F]+ in foo}} +// CHECK-NEXT: {{#1 0x[0-9a-fA-F]+ in main}} + +// CHECK-nounwind: READ of size 4 +// CHECK-nounwind-NEXT: {{#0 0x[0-9a-fA-F]+ in foo}} + +__attribute__((noinline)) int foo(size_t n, int *buffer) { + int r; + __asm__("movl (%[buffer], %[n], 4), %[r] \n\t" + : [r] "=r"(r) + : [buffer] "r"(buffer), [n] "r"(n) + : "memory"); + return r; +} + +int main() { + const size_t n = 16; + int *buffer = new int[n]; + foo(n, buffer); + delete[] buffer; + return 0; +} diff --git a/test/asan/TestCases/Linux/asan_dlopen_test.cc b/test/asan/TestCases/Linux/asan_dlopen_test.cc new file mode 100644 index 000000000000..f1e31b0a0553 --- /dev/null +++ b/test/asan/TestCases/Linux/asan_dlopen_test.cc @@ -0,0 +1,15 @@ +// Test that dlopen of dynamic runtime is prohibited. +// +// RUN: %clangxx %s -DRT=\"%shared_libasan\" -o %t -ldl +// RUN: not %run %t 2>&1 | FileCheck %s +// REQUIRES: asan-dynamic-runtime +// XFAIL: android + +#include <dlfcn.h> + +int main(int argc, char **argv) { + dlopen(RT, RTLD_LAZY); + return 0; +} + +// CHECK: ASan runtime does not come first in initial library list diff --git a/test/asan/TestCases/Linux/asan_prelink_test.cc b/test/asan/TestCases/Linux/asan_prelink_test.cc new file mode 100644 index 000000000000..6145c01f7342 --- /dev/null +++ b/test/asan/TestCases/Linux/asan_prelink_test.cc @@ -0,0 +1,29 @@ +// 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 %run %t 2>&1 | FileCheck %s + +// GNU driver doesn't handle .so files properly. +// REQUIRES: x86_64-supported-target, asan-64-bits, Clang +#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/test/asan/TestCases/Linux/asan_preload_test-1.cc b/test/asan/TestCases/Linux/asan_preload_test-1.cc new file mode 100644 index 000000000000..e5eab5545b83 --- /dev/null +++ b/test/asan/TestCases/Linux/asan_preload_test-1.cc @@ -0,0 +1,30 @@ +// Test that non-sanitized executables work with sanitized shared libs +// and preloaded runtime. +// +// RUN: %clangxx -DBUILD_SO=1 -fPIC -shared %s -o %t.so +// RUN: %clangxx %s %t.so -o %t +// +// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t.so +// RUN: LD_PRELOAD=%shared_libasan not %run %t 2>&1 | FileCheck %s + +// REQUIRES: asan-dynamic-runtime + +// This way of setting LD_PRELOAD does not work with Android test runner. +// REQUIRES: not-android + +#if BUILD_SO +char dummy; +void do_access(const void *p) { + // CHECK: AddressSanitizer: heap-buffer-overflow + dummy = ((const char *)p)[1]; +} +#else +#include <stdlib.h> +extern void do_access(const void *p); +int main(int argc, char **argv) { + void *p = malloc(1); + do_access(p); + free(p); + return 0; +} +#endif diff --git a/test/asan/TestCases/Linux/asan_preload_test-2.cc b/test/asan/TestCases/Linux/asan_preload_test-2.cc new file mode 100644 index 000000000000..00b32e15d17d --- /dev/null +++ b/test/asan/TestCases/Linux/asan_preload_test-2.cc @@ -0,0 +1,24 @@ +// Test that preloaded runtime works with unsanitized executables. +// +// RUN: %clangxx %s -o %t +// RUN: LD_PRELOAD=%shared_libasan not %run %t 2>&1 | FileCheck %s + +// REQUIRES: asan-dynamic-runtime + +// This way of setting LD_PRELOAD does not work with Android test runner. +// REQUIRES: not-android + +#include <stdlib.h> + +extern "C" void *memset(void *p, int val, size_t n); + +void do_access(void *p) { + // CHECK: AddressSanitizer: heap-buffer-overflow + memset(p, 0, 2); +} + +int main(int argc, char **argv) { + void *p = malloc(1); + do_access(p); + return 0; +} diff --git a/test/asan/TestCases/Linux/asan_rt_confict_test-1.cc b/test/asan/TestCases/Linux/asan_rt_confict_test-1.cc new file mode 100644 index 000000000000..30f1c17700c8 --- /dev/null +++ b/test/asan/TestCases/Linux/asan_rt_confict_test-1.cc @@ -0,0 +1,13 @@ +// Test that preloading dynamic runtime to statically sanitized +// executable is prohibited. +// +// RUN: %clangxx_asan_static %s -o %t +// RUN: LD_PRELOAD=%shared_libasan not %run %t 2>&1 | FileCheck %s + +// REQUIRES: asan-dynamic-runtime +// XFAIL: android + +#include <stdlib.h> +int main(int argc, char **argv) { return 0; } + +// CHECK: Your application is linked against incompatible ASan runtimes diff --git a/test/asan/TestCases/Linux/asan_rt_confict_test-2.cc b/test/asan/TestCases/Linux/asan_rt_confict_test-2.cc new file mode 100644 index 000000000000..4c935e2b0f3b --- /dev/null +++ b/test/asan/TestCases/Linux/asan_rt_confict_test-2.cc @@ -0,0 +1,25 @@ +// Test that mixed static/dynamic sanitization of program objects +// is prohibited. +// +// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t.so +// RUN: %clangxx_asan_static %s %t.so -o %t +// RUN: not %run %t 2>&1 | FileCheck %s + +// REQUIRES: asan-dynamic-runtime +// XFAIL: android + +#if BUILD_SO +char dummy; +void do_access(const void *p) { dummy = ((const char *)p)[1]; } +#else +#include <stdlib.h> +extern void do_access(const void *p); +int main(int argc, char **argv) { + void *p = malloc(1); + do_access(p); + free(p); + return 0; +} +#endif + +// CHECK: Your application is linked against incompatible ASan runtimes diff --git a/test/asan/TestCases/Linux/clang_gcc_abi.cc b/test/asan/TestCases/Linux/clang_gcc_abi.cc new file mode 100644 index 000000000000..e833881661d2 --- /dev/null +++ b/test/asan/TestCases/Linux/clang_gcc_abi.cc @@ -0,0 +1,44 @@ +// RUN: %clangxx_asan -O0 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s + +// REQUIRES: arm-supported-target +// XFAIL: armv7l-unknown-linux-gnueabihf + +#include <stdlib.h> + +int boom() { + volatile int three = 3; + char *s = (char *)malloc(three); +// CHECK: #1 0x{{.*}} in boom {{.*}}clang_gcc_abi.cc:[[@LINE-1]] + return s[three]; //BOOM +} + +__attribute__((naked, noinline)) void gcc_abi() { +// CHECK: #2 0x{{.*}} in gcc_abi {{.*}}clang_gcc_abi.cc:[[@LINE+1]] + asm volatile("str fp, [sp, #-8]!\n\t" + "str lr, [sp, #4]\n\t" + "add fp, sp, #4\n\t" + "bl boom\n\t" + "sub sp, fp, #4\n\t" + "ldr fp, [sp]\n\t" + "add sp, sp, #4\n\t" + "ldr pc, [sp], #4\n\t" + ); +} + +__attribute__((naked, noinline)) void clang_abi() { +// CHECK: #3 0x{{.*}} in clang_abi {{.*}}clang_gcc_abi.cc:[[@LINE+1]] + asm volatile("push {r11, lr}\n\t" + "mov r11, sp\n\t" + "bl gcc_abi\n\t" + "add r0, r0, #1\n\t" + "pop {r11, pc}\n\t" + ); +} + +int main() { + clang_abi(); +// CHECK: #4 0x{{.*}} in main {{.*}}clang_gcc_abi.cc:[[@LINE-1]] +} diff --git a/test/asan/TestCases/Linux/clone_test.cc b/test/asan/TestCases/Linux/clone_test.cc new file mode 100644 index 000000000000..e9c1f166eb45 --- /dev/null +++ b/test/asan/TestCases/Linux/clone_test.cc @@ -0,0 +1,45 @@ +// Regression test for: +// http://code.google.com/p/address-sanitizer/issues/detail?id=37 + +// RUN: %clangxx_asan -O0 %s -o %t && %run %t | FileCheck %s +// RUN: %clangxx_asan -O1 %s -o %t && %run %t | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t && %run %t | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && %run %t | FileCheck %s +// XFAIL: arm-linux-gnueabi + +#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); + 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/test/asan/TestCases/Linux/coverage-and-lsan.cc b/test/asan/TestCases/Linux/coverage-and-lsan.cc new file mode 100644 index 000000000000..4cb8e2af3084 --- /dev/null +++ b/test/asan/TestCases/Linux/coverage-and-lsan.cc @@ -0,0 +1,20 @@ +// Make sure coverage is dumped even if there are reported leaks. +// +// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t +// +// RUN: rm -rf %T/coverage-and-lsan +// +// RUN: mkdir -p %T/coverage-and-lsan/normal +// RUN: ASAN_OPTIONS=coverage=1:coverage_dir=%T/coverage-and-lsan:verbosity=1 not %run %t 2>&1 | FileCheck %s +// RUN: %sancov print %T/coverage-and-lsan/*.sancov 2>&1 +// +// REQUIRES: leak-detection + +int *g = new int; +int main(int argc, char **argv) { + g = 0; + return 0; +} + +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: CovDump: diff --git a/test/asan/TestCases/Linux/coverage-caller-callee-total-count.cc b/test/asan/TestCases/Linux/coverage-caller-callee-total-count.cc new file mode 100644 index 000000000000..0201425106f9 --- /dev/null +++ b/test/asan/TestCases/Linux/coverage-caller-callee-total-count.cc @@ -0,0 +1,41 @@ +// Test __sanitizer_get_total_unique_coverage for caller-callee coverage + +// RUN: %clangxx_asan -fsanitize-coverage=4 %s -o %t +// RUN: ASAN_OPTIONS=coverage=1 %run %t +// RUN: rm -f caller-callee*.sancov +// +// REQUIRES: asan-64-bits + +#include <sanitizer/common_interface_defs.h> +#include <stdio.h> +#include <assert.h> +int P = 0; +struct Foo {virtual void f() {if (P) printf("Foo::f()\n");}}; +struct Foo1 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; +struct Foo2 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; + +Foo *foo[3] = {new Foo, new Foo1, new Foo2}; + +uintptr_t CheckNewTotalUniqueCoverageIsLargerAndReturnIt(uintptr_t old_total) { + uintptr_t new_total = __sanitizer_get_total_unique_coverage(); + assert(new_total > old_total); + return new_total; +} + +int main(int argc, char **argv) { + uintptr_t total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(0); + foo[0]->f(); + total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total); + foo[1]->f(); + total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total); + foo[2]->f(); + total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total); + // Ok, called every function once. + // Now call them again from another call site. Should get new coverage. + foo[0]->f(); + total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total); + foo[1]->f(); + total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total); + foo[2]->f(); + total = CheckNewTotalUniqueCoverageIsLargerAndReturnIt(total); +} diff --git a/test/asan/TestCases/Linux/coverage-caller-callee.cc b/test/asan/TestCases/Linux/coverage-caller-callee.cc new file mode 100644 index 000000000000..cd318962b8e0 --- /dev/null +++ b/test/asan/TestCases/Linux/coverage-caller-callee.cc @@ -0,0 +1,74 @@ +// Test caller-callee coverage with large number of threads +// and various numbers of callers and callees. + +// RUN: %clangxx_asan -fsanitize-coverage=4 %s -o %t +// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 10 1 2>&1 | FileCheck %s --check-prefix=CHECK-10-1 +// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 9 2 2>&1 | FileCheck %s --check-prefix=CHECK-9-2 +// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 7 3 2>&1 | FileCheck %s --check-prefix=CHECK-7-3 +// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 17 1 2>&1 | FileCheck %s --check-prefix=CHECK-17-1 +// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 15 2 2>&1 | FileCheck %s --check-prefix=CHECK-15-2 +// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 18 3 2>&1 | FileCheck %s --check-prefix=CHECK-18-3 +// RUN: rm -f caller-callee*.sancov +// +// REQUIRES: asan-64-bits +// +// CHECK-10-1: CovDump: 10 caller-callee pairs written +// CHECK-9-2: CovDump: 18 caller-callee pairs written +// CHECK-7-3: CovDump: 21 caller-callee pairs written +// CHECK-17-1: CovDump: 14 caller-callee pairs written +// CHECK-15-2: CovDump: 28 caller-callee pairs written +// CHECK-18-3: CovDump: 42 caller-callee pairs written + +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> +int P = 0; +struct Foo {virtual void f() {if (P) printf("Foo::f()\n");}}; +struct Foo1 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; +struct Foo2 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; +struct Foo3 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; +struct Foo4 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; +struct Foo5 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; +struct Foo6 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; +struct Foo7 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; +struct Foo8 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; +struct Foo9 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; +struct Foo10 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; +struct Foo11 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; +struct Foo12 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; +struct Foo13 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; +struct Foo14 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; +struct Foo15 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; +struct Foo16 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; +struct Foo17 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; +struct Foo18 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; +struct Foo19 : Foo {virtual void f() {if (P) printf("%d\n", __LINE__);}}; + +Foo *foo[20] = { + new Foo, new Foo1, new Foo2, new Foo3, new Foo4, new Foo5, new Foo6, + new Foo7, new Foo8, new Foo9, new Foo10, new Foo11, new Foo12, new Foo13, + new Foo14, new Foo15, new Foo16, new Foo17, new Foo18, new Foo19, +}; + +int n_functions = 10; +int n_callers = 2; + +void *Thread(void *arg) { + if (n_callers >= 1) for (int i = 0; i < 2000; i++) foo[i % n_functions]->f(); + if (n_callers >= 2) for (int i = 0; i < 2000; i++) foo[i % n_functions]->f(); + if (n_callers >= 3) for (int i = 0; i < 2000; i++) foo[i % n_functions]->f(); + return arg; +} + +int main(int argc, char **argv) { + if (argc >= 2) + n_functions = atoi(argv[1]); + if (argc >= 3) + n_callers = atoi(argv[2]); + const int kNumThreads = 16; + pthread_t t[kNumThreads]; + for (int i = 0; i < kNumThreads; i++) + pthread_create(&t[i], 0, Thread, 0); + for (int i = 0; i < kNumThreads; i++) + pthread_join(t[i], 0); +} diff --git a/test/asan/TestCases/Linux/coverage-direct-large.cc b/test/asan/TestCases/Linux/coverage-direct-large.cc new file mode 100644 index 000000000000..78aa68621ad1 --- /dev/null +++ b/test/asan/TestCases/Linux/coverage-direct-large.cc @@ -0,0 +1,45 @@ +// Test for direct coverage writing with lots of data. +// Current implementation maps output file in chunks of 64K. This test overflows +// 1 chunk. +// RUN: %clangxx_asan -fsanitize-coverage=1 -O0 %s -o %t + +// RUN: rm -rf %T/coverage-direct-large + +// RUN: mkdir -p %T/coverage-direct-large/normal && cd %T/coverage-direct-large/normal +// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=0:verbosity=1 %run %t +// RUN: %sancov print *.sancov >out.txt +// RUN: cd ../.. + +// RUN: mkdir -p %T/coverage-direct-large/direct && cd %T/coverage-direct-large/direct +// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=1:verbosity=1 %run %t +// RUN: %sancov rawunpack *.sancov.raw +// RUN: %sancov print *.sancov >out.txt +// RUN: cd ../.. + +// RUN: diff -u coverage-direct-large/normal/out.txt coverage-direct-large/direct/out.txt +// +// XFAIL: android + +#define F0(Q, x) Q(x) +#define F1(Q, x) \ + F0(Q, x##0) F0(Q, x##1) F0(Q, x##2) F0(Q, x##3) F0(Q, x##4) F0(Q, x##5) \ + F0(Q, x##6) F0(Q, x##7) F0(Q, x##8) F0(Q, x##9) +#define F2(Q, x) \ + F1(Q, x##0) F1(Q, x##1) F1(Q, x##2) F1(Q, x##3) F1(Q, x##4) F1(Q, x##5) \ + F1(Q, x##6) F1(Q, x##7) F1(Q, x##8) F1(Q, x##9) +#define F3(Q, x) \ + F2(Q, x##0) F2(Q, x##1) F2(Q, x##2) F2(Q, x##3) F2(Q, x##4) F2(Q, x##5) \ + F2(Q, x##6) F2(Q, x##7) F2(Q, x##8) F2(Q, x##9) +#define F4(Q, x) \ + F3(Q, x##0) F3(Q, x##1) F3(Q, x##2) F3(Q, x##3) F3(Q, x##4) F3(Q, x##5) \ + F3(Q, x##6) F3(Q, x##7) F3(Q, x##8) F3(Q, x##9) + +#define DECL(x) __attribute__((noinline)) void x() {} +#define CALL(x) x(); + +F4(DECL, f) + +int main(void) { + F4(CALL, f) + return 0; +} diff --git a/test/asan/TestCases/Linux/coverage-direct.cc b/test/asan/TestCases/Linux/coverage-direct.cc new file mode 100644 index 000000000000..2cc1aed0a0fa --- /dev/null +++ b/test/asan/TestCases/Linux/coverage-direct.cc @@ -0,0 +1,44 @@ +// Test for direct coverage writing with dlopen. +// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %T/libcoverage_direct_test_1.so -fPIC +// RUN: %clangxx_asan -fsanitize-coverage=1 -DSO_DIR=\"%T\" %s -o %t + +// RUN: rm -rf %T/coverage-direct + +// RUN: mkdir -p %T/coverage-direct/normal +// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=0:coverage_dir=%T/coverage-direct/normal:verbosity=1 %run %t +// RUN: %sancov print %T/coverage-direct/normal/*.sancov >%T/coverage-direct/normal/out.txt + +// RUN: mkdir -p %T/coverage-direct/direct +// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=1:coverage_dir=%T/coverage-direct/direct:verbosity=1 %run %t +// RUN: cd %T/coverage-direct/direct +// RUN: %sancov rawunpack *.sancov.raw +// RUN: %sancov print *.sancov >out.txt +// RUN: cd ../.. + +// RUN: diff -u coverage-direct/normal/out.txt coverage-direct/direct/out.txt +// +// XFAIL: android + +#include <assert.h> +#include <dlfcn.h> +#include <stdio.h> +#include <unistd.h> + +#ifdef SHARED +extern "C" { +void bar() { printf("bar\n"); } +} +#else + +int main(int argc, char **argv) { + fprintf(stderr, "PID: %d\n", getpid()); + void *handle1 = + dlopen(SO_DIR "/libcoverage_direct_test_1.so", RTLD_LAZY); + assert(handle1); + void (*bar1)() = (void (*)())dlsym(handle1, "bar"); + assert(bar1); + bar1(); + + return 0; +} +#endif diff --git a/test/asan/TestCases/Linux/coverage-disabled.cc b/test/asan/TestCases/Linux/coverage-disabled.cc new file mode 100644 index 000000000000..a75b26dc02e9 --- /dev/null +++ b/test/asan/TestCases/Linux/coverage-disabled.cc @@ -0,0 +1,18 @@ +// Test that no data is collected without a runtime flag. +// +// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t +// +// RUN: rm -rf %T/coverage-disabled +// +// RUN: mkdir -p %T/coverage-disabled/normal +// RUN: ASAN_OPTIONS=coverage_direct=0:coverage_dir=%T/coverage-disabled/normal:verbosity=1 %run %t +// RUN: not %sancov print %T/coverage-disabled/normal/*.sancov 2>&1 +// +// RUN: mkdir -p %T/coverage-disabled/direct +// RUN: ASAN_OPTIONS=coverage_direct=1:coverage_dir=%T/coverage-disabled/direct:verbosity=1 %run %t +// RUN: cd %T/coverage-disabled/direct +// RUN: not %sancov rawunpack *.sancov + +int main(int argc, char **argv) { + return 0; +} diff --git a/test/asan/TestCases/Linux/coverage-fork-direct.cc b/test/asan/TestCases/Linux/coverage-fork-direct.cc new file mode 100644 index 000000000000..51cbbd821b8e --- /dev/null +++ b/test/asan/TestCases/Linux/coverage-fork-direct.cc @@ -0,0 +1,38 @@ +// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t +// RUN: rm -rf %T/coverage-fork-direct +// RUN: mkdir -p %T/coverage-fork-direct && cd %T/coverage-fork-direct +// RUN: (ASAN_OPTIONS=coverage=1:coverage_direct=1:verbosity=1 %run %t; \ +// RUN: %sancov rawunpack *.sancov.raw; %sancov print *.sancov) 2>&1 +// +// XFAIL: android + +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +__attribute__((noinline)) +void foo() { printf("foo\n"); } + +__attribute__((noinline)) +void bar() { printf("bar\n"); } + +__attribute__((noinline)) +void baz() { printf("baz\n"); } + +int main(int argc, char **argv) { + pid_t child_pid = fork(); + if (child_pid == 0) { + fprintf(stderr, "Child PID: %d\n", getpid()); + baz(); + } else { + fprintf(stderr, "Parent PID: %d\n", getpid()); + foo(); + bar(); + } + return 0; +} + +// CHECK-DAG: Child PID: [[ChildPID:[0-9]+]] +// CHECK-DAG: Parent PID: [[ParentPID:[0-9]+]] +// CHECK-DAG: read 3 PCs from {{.*}}.[[ParentPID]].sancov +// CHECK-DAG: read 1 PCs from {{.*}}.[[ChildPID]].sancov diff --git a/test/asan/TestCases/Linux/coverage-fork.cc b/test/asan/TestCases/Linux/coverage-fork.cc new file mode 100644 index 000000000000..38c200942609 --- /dev/null +++ b/test/asan/TestCases/Linux/coverage-fork.cc @@ -0,0 +1,38 @@ +// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t +// RUN: export ASAN_OPTIONS=coverage=1:coverage_direct=0:verbosity=1 +// RUN: rm -rf %T/coverage-fork +// RUN: mkdir -p %T/coverage-fork && cd %T/coverage-fork +// RUN: %run %t 2>&1 | FileCheck %s +// +// XFAIL: android + +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +__attribute__((noinline)) +void foo() { printf("foo\n"); } + +__attribute__((noinline)) +void bar() { printf("bar\n"); } + +__attribute__((noinline)) +void baz() { printf("baz\n"); } + +int main(int argc, char **argv) { + pid_t child_pid = fork(); + if (child_pid == 0) { + fprintf(stderr, "Child PID: %d\n", getpid()); + baz(); + } else { + fprintf(stderr, "Parent PID: %d\n", getpid()); + foo(); + bar(); + } + return 0; +} + +// CHECK-DAG: Child PID: [[ChildPID:[0-9]+]] +// CHECK-DAG: [[ChildPID]].sancov: 1 PCs written +// CHECK-DAG: Parent PID: [[ParentPID:[0-9]+]] +// CHECK-DAG: [[ParentPID]].sancov: 3 PCs written diff --git a/test/asan/TestCases/Linux/coverage-levels.cc b/test/asan/TestCases/Linux/coverage-levels.cc new file mode 100644 index 000000000000..748ef1f08db5 --- /dev/null +++ b/test/asan/TestCases/Linux/coverage-levels.cc @@ -0,0 +1,20 @@ +// Test various levels of coverage +// +// RUN: %clangxx_asan -O1 -fsanitize-coverage=1 %s -o %t +// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 +// RUN: %clangxx_asan -O1 -fsanitize-coverage=2 %s -o %t +// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 +// RUN: %clangxx_asan -O1 -fsanitize-coverage=3 %s -o %t +// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3 +// +// REQUIRES: asan-64-bits + +volatile int sink; +int main(int argc, char **argv) { + if (argc == 0) + sink = 0; +} + +// CHECK1: 1 PCs written +// CHECK2: 2 PCs written +// CHECK3: 3 PCs written diff --git a/test/asan/TestCases/Linux/coverage-maybe-open-file.cc b/test/asan/TestCases/Linux/coverage-maybe-open-file.cc new file mode 100644 index 000000000000..4664cef7f5af --- /dev/null +++ b/test/asan/TestCases/Linux/coverage-maybe-open-file.cc @@ -0,0 +1,31 @@ +// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316 +// XFAIL: android +// +// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t +// RUN: rm -rf %T/coverage-maybe-open-file +// RUN: mkdir -p %T/coverage-maybe-open-file && cd %T/coverage-maybe-open-file +// RUN: ASAN_OPTIONS=coverage=1 %run %t | FileCheck %s --check-prefix=CHECK-success +// RUN: ASAN_OPTIONS=coverage=0 %run %t | FileCheck %s --check-prefix=CHECK-fail +// RUN: [ "$(cat test.sancov.packed)" == "test" ] +// RUN: cd .. && rm -rf %T/coverage-maybe-open-file + +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include <sanitizer/common_interface_defs.h> + +int main(int argc, char **argv) { + int fd = __sanitizer_maybe_open_cov_file("test"); + if (fd > 0) { + printf("SUCCESS\n"); + const char s[] = "test\n"; + write(fd, s, strlen(s)); + close(fd); + } else { + printf("FAIL\n"); + } +} + +// CHECK-success: SUCCESS +// CHECK-fail: FAIL diff --git a/test/asan/TestCases/Linux/coverage-module-unloaded.cc b/test/asan/TestCases/Linux/coverage-module-unloaded.cc new file mode 100644 index 000000000000..449841e78189 --- /dev/null +++ b/test/asan/TestCases/Linux/coverage-module-unloaded.cc @@ -0,0 +1,56 @@ +// Check that unloading a module doesn't break coverage dumping for remaining +// modules. +// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %T/libcoverage_module_unloaded_test_1.so -fPIC +// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %T/libcoverage_module_unloaded_test_2.so -fPIC +// RUN: %clangxx_asan -fsanitize-coverage=1 -DSO_DIR=\"%T\" %s -o %t +// RUN: export ASAN_OPTIONS=coverage=1:verbosity=1 +// RUN: mkdir -p %T/coverage-module-unloaded && cd %T/coverage-module-unloaded +// RUN: %run %t 2>&1 | FileCheck %s +// RUN: %run %t foo 2>&1 | FileCheck %s +// RUN: cd .. && rm coverage-module-unloaded -r +// +// https://code.google.com/p/address-sanitizer/issues/detail?id=263 +// XFAIL: android + +#include <assert.h> +#include <dlfcn.h> +#include <stdio.h> +#include <unistd.h> + +#ifdef SHARED +extern "C" { +void bar() { printf("bar\n"); } +} +#else + +int main(int argc, char **argv) { + fprintf(stderr, "PID: %d\n", getpid()); + void *handle1 = + dlopen(SO_DIR "/libcoverage_module_unloaded_test_1.so", RTLD_LAZY); + assert(handle1); + void (*bar1)() = (void (*)())dlsym(handle1, "bar"); + assert(bar1); + bar1(); + void *handle2 = + dlopen(SO_DIR "/libcoverage_module_unloaded_test_2.so", RTLD_LAZY); + assert(handle2); + void (*bar2)() = (void (*)())dlsym(handle2, "bar"); + assert(bar2); + bar2(); + + // It matters whether the unloaded module has a higher or lower address range + // than the remaining one. Make sure to test both cases. + if (argc < 2) + dlclose(bar1 < bar2 ? handle1 : handle2); + else + dlclose(bar1 < bar2 ? handle2 : handle1); + return 0; +} +#endif + +// CHECK: PID: [[PID:[0-9]+]] +// CHECK: [[PID]].sancov: 1 PCs written +// CHECK: .so.[[PID]] +// If we get coverage for both DSOs, it means the module wasn't unloaded and +// this test is useless. +// CHECK-NOT: .so.[[PID]] diff --git a/test/asan/TestCases/Linux/coverage-sandboxing.cc b/test/asan/TestCases/Linux/coverage-sandboxing.cc new file mode 100644 index 000000000000..56f9c40f4cc0 --- /dev/null +++ b/test/asan/TestCases/Linux/coverage-sandboxing.cc @@ -0,0 +1,85 @@ +// RUN: %clangxx_asan -fsanitize-coverage=2 -DSHARED %s -shared -o %T/libcoverage_sandboxing_test.so -fPIC +// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t -Wl,-R,\$ORIGIN -L%T -lcoverage_sandboxing_test +// RUN: export ASAN_OPTIONS=coverage=1:verbosity=1 +// RUN: rm -rf %T/coverage_sandboxing_test +// RUN: mkdir %T/coverage_sandboxing_test && cd %T/coverage_sandboxing_test +// RUN: mkdir vanilla && cd vanilla +// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-vanilla +// RUN: mkdir ../sandbox1 && cd ../sandbox1 +// RUN: %run %t a 2>&1 | FileCheck %s --check-prefix=CHECK-sandbox +// RUN: %sancov unpack coverage_sandboxing_test.sancov.packed +// RUN: mkdir ../sandbox2 && cd ../sandbox2 +// RUN: %run %t a b 2>&1 | FileCheck %s --check-prefix=CHECK-sandbox +// RUN: %sancov unpack coverage_sandboxing_test.sancov.packed +// RUN: cd .. +// RUN: %sancov print vanilla/libcoverage_sandboxing_test.so.*.sancov > vanilla.txt +// RUN: %sancov print sandbox1/libcoverage_sandboxing_test.so.*.sancov > sandbox1.txt +// RUN: %sancov print sandbox2/libcoverage_sandboxing_test.so.*.sancov > sandbox2.txt +// RUN: diff vanilla.txt sandbox1.txt +// RUN: diff vanilla.txt sandbox2.txt +// RUN: cd ../ && rm coverage_sandboxing_test -r +// https://code.google.com/p/address-sanitizer/issues/detail?id=263 +// XFAIL: android + +#include <assert.h> +#include <fcntl.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include <sanitizer/common_interface_defs.h> + +#define bb0(n) \ + case n: \ + fprintf(stderr, "foo: %d\n", n); \ + break; + +#define bb1(n) bb0(n) bb0(n + 1) +#define bb2(n) bb1(n) bb1(n + 2) +#define bb3(n) bb2(n) bb2(n + 4) +#define bb4(n) bb3(n) bb3(n + 8) +#define bb5(n) bb4(n) bb4(n + 16) +#define bb6(n) bb5(n) bb5(n + 32) +#define bb7(n) bb6(n) bb6(n + 64) +#define bb8(n) bb7(n) bb7(n + 128) + +#ifdef SHARED +void foo(int i) { + switch(i) { + // 256 basic blocks + bb8(0) + } +} +#else +extern void foo(int i); + +int main(int argc, char **argv) { + assert(argc <= 3); + for (int i = 0; i < 256; i++) foo(i); + fprintf(stderr, "PID: %d\n", getpid()); + if (argc == 1) { + // Vanilla mode, dump to individual files. + return 0; + } + // Dump to packed file. + int fd = creat("coverage_sandboxing_test.sancov.packed", 0660); + __sanitizer_sandbox_arguments args = {0}; + args.coverage_sandboxed = 1; + args.coverage_fd = fd; + if (argc == 2) + // Write to packed file, do not split into blocks. + args.coverage_max_block_size = 0; + else if (argc == 3) + // Write to packed file, split into blocks (as if writing to a socket). + args.coverage_max_block_size = 100; + __sanitizer_sandbox_on_notify(&args); + return 0; +} +#endif + +// CHECK-vanilla: PID: [[PID:[0-9]+]] +// CHECK-vanilla: [[PID]].sancov: 1 PCs written +// CHECK-vanilla: .so.[[PID]].sancov: 258 PCs written + +// CHECK-sandbox: PID: [[PID:[0-9]+]] +// CHECK-sandbox: 258 PCs written to packed file diff --git a/test/asan/TestCases/Linux/coverage-tracing.cc b/test/asan/TestCases/Linux/coverage-tracing.cc new file mode 100644 index 000000000000..89ab0d283add --- /dev/null +++ b/test/asan/TestCases/Linux/coverage-tracing.cc @@ -0,0 +1,22 @@ +// Test -mllvm -sanitizer-coverage-experimental-tracing +// +// RUN: %clangxx_asan -O1 -fsanitize-coverage=1 -mllvm -sanitizer-coverage-experimental-tracing %s -o %t +// RUN: rm -rf %T/coverage-tracing +// RUN: mkdir -p %T/coverage-tracing +// RUN: ASAN_OPTIONS=coverage=1:coverage_dir=%T/coverage-tracing:verbosity=1 %run %t 1 2 3 4 2>&1 | FileCheck %s +// RUN: rm -rf %T/coverage-tracing +// +// REQUIRES: asan-64-bits + +volatile int sink; +int main(int argc, char **argv) { + volatile int i = 0; + do { + sink = 0; + i++; + } while (i < argc); + return 0; +} + +// CHECK: CovDump: Trace: {{[3-9]}} PCs written +// CHECK: CovDump: Trace: {{[6-9]}} Events written diff --git a/test/asan/TestCases/Linux/coverage.cc b/test/asan/TestCases/Linux/coverage.cc new file mode 100644 index 000000000000..f6eb0ae9285b --- /dev/null +++ b/test/asan/TestCases/Linux/coverage.cc @@ -0,0 +1,71 @@ +// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %T/libcoverage_test.so -fPIC +// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t -Wl,-R,\$ORIGIN -L%T -lcoverage_test +// RUN: export ASAN_OPTIONS=coverage=1:verbosity=1 +// RUN: mkdir -p %T/coverage && cd %T/coverage +// RUN: %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-main +// RUN: %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-foo +// RUN: %run %t bar 2>&1 | FileCheck %s --check-prefix=CHECK-bar +// RUN: %run %t foo bar 2>&1 | FileCheck %s --check-prefix=CHECK-foo-bar +// RUN: not %run %t foo bar 4 2>&1 | FileCheck %s --check-prefix=CHECK-report +// RUN: not %run %t foo bar 4 5 2>&1 | FileCheck %s --check-prefix=CHECK-segv +// RUN: cd .. && rm coverage -r +// +// https://code.google.com/p/address-sanitizer/issues/detail?id=263 +// XFAIL: android + +#include "sanitizer/common_interface_defs.h" +#include <assert.h> +#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 G[4]; + +int main(int argc, char **argv) { + fprintf(stderr, "PID: %d\n", getpid()); + for (int i = 1; i < argc; i++) { + if (!strcmp(argv[i], "foo")) { + uintptr_t old_coverage = __sanitizer_get_total_unique_coverage(); + foo(); + uintptr_t new_coverage = __sanitizer_get_total_unique_coverage(); + assert(new_coverage > old_coverage); + } + if (!strcmp(argv[i], "bar")) + bar(); + } + if (argc == 5) { + static volatile char *zero = 0; + *zero = 0; // SEGV if argc == 5. + } + return G[argc]; // Buffer overflow if argc >= 4. +} +#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 +// +// CHECK-report: AddressSanitizer: global-buffer-overflow +// CHECK-report: PCs written +// +// CHECK-segv: AddressSanitizer: SEGV +// CHECK-segv: PCs written diff --git a/test/asan/TestCases/Linux/function-sections-are-bad.cc b/test/asan/TestCases/Linux/function-sections-are-bad.cc new file mode 100644 index 000000000000..15aaccbc957f --- /dev/null +++ b/test/asan/TestCases/Linux/function-sections-are-bad.cc @@ -0,0 +1,41 @@ +// Check that --gc-sections does not throw away (or localize) parts of sanitizer +// interface. +// RUN: %clang_asan %s -Wl,--gc-sections -ldl -o %t +// RUN: %clang_asan %s -DBUILD_SO -fPIC -o %t-so.so -shared +// RUN: %run %t 2>&1 + +// REQUIRES: asan-64-bits + +#ifndef BUILD_SO +#include <assert.h> +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> + +int main(int argc, char *argv[]) { + char path[4096]; + snprintf(path, sizeof(path), "%s-so.so", argv[0]); + + void *handle = dlopen(path, RTLD_LAZY); + if (!handle) fprintf(stderr, "%s\n", dlerror()); + assert(handle != 0); + + typedef void (*F)(); + F f = (F)dlsym(handle, "call_rtl_from_dso"); + printf("%s\n", dlerror()); + assert(dlerror() == 0); + f(); + + dlclose(handle); + return 0; +} + +#else // BUILD_SO + +#include <sanitizer/asan_interface.h> +extern "C" void call_rtl_from_dso() { + volatile int32_t x; + volatile int32_t y = __sanitizer_unaligned_load32((void *)&x); +} + +#endif // BUILD_SO diff --git a/test/asan/TestCases/Linux/globals-gc-sections.cc b/test/asan/TestCases/Linux/globals-gc-sections.cc new file mode 100644 index 000000000000..72a9e9498f85 --- /dev/null +++ b/test/asan/TestCases/Linux/globals-gc-sections.cc @@ -0,0 +1,13 @@ +// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -ffunction-sections -mllvm -asan-globals=0 +// RUN: %clangxx_asan %s -o %t -Wl,--gc-sections -ffunction-sections -mllvm -asan-globals=1 + +// https://code.google.com/p/address-sanitizer/issues/detail?id=260 +// XFAIL: * + +int undefined(); + +int (*unused)() = undefined; + +int main() { + return 0; +} diff --git a/test/asan/TestCases/Linux/initialization-bug-any-order.cc b/test/asan/TestCases/Linux/initialization-bug-any-order.cc new file mode 100644 index 000000000000..a462f4a163f1 --- /dev/null +++ b/test/asan/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 %run %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 %run %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/test/asan/TestCases/Linux/interception-in-shared-lib-test.cc b/test/asan/TestCases/Linux/interception-in-shared-lib-test.cc new file mode 100644 index 000000000000..b828d5524ee0 --- /dev/null +++ b/test/asan/TestCases/Linux/interception-in-shared-lib-test.cc @@ -0,0 +1,32 @@ +// Check that memset() call from a shared library gets intercepted. +// Please always keep this file in sync with +// ../Darwin/interception-in-shared-lib-test.cc. + +// RUN: %clangxx_asan -O0 %s -DSHARED_LIB \ +// RUN: -shared -o %T/libinterception-in-shared-lib-test.so \ +// RUN: -fPIC +// TODO(glider): figure out how to set rpath in a more portable way and unite +// this test with ../Darwin/interception-in-shared-lib-test.cc. +// RUN: %clangxx_asan -O0 %s -o %t -Wl,-R,\$ORIGIN -L%T -linterception-in-shared-lib-test && \ +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <stdio.h> +#include <string.h> + +#if defined(SHARED_LIB) +extern "C" +void my_memset(void *p, size_t sz) { + memset(p, 0, sz); +} +#else +extern "C" void my_memset(void *p, size_t sz); + +int main(int argc, char *argv[]) { + char buf[10]; + my_memset(buf, 11); + // CHECK: {{.*ERROR: AddressSanitizer: stack-buffer-overflow}} + // CHECK: {{WRITE of size 11 at 0x.* thread T0}} + // CHECK: {{0x.* in my_memset .*interception-in-shared-lib-test.cc:19}} + return 0; +} +#endif diff --git a/test/asan/TestCases/Linux/interception_malloc_test.cc b/test/asan/TestCases/Linux/interception_malloc_test.cc new file mode 100644 index 000000000000..f6d6d340bd9c --- /dev/null +++ b/test/asan/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 %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && not %run %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/test/asan/TestCases/Linux/interception_readdir_r_test.cc b/test/asan/TestCases/Linux/interception_readdir_r_test.cc new file mode 100644 index 000000000000..93b553c3744f --- /dev/null +++ b/test/asan/TestCases/Linux/interception_readdir_r_test.cc @@ -0,0 +1,62 @@ +// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316 +// XFAIL: android +// +// RUN: %clangxx_asan -O0 %s -DTEMP_DIR='"'"%T"'"' -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -DTEMP_DIR='"'"%T"'"' -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -DTEMP_DIR='"'"%T"'"' -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -DTEMP_DIR='"'"%T"'"' -o %t && %run %t 2>&1 | FileCheck %s +// +// RUN: %clangxx_asan -O0 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -D_FILE_OFFSET_BITS=64 -DTEMP_DIR='"'"%T"'"' -o %t && %run %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/test/asan/TestCases/Linux/interception_test.cc b/test/asan/TestCases/Linux/interception_test.cc new file mode 100644 index 000000000000..fb9d01cfe6d7 --- /dev/null +++ b/test/asan/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 %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && not %run %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/test/asan/TestCases/Linux/interface_symbols_linux.c b/test/asan/TestCases/Linux/interface_symbols_linux.c new file mode 100644 index 000000000000..a616732ff9f8 --- /dev/null +++ b/test/asan/TestCases/Linux/interface_symbols_linux.c @@ -0,0 +1,35 @@ +// Check the presence 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: | sed -E "s/__asan_init_v[0-9]+/__asan_init/" \ +// RUN: | grep -v "__asan_default_options" \ +// RUN: | grep -v "__asan_stack_" \ +// RUN: | grep -v "__asan_on_error" > %t.symbols +// RUN: cat %p/../../../../lib/asan/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: echo __asan_get_current_fake_stack >> %t.interface +// RUN: echo __asan_addr_is_in_fake_stack >> %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,asan-static-runtime + +int main() { return 0; } diff --git a/test/asan/TestCases/Linux/kernel-area.cc b/test/asan/TestCases/Linux/kernel-area.cc new file mode 100644 index 000000000000..8dd509f84975 --- /dev/null +++ b/test/asan/TestCases/Linux/kernel-area.cc @@ -0,0 +1,24 @@ +// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316 +// XFAIL: android +// +// Test that kernel area is not sanitized on 32-bit machines. +// +// RUN: %clangxx_asan %s -o %t +// RUN: ASAN_OPTIONS=verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%kernel_bits +// RUN: ASAN_OPTIONS=verbosity=1:full_address_space=0 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%kernel_bits +// RUN: ASAN_OPTIONS=verbosity=1:full_address_space=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-kernel-64-bits +// +// CHECK-kernel-32-bits: || `[0x38000000, 0xbfffffff]` || HighMem || +// CHECK-kernel-32-bits: || `[0x27000000, 0x37ffffff]` || HighShadow || +// CHECK-kernel-32-bits: || `[0x24000000, 0x26ffffff]` || ShadowGap || +// +// CHECK-kernel-64-bits: || `[0x40000000, 0xffffffff]` || HighMem || +// CHECK-kernel-64-bits: || `[0x28000000, 0x3fffffff]` || HighShadow || +// CHECK-kernel-64-bits: || `[0x24000000, 0x27ffffff]` || ShadowGap || +// +// REQUIRES: asan-32-bits + +int main() { + return 0; +} + diff --git a/test/asan/TestCases/Linux/leak.cc b/test/asan/TestCases/Linux/leak.cc new file mode 100644 index 000000000000..36dc6ddb8adf --- /dev/null +++ b/test/asan/TestCases/Linux/leak.cc @@ -0,0 +1,16 @@ +// Minimal test for LeakSanitizer+AddressSanitizer. +// REQUIRES: leak-detection +// +// RUN: %clangxx_asan %s -o %t +// RUN: ASAN_OPTIONS=detect_leaks=1 not %run %t 2>&1 | FileCheck %s +// RUN: ASAN_OPTIONS="" not %run %t 2>&1 | FileCheck %s +// RUN: ASAN_OPTIONS=detect_leaks=0 %run %t +#include <stdio.h> +int *t; + +int main(int argc, char **argv) { + t = new int[argc - 1]; + printf("t: %p\n", t); + t = 0; +} +// CHECK: LeakSanitizer: detected memory leaks diff --git a/test/asan/TestCases/Linux/lit.local.cfg b/test/asan/TestCases/Linux/lit.local.cfg new file mode 100644 index 000000000000..57271b8078a4 --- /dev/null +++ b/test/asan/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/test/asan/TestCases/Linux/malloc-in-qsort.cc b/test/asan/TestCases/Linux/malloc-in-qsort.cc new file mode 100644 index 000000000000..545bc7e42a17 --- /dev/null +++ b/test/asan/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 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-FAST +// RUN: ASAN_OPTIONS=fast_unwind_on_malloc=0 not %run %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 available 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/test/asan/TestCases/Linux/malloc_delete_mismatch.cc b/test/asan/TestCases/Linux/malloc_delete_mismatch.cc new file mode 100644 index 000000000000..18d65ce0008f --- /dev/null +++ b/test/asan/TestCases/Linux/malloc_delete_mismatch.cc @@ -0,0 +1,33 @@ +// 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 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=ALLOC-STACK + +// No error here. +// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=0 %run %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 %run %t 2>&1 | FileCheck %s +// RUN: ASAN_OPTIONS=alloc_dealloc_mismatch=1:malloc_context_size=0:fast_unwind_on_malloc=1 not %run %t 2>&1 | FileCheck %s +// XFAIL: arm-linux-gnueabi +// XFAIL: armv7l-unknown-linux-gnueabihf +#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/test/asan/TestCases/Linux/odr-violation.cc b/test/asan/TestCases/Linux/odr-violation.cc new file mode 100644 index 000000000000..ddc68a2db0f1 --- /dev/null +++ b/test/asan/TestCases/Linux/odr-violation.cc @@ -0,0 +1,42 @@ +// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316 +// XFAIL: android +// +// Different size: detect a bug if detect_odr_violation>=1 +// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t-ODR-SO.so +// RUN: %clangxx_asan %s %t-ODR-SO.so -Wl,-R. -o %t-ODR-EXE +// RUN: ASAN_OPTIONS=detect_odr_violation=1 not %run %t-ODR-EXE 2>&1 | FileCheck %s +// RUN: ASAN_OPTIONS=detect_odr_violation=2 not %run %t-ODR-EXE 2>&1 | FileCheck %s +// RUN: ASAN_OPTIONS=detect_odr_violation=0 %run %t-ODR-EXE 2>&1 | FileCheck %s --check-prefix=DISABLED +// RUN: not %run %t-ODR-EXE 2>&1 | FileCheck %s +// +// Same size: report a bug only if detect_odr_violation>=2. +// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t-ODR-SO.so -DSZ=100 +// RUN: ASAN_OPTIONS=detect_odr_violation=1 %run %t-ODR-EXE 2>&1 | FileCheck %s --check-prefix=DISABLED +// RUN: ASAN_OPTIONS=detect_odr_violation=2 not %run %t-ODR-EXE 2>&1 | FileCheck %s +// RUN: not %run %t-ODR-EXE 2>&1 | FileCheck %s + +// GNU driver doesn't handle .so files properly. +// REQUIRES: Clang + +#ifndef SZ +# define SZ 4 +#endif + +#if BUILD_SO +namespace foo { char G[SZ]; } +#else +#include <stdio.h> +namespace foo { char G[100]; } +// CHECK: ERROR: AddressSanitizer: odr-violation +// CHECK: size=100 'foo::G' {{.*}}odr-violation.cc:[[@LINE-2]]:22 +// CHECK: size={{4|100}} 'foo::G' +int main(int argc, char **argv) { + printf("PASS: %p\n", &foo::G); +} +#endif + +// CHECK: These globals were registered at these points: +// CHECK: ODR-EXE +// CHECK: ODR-SO +// CHECK: SUMMARY: AddressSanitizer: odr-violation: global 'foo::G' at {{.*}}odr-violation.cc +// DISABLED: PASS diff --git a/test/asan/TestCases/Linux/overflow-in-qsort.cc b/test/asan/TestCases/Linux/overflow-in-qsort.cc new file mode 100644 index 000000000000..79b654e117cd --- /dev/null +++ b/test/asan/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 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-FAST +// RUN: ASAN_OPTIONS=fast_unwind_on_fatal=0 not %run %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 available 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/test/asan/TestCases/Linux/preinit_test.cc b/test/asan/TestCases/Linux/preinit_test.cc new file mode 100644 index 000000000000..10dde67d6a9b --- /dev/null +++ b/test/asan/TestCases/Linux/preinit_test.cc @@ -0,0 +1,33 @@ +// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316 +// XFAIL: android +// +// RUN: %clangxx -DFUNC=zzzz %s -shared -o %t.so -fPIC +// RUN: %clangxx_asan -DFUNC=main %s -o %t -Wl,-R. %t.so +// RUN: %run %t + +// GNU driver doesn't handle .so files properly. +// REQUIRES: Clang + +// 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/test/asan/TestCases/Linux/ptrace.cc b/test/asan/TestCases/Linux/ptrace.cc new file mode 100644 index 000000000000..7e5acb64c7a1 --- /dev/null +++ b/test/asan/TestCases/Linux/ptrace.cc @@ -0,0 +1,56 @@ +// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316 +// XFAIL: android +// +// RUN: %clangxx_asan -O0 %s -o %t && %run %t +// RUN: %clangxx_asan -DPOSITIVE -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s +// REQUIRES: x86_64-supported-target,i386-supported-target + +#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 = ®s; +#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/test/asan/TestCases/Linux/rlimit_mmap_test.cc b/test/asan/TestCases/Linux/rlimit_mmap_test.cc new file mode 100644 index 000000000000..7f37727b2eeb --- /dev/null +++ b/test/asan/TestCases/Linux/rlimit_mmap_test.cc @@ -0,0 +1,16 @@ +// Check that we properly report mmap failure. +// RUN: %clangxx_asan %s -o %t && not %run %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/test/asan/TestCases/Linux/shmctl.cc b/test/asan/TestCases/Linux/shmctl.cc new file mode 100644 index 000000000000..e1752bc894c0 --- /dev/null +++ b/test/asan/TestCases/Linux/shmctl.cc @@ -0,0 +1,27 @@ +// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316 +// XFAIL: android +// +// RUN: %clangxx_asan -O1 %s -o %t && %run %t 2>&1 +// Regression test for +// https://code.google.com/p/address-sanitizer/issues/detail?id=250 +#include <stdio.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#include <assert.h> + +int main() { + int id = shmget(IPC_PRIVATE, 4096, 0644 | IPC_CREAT); + assert(id > -1); + struct shmid_ds ds; + int res = shmctl(id, IPC_STAT, &ds); + assert(res > -1); + printf("shm_segsz: %zd\n", ds.shm_segsz); + assert(ds.shm_segsz == 4096); + assert(-1 != shmctl(id, IPC_RMID, 0)); + + struct shm_info shmInfo; + res = shmctl(0, SHM_INFO, (struct shmid_ds *)&shmInfo); + assert(res > -1); + + return 0; +} diff --git a/test/asan/TestCases/Linux/sized_delete_test.cc b/test/asan/TestCases/Linux/sized_delete_test.cc new file mode 100644 index 000000000000..823e3c0bf88e --- /dev/null +++ b/test/asan/TestCases/Linux/sized_delete_test.cc @@ -0,0 +1,93 @@ +// RUN: %clangxx_asan -Xclang -fsized-deallocation -O0 %s -o %t +// RUN: not %run %t scalar 2>&1 | FileCheck %s -check-prefix=SCALAR +// RUN: ASAN_OPTIONS=new_delete_type_mismatch=1 not %run %t scalar 2>&1 | FileCheck %s -check-prefix=SCALAR +// RUN: not %run %t array 2>&1 | FileCheck %s -check-prefix=ARRAY +// RUN: ASAN_OPTIONS=new_delete_type_mismatch=1 not %run %t array 2>&1 | FileCheck %s -check-prefix=ARRAY +// RUN: ASAN_OPTIONS=new_delete_type_mismatch=0 %run %t scalar +// RUN: ASAN_OPTIONS=new_delete_type_mismatch=0 %run %t array + +// Sized-delete is implemented with a weak delete() definition. +// Weak symbols are kind of broken on Android. +// XFAIL: android + +#include <new> +#include <stdio.h> +#include <string> + +inline void break_optimization(void *arg) { + __asm__ __volatile__("" : : "r" (arg) : "memory"); +} + +struct S12 { + int a, b, c; +}; + +struct S20 { + int a, b, c, d, e; +}; + +struct D1 { + int a, b, c; + ~D1() { fprintf(stderr, "D1::~D1\n"); } +}; + +struct D2 { + int a, b, c, d, e; + ~D2() { fprintf(stderr, "D2::~D2\n"); } +}; + +void Del12(S12 *x) { + break_optimization(x); + delete x; +} +void Del12NoThrow(S12 *x) { + break_optimization(x); + operator delete(x, std::nothrow); +} +void Del12Ar(S12 *x) { + break_optimization(x); + delete [] x; +} +void Del12ArNoThrow(S12 *x) { + break_optimization(x); + operator delete[](x, std::nothrow); +} + +int main(int argc, char **argv) { + if (argc != 2) return 1; + std::string flag = argv[1]; + // These are correct. + Del12(new S12); + Del12NoThrow(new S12); + Del12Ar(new S12[100]); + Del12ArNoThrow(new S12[100]); + + // Here we pass wrong type of pointer to delete, + // but [] and nothrow variants of delete are not sized. + Del12Ar(reinterpret_cast<S12*>(new S20[100])); + Del12NoThrow(reinterpret_cast<S12*>(new S20)); + Del12ArNoThrow(reinterpret_cast<S12*>(new S20[100])); + fprintf(stderr, "OK SO FAR\n"); + // SCALAR: OK SO FAR + // ARRAY: OK SO FAR + if (flag == "scalar") { + // Here asan should bark as we are passing a wrong type of pointer + // to sized delete. + Del12(reinterpret_cast<S12*>(new S20)); + // SCALAR: AddressSanitizer: new-delete-type-mismatch + // SCALAR: object passed to delete has wrong type: + // SCALAR: size of the allocated type: 20 bytes; + // SCALAR: size of the deallocated type: 12 bytes. + // SCALAR: is located 0 bytes inside of 20-byte region + // SCALAR: SUMMARY: AddressSanitizer: new-delete-type-mismatch + } else if (flag == "array") { + D1 *d1 = reinterpret_cast<D1*>(new D2[10]); + break_optimization(d1); + delete [] d1; + // ARRAY-NOT: D2::~D2 + // ARRAY: D1::~D1 + // ARRAY: AddressSanitizer: new-delete-type-mismatch + // ARRAY: size of the allocated type: 20{{4|8}} bytes; + // ARRAY: size of the deallocated type: 12{{4|8}} bytes. + } +} diff --git a/test/asan/TestCases/Linux/stack-trace-dlclose.cc b/test/asan/TestCases/Linux/stack-trace-dlclose.cc new file mode 100644 index 000000000000..e494e5661d1d --- /dev/null +++ b/test/asan/TestCases/Linux/stack-trace-dlclose.cc @@ -0,0 +1,45 @@ +// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316 +// XFAIL: android +// +// RUN: %clangxx_asan -DSHARED %s -shared -o %T/stack_trace_dlclose.so -fPIC +// RUN: %clangxx_asan -DSO_DIR=\"%T\" %s -o %t +// RUN: ASAN_OPTIONS=exitcode=0 %run %t 2>&1 | FileCheck %s +// XFAIL: arm-linux-gnueabi +// XFAIL: armv7l-unknown-linux-gnueabihf + +#include <assert.h> +#include <dlfcn.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> + +#include <sanitizer/common_interface_defs.h> + +#ifdef SHARED +extern "C" { +void *foo() { + return malloc(1); +} +} +#else +void *handle; + +int main(int argc, char **argv) { + void *handle = dlopen(SO_DIR "/stack_trace_dlclose.so", RTLD_LAZY); + assert(handle); + void *(*foo)() = (void *(*)())dlsym(handle, "foo"); + assert(foo); + void *p = foo(); + assert(p); + dlclose(handle); + + free(p); + free(p); // double-free + + return 0; +} +#endif + +// CHECK: {{ #0 0x.* in malloc}} +// CHECK: {{ #1 0x.* \(<unknown module>\)}} +// CHECK: {{ #2 0x.* in main}} diff --git a/test/asan/TestCases/Linux/stress_dtls.c b/test/asan/TestCases/Linux/stress_dtls.c new file mode 100644 index 000000000000..cb901ee59953 --- /dev/null +++ b/test/asan/TestCases/Linux/stress_dtls.c @@ -0,0 +1,116 @@ +// REQUIRES: asan-64-bits +// Stress test dynamic TLS + dlopen + threads. +// +// Note that glibc 2.15 seems utterly broken on this test, +// it fails with ~17 DSOs dlopen-ed. +// glibc 2.19 seems fine. +// +// +// RUN: %clangxx_asan -x c -DSO_NAME=f0 %s -shared -o %t-f0.so -fPIC +// RUN: %clangxx_asan -x c -DSO_NAME=f1 %s -shared -o %t-f1.so -fPIC +// RUN: %clangxx_asan -x c -DSO_NAME=f2 %s -shared -o %t-f2.so -fPIC +// RUN: %clangxx_asan %s -ldl -pthread -o %t +// RUN: %run %t 0 3 +// RUN: %run %t 2 3 +// RUN: ASAN_OPTIONS=verbosity=2 %run %t 10 2 2>&1 | FileCheck %s +// RUN: ASAN_OPTIONS=verbosity=2:intercept_tls_get_addr=1 %run %t 10 2 2>&1 | FileCheck %s +// RUN: ASAN_OPTIONS=verbosity=2:intercept_tls_get_addr=0 %run %t 10 2 2>&1 | FileCheck %s --check-prefix=CHECK0 +// CHECK: __tls_get_addr +// CHECK: Creating thread 0 +// CHECK: __tls_get_addr +// CHECK: Creating thread 1 +// CHECK: __tls_get_addr +// CHECK: Creating thread 2 +// CHECK: __tls_get_addr +// CHECK: Creating thread 3 +// CHECK: __tls_get_addr +// Make sure that TLS slots don't leak +// CHECK-NOT: num_live_dtls 5 +// +// CHECK0-NOT: __tls_get_addr +/* +cc=your-compiler + +$cc stress_dtls.c -pthread -ldl +for((i=0;i<100;i++)); do + $cc -fPIC -shared -DSO_NAME=f$i -o a.out-f$i.so stress_dtls.c; +done +./a.out 2 4 # <<<<<< 2 threads, 4 libs +./a.out 3 50 # <<<<<< 3 threads, 50 libs +*/ +#ifndef SO_NAME +#define _GNU_SOURCE +#include <assert.h> +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> +#include <pthread.h> +#include <stdint.h> + +typedef void **(*f_t)(); + +__thread int my_tls; + +#define MAX_N_FUNCTIONS 1000 +f_t Functions[MAX_N_FUNCTIONS]; + +void *PrintStuff(void *unused) { + uintptr_t stack; + // fprintf(stderr, "STACK: %p TLS: %p SELF: %p\n", &stack, &my_tls, + // (void *)pthread_self()); + int i; + for (i = 0; i < MAX_N_FUNCTIONS; i++) { + if (!Functions[i]) break; + uintptr_t dtls = (uintptr_t)Functions[i](); + fprintf(stderr, " dtls[%03d]: %lx\n", i, dtls); + *(long*)dtls = 42; // check that this is writable. + } + return NULL; +} + +int main(int argc, char *argv[]) { + int num_threads = 1; + int num_libs = 1; + if (argc >= 2) + num_threads = atoi(argv[1]); + if (argc >= 3) + num_libs = atoi(argv[2]); + assert(num_libs <= MAX_N_FUNCTIONS); + + int lib; + for (lib = 0; lib < num_libs; lib++) { + char buf[4096]; + snprintf(buf, sizeof(buf), "%s-f%d.so", argv[0], lib); + void *handle = dlopen(buf, RTLD_LAZY); + if (!handle) { + fprintf(stderr, "%s\n", dlerror()); + exit(1); + } + snprintf(buf, sizeof(buf), "f%d", lib); + Functions[lib] = (f_t)dlsym(handle, buf); + if (!Functions[lib]) { + fprintf(stderr, "%s\n", dlerror()); + exit(1); + } + fprintf(stderr, "LIB[%03d] %s: %p\n", lib, buf, Functions[lib]); + PrintStuff(0); + + int i; + for (i = 0; i < num_threads; i++) { + pthread_t t; + fprintf(stderr, "Creating thread %d\n", i); + pthread_create(&t, 0, PrintStuff, 0); + pthread_join(t, 0); + } + } + return 0; +} +#else // SO_NAME +#ifndef DTLS_SIZE +# define DTLS_SIZE (1 << 17) +#endif +__thread void *huge_thread_local_array[DTLS_SIZE]; +void **SO_NAME() { + return &huge_thread_local_array[0]; +} +#endif diff --git a/test/asan/TestCases/Linux/swapcontext_test.cc b/test/asan/TestCases/Linux/swapcontext_test.cc new file mode 100644 index 000000000000..86ed5930bcf4 --- /dev/null +++ b/test/asan/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 && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && %run %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/test/asan/TestCases/Linux/syscalls.cc b/test/asan/TestCases/Linux/syscalls.cc new file mode 100644 index 000000000000..bcdd5bc82119 --- /dev/null +++ b/test/asan/TestCases/Linux/syscalls.cc @@ -0,0 +1,25 @@ +// FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316 +// XFAIL: android +// +// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s -o %t && not %run %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/test/asan/TestCases/Linux/uar_signals.cc b/test/asan/TestCases/Linux/uar_signals.cc new file mode 100644 index 000000000000..f42c3f666554 --- /dev/null +++ b/test/asan/TestCases/Linux/uar_signals.cc @@ -0,0 +1,70 @@ +// This test checks that the implementation of use-after-return +// is async-signal-safe. +// RUN: %clangxx_asan -O1 %s -o %t -pthread && %run %t +// REQUIRES: stable-runtime +#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/test/asan/TestCases/Linux/unpoison_tls.cc b/test/asan/TestCases/Linux/unpoison_tls.cc new file mode 100644 index 000000000000..9c1d74b28e5f --- /dev/null +++ b/test/asan/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 -pthread -o %t && %run %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; +} |
