diff --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-capture.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-capture.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-capture.cpp @@ -0,0 +1,20 @@ +// RUN: %clangxx_asan %stdcxx11 -O1 -fsanitize-address-use-after-scope %s -o %t && \ +// RUN: not %run %t 2>&1 | FileCheck %s +// +// Not expected to work yet with HWAsan +// XFAIL: * + +#include + +int main() { + std::function f; + { + int x = 0; + f = [&x]() __attribute__((noinline)) { + return x; // BOOM + // CHECK: ERROR: AddressSanitizer: stack-use-after-scope + // CHECK: #0 0x{{.*}} in {{.*}}use-after-scope-capture.cpp:[[@LINE-2]] + }; + } + return f(); // BOOM +} diff --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-dtor-order.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-dtor-order.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-dtor-order.cpp @@ -0,0 +1,29 @@ +// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \ +// RUN: not %run %t 2>&1 | FileCheck %s +// +// Not expected to work yet with HWAsan. +// XFAIL: * + +#include + +struct IntHolder { + explicit IntHolder(int *val = 0) : val_(val) { } + __attribute__((noinline)) ~IntHolder() { + printf("Value: %d\n", *val_); // BOOM + // CHECK: ERROR: AddressSanitizer: stack-use-after-scope + // CHECK: #0 0x{{.*}} in IntHolder::~IntHolder{{.*}}.cpp:[[@LINE-2]] + } + void set(int *val) { val_ = val; } + int *get() { return val_; } + + int *val_; +}; + +int main(int argc, char *argv[]) { + // It is incorrect to use "x" int IntHolder destructor, because "x" is + // "destroyed" earlier as it's declared later. + IntHolder holder; + int x = argc; + holder.set(&x); + return 0; +} diff --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-goto.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-goto.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-goto.cpp @@ -0,0 +1,76 @@ +// RUN: %clangxx_asan -O0 -fsanitize-address-use-after-scope %s -o %t && %run %t + +// Function jumps over variable initialization making lifetime analysis +// ambiguous. Asan should ignore such variable and program must not fail. +// +// Not expected to work yet with HWAsan. +// XFAIL: * + +#include + +int *ptr; + +void f1(int cond) { + if (cond) + goto label; + int tmp; + + label: + ptr = &tmp; + *ptr = 5; +} + +void f2(int cond) { + switch (cond) { + case 1: { + ++cond; + int tmp; + ptr = &tmp; + exit(0); + case 2: + ptr = &tmp; + *ptr = 5; + exit(0); + } + } +} + +void f3(int cond) { + { + int tmp; + goto l2; + l1: + ptr = &tmp; + *ptr = 5; + + exit(0); + } + l2: + goto l1; +} + +void use(int *x) { + static int c = 10; + if (--c == 0) + exit(0); + (*x)++; +} + +void f4() { + { + int x; + l2: + use(&x); + goto l1; + } + l1: + goto l2; +} + +int main() { + f1(1); + f2(1); + f3(1); + f4(); + return 0; +} diff --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-if.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-if.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-if.cpp @@ -0,0 +1,18 @@ +// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \ +// RUN: not %run %t 2>&1 | FileCheck %s +// +// Not expected to work yet with HWAsan. +// XFAIL: * + +int *p; +bool b = true; + +int main() { + if (b) { + int x[5]; + p = x+1; + } + return *p; // BOOM + // CHECK: ERROR: AddressSanitizer: stack-use-after-scope + // CHECK: #0 0x{{.*}} in main {{.*}}.cpp:[[@LINE-2]] +} diff --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-inlined.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-inlined.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-inlined.cpp @@ -0,0 +1,31 @@ +// Test with "-O2" only to make sure inlining (leading to use-after-scope) +// happens. "always_inline" is not enough, as Clang doesn't emit +// llvm.lifetime intrinsics at -O0. +// +// RUN: %clangxx_asan -O2 -fsanitize-address-use-after-scope %s -o %t && \ +// RUN: not %run %t 2>&1 | FileCheck %s +// +// Not expected to work yet with HWAsan. +// XFAIL: * + +int *arr; + +__attribute__((always_inline)) +void inlined(int arg) { + int x[5]; + for (int i = 0; i < arg; i++) x[i] = i; + arr = x; +} + +int main(int argc, char *argv[]) { + inlined(argc); + return arr[argc - 1]; // BOOM + // CHECK: ERROR: AddressSanitizer: stack-use-after-scope + // CHECK: READ of size 4 at 0x{{.*}} thread T0 + // CHECK: #0 0x{{.*}} in main + // CHECK: {{.*}}use-after-scope-inlined.cpp:[[@LINE-4]] + // CHECK: Address 0x{{.*}} is located in stack of thread T0 at offset [[OFFSET:[^ ]*]] in frame + // CHECK: {{.*}} in main + // CHECK: This frame has + // CHECK: {{\[}}[[OFFSET]], {{.*}}) 'x.i' (line [[@LINE-15]]) +} diff --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-loop-bug.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-loop-bug.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-loop-bug.cpp @@ -0,0 +1,20 @@ +// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \ +// RUN: not %run %t 2>&1 | FileCheck %s +// +// Not expected to work yet with HWAsan. +// XFAIL: * + +volatile int *p; + +int main() { + // Variable goes in and out of scope. + for (int i = 0; i < 3; ++i) { + int x[3] = {i, i, i}; + p = x + i; + } + return *p; // BOOM + // CHECK: ERROR: AddressSanitizer: stack-use-after-scope + // CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope-loop-bug.cpp:[[@LINE-2]] + // CHECK: Address 0x{{.*}} is located in stack of thread T{{.*}} at offset [[OFFSET:[^ ]+]] in frame + // {{\[}}[[OFFSET]], {{[0-9]+}}) 'x' +} diff --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-loop-removed.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-loop-removed.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-loop-removed.cpp @@ -0,0 +1,21 @@ +// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \ +// RUN: not %run %t 2>&1 | FileCheck %s +// +// Not expected to work yet with HWAsan. +// XFAIL: * + +#include + +int *p; + +int main() { + for (int i = 0; i < 3; i++) { + int x; + p = &x; + } + return *p; // BOOM + // CHECK: ERROR: AddressSanitizer: stack-use-after-scope + // CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope-loop-removed.cpp:[[@LINE-2]] + // CHECK: Address 0x{{.*}} is located in stack of thread T{{.*}} at offset [[OFFSET:[^ ]+]] in frame + // {{\[}}[[OFFSET]], {{[0-9]+}}) 'x' +} diff --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-loop.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-loop.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-loop.cpp @@ -0,0 +1,17 @@ +// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \ +// RUN: not %run %t 2>&1 | FileCheck %s +// +// Not expected to work yet with HWAsan. +// XFAIL: * + +int *p[3]; + +int main() { + for (int i = 0; i < 3; i++) { + int x; + p[i] = &x; + } + return **p; // BOOM + // CHECK: ERROR: AddressSanitizer: stack-use-after-scope + // CHECK: #0 0x{{.*}} in main {{.*}}.cpp:[[@LINE-2]] +} diff --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-nobug.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-nobug.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-nobug.cpp @@ -0,0 +1,19 @@ +// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && %run %t +// +// Not expected to work yet with HWAsan. +// XFAIL: * + +#include +#include + +int *p[3]; + +int main() { + // Variable goes in and out of scope. + for (int i = 0; i < 3; i++) { + int x; + p[i] = &x; + } + printf("PASSED\n"); + return 0; +} diff --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-temp.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-temp.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-temp.cpp @@ -0,0 +1,24 @@ +// RUN: %clangxx_asan %stdcxx11 -O1 -fsanitize-address-use-after-scope %s -o %t && \ +// RUN: not %run %t 2>&1 | FileCheck %s +// +// Not expected to work yet with HWAsan. +// XFAIL: * + + +struct IntHolder { + int val; +}; + +const IntHolder *saved; + +__attribute__((noinline)) void save(const IntHolder &holder) { + saved = &holder; +} + +int main(int argc, char *argv[]) { + save({argc}); + int x = saved->val; // BOOM + // CHECK: ERROR: AddressSanitizer: stack-use-after-scope + // CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope-temp.cpp:[[@LINE-2]] + return x; +} diff --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-temp2.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-temp2.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-temp2.cpp @@ -0,0 +1,23 @@ +// RUN: %clangxx_asan %stdcxx11 -O1 -fsanitize-address-use-after-scope %s -o %t && \ +// RUN: not %run %t 2>&1 | FileCheck %s +// +// Not expected to work yet with HWAsan. +// XFAIL: * + + +struct IntHolder { + __attribute__((noinline)) const IntHolder &Self() const { + return *this; + } + int val = 3; +}; + +const IntHolder *saved; + +int main(int argc, char *argv[]) { + saved = &IntHolder().Self(); + int x = saved->val; // BOOM + // CHECK: ERROR: AddressSanitizer: stack-use-after-scope + // CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope-temp2.cpp:[[@LINE-2]] + return x; +} diff --git a/compiler-rt/test/hwasan/TestCases/use-after-scope-types.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope-types.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/use-after-scope-types.cpp @@ -0,0 +1,77 @@ +// RUN: %clangxx_asan %stdcxx11 -O0 -fsanitize-address-use-after-scope %s -o %t +// RUN: not %run %t 0 2>&1 | FileCheck %s +// RUN: not %run %t 1 2>&1 | FileCheck %s +// RUN: not %run %t 2 2>&1 | FileCheck %s +// RUN: not %run %t 3 2>&1 | FileCheck %s +// RUN: not %run %t 4 2>&1 | FileCheck %s +// RUN: not %run %t 5 2>&1 | FileCheck %s +// RUN: not %run %t 6 2>&1 | FileCheck %s +// RUN: not %run %t 7 2>&1 | FileCheck %s +// RUN: not %run %t 8 2>&1 | FileCheck %s +// RUN: not %run %t 9 2>&1 | FileCheck %s +// RUN: not %run %t 10 2>&1 | FileCheck %s +// +// Not expected to work yet with HWAsan. +// XFAIL: * + +#include +#include +#include + +template struct Ptr { + void Store(T *ptr) { t = ptr; } + + void Access() { *t = {}; } + + T *t; +}; + +template struct Ptr { + using Type = T[N]; + void Store(Type *ptr) { t = *ptr; } + + void Access() { *t = {}; } + + T *t; +}; + +template __attribute__((noinline)) void test() { + Ptr ptr; + { + T x; + ptr.Store(&x); + } + + ptr.Access(); + // CHECK: ERROR: AddressSanitizer: stack-use-after-scope + // CHECK: #{{[0-9]+}} 0x{{.*}} in {{(void )?test.*\((void)?\) .*}}use-after-scope-types.cpp + // CHECK: Address 0x{{.*}} is located in stack of thread T{{.*}} at offset [[OFFSET:[^ ]+]] in frame + // {{\[}}[[OFFSET]], {{[0-9]+}}) 'x' +} + +int main(int argc, char **argv) { + using Tests = void (*)(); + Tests tests[] = { + &test, + &test, + &test, + &test, + &test, + &test, + &test>, + &test, + &test, + &test, + &test, + }; + + int n = atoi(argv[1]); + if (n == sizeof(tests) / sizeof(tests[0])) { + for (auto te : tests) + te(); + } else { + tests[n](); + } + + return 0; +} diff --git a/compiler-rt/test/hwasan/TestCases/use-after-scope.cpp b/compiler-rt/test/hwasan/TestCases/use-after-scope.cpp new file mode 100644 --- /dev/null +++ b/compiler-rt/test/hwasan/TestCases/use-after-scope.cpp @@ -0,0 +1,24 @@ +// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \ +// RUN: not %run %t 2>&1 | FileCheck %s + +// -fsanitize-address-use-after-scope is now on by default: +// RUN: %clangxx_asan -O1 %s -o %t && \ +// RUN: not %run %t 2>&1 | FileCheck %s +// +// Not expected to work yet with HWAsan. +// XFAIL: * + +volatile int *p = 0; + +int main() { + { + int x = 0; + p = &x; + } + *p = 5; // BOOM + // CHECK: ERROR: AddressSanitizer: stack-use-after-scope + // CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope.cpp:[[@LINE-2]] + // CHECK: Address 0x{{.*}} is located in stack of thread T{{.*}} at offset [[OFFSET:[^ ]+]] in frame + // {{\[}}[[OFFSET]], {{[0-9]+}}) 'x' + return 0; +}