diff options
Diffstat (limited to 'test')
278 files changed, 4268 insertions, 851 deletions
diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 03d4571e0de78..9b9c515a304d2 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -23,7 +23,7 @@ if(NOT ANDROID) # Use LLVM utils and Clang from the same build tree. list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS clang clang-headers FileCheck count not llvm-config llvm-nm llvm-objdump - llvm-symbolizer compiler-rt-headers sancov) + llvm-readobj llvm-symbolizer compiler-rt-headers sancov) if (COMPILER_RT_HAS_PROFILE) list(APPEND SANITIZER_COMMON_LIT_TEST_DEPS profile) endif() @@ -45,6 +45,9 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS) if(COMPILER_RT_HAS_DFSAN) add_subdirectory(dfsan) endif() + if (COMPILER_RT_HAS_INTERCEPTION) + add_subdirectory(interception) + endif() if(COMPILER_RT_HAS_LSAN) add_subdirectory(lsan) endif() @@ -76,6 +79,9 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS) if(COMPILER_RT_HAS_SCUDO) add_subdirectory(scudo) endif() + if(COMPILER_RT_HAS_XRAY) + add_subdirectory(xray) + endif() endif() if(COMPILER_RT_STANDALONE_BUILD) @@ -83,8 +89,13 @@ if(COMPILER_RT_STANDALONE_BUILD) # introduce a rule to run to run all of them. get_property(LLVM_LIT_TESTSUITES GLOBAL PROPERTY LLVM_LIT_TESTSUITES) get_property(LLVM_LIT_DEPENDS GLOBAL PROPERTY LLVM_LIT_DEPENDS) - add_lit_target(check-all + add_lit_target(check-compiler-rt "Running all regression tests" ${LLVM_LIT_TESTSUITES} DEPENDS ${LLVM_LIT_DEPENDS}) + if(NOT TARGET check-all) + add_custom_target(check-all) + endif() + add_custom_target(compiler-rt-test-depends DEPENDS ${LLVM_LIT_DEPENDS}) + add_dependencies(check-all check-compiler-rt) endif() diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt index cb32cfba83b04..637c5b80802cd 100644 --- a/test/asan/CMakeLists.txt +++ b/test/asan/CMakeLists.txt @@ -43,15 +43,7 @@ foreach(arch ${ASAN_TEST_ARCH}) endif() string(TOLOWER "-${arch}-${OS_NAME}" ASAN_TEST_CONFIG_SUFFIX) get_bits_for_arch(${arch} ASAN_TEST_BITS) - if(ANDROID OR ${arch} MATCHES "arm|aarch64") - # This is only true if we are cross-compiling. - # Build all tests with host compiler and use host tools. - set(ASAN_TEST_TARGET_CC ${COMPILER_RT_TEST_COMPILER}) - set(ASAN_TEST_TARGET_CFLAGS ${COMPILER_RT_TEST_COMPILER_CFLAGS}) - else() - get_target_flags_for_arch(${arch} ASAN_TEST_TARGET_CFLAGS) - string(REPLACE ";" " " ASAN_TEST_TARGET_CFLAGS "${ASAN_TEST_TARGET_CFLAGS}") - endif() + get_test_cc_for_arch(${arch} ASAN_TEST_TARGET_CC ASAN_TEST_TARGET_CFLAGS) if(ANDROID) set(ASAN_TEST_DYNAMIC True) else() diff --git a/test/asan/TestCases/Android/coverage-android.cc b/test/asan/TestCases/Android/coverage-android.cc index 2a3359948691d..cf4f33ebdb446 100644 --- a/test/asan/TestCases/Android/coverage-android.cc +++ b/test/asan/TestCases/Android/coverage-android.cc @@ -101,6 +101,10 @@ // RUN: %sancov rawunpack *.sancov.raw // RUN: %sancov print *.sancov |& FileCheck --check-prefix=CHECK3 %s +// PC counts in CHECK lines are platform dependent and match arm32 at the moment. +// sancov tool does not support Android well enough to match function names +// REQUIRES: arm + #include <assert.h> #include <dlfcn.h> #include <stdio.h> diff --git a/test/asan/TestCases/Darwin/cstring_section.c b/test/asan/TestCases/Darwin/cstring_section.c new file mode 100644 index 0000000000000..952d6fcdd4656 --- /dev/null +++ b/test/asan/TestCases/Darwin/cstring_section.c @@ -0,0 +1,17 @@ +// Test that AddressSanitizer moves constant strings into a separate section. + +// RUN: %clang_asan -c -o %t %s +// RUN: llvm-objdump -s %t | FileCheck %s + +// Check that "Hello.\n" is in __asan_cstring and not in __cstring. +// CHECK: Contents of section __asan_cstring: +// CHECK: 48656c6c {{.*}} Hello. +// CHECK: Contents of section __const: +// CHECK-NOT: 48656c6c {{.*}} Hello. +// CHECK: Contents of section __cstring: +// CHECK-NOT: 48656c6c {{.*}} Hello. + +int main(int argc, char *argv[]) { + argv[0] = "Hello.\n"; + return 0; +} diff --git a/test/asan/TestCases/Darwin/dead-strip.c b/test/asan/TestCases/Darwin/dead-strip.c new file mode 100644 index 0000000000000..f87a5e52b1cf1 --- /dev/null +++ b/test/asan/TestCases/Darwin/dead-strip.c @@ -0,0 +1,22 @@ +// Test that AddressSanitizer does not re-animate dead globals when dead +// stripping is turned on. +// +// This test verifies that an out-of-bounds access on a global variable is +// detected after dead stripping has been performed. This proves that the +// runtime is able to register globals in the __DATA,__asan_globals section. + +// REQUIRES: osx-ld64-live_support +// RUN: %clang_asan -mmacosx-version-min=10.11 -Xlinker -dead_strip -o %t %s +// RUN: llvm-nm -format=posix %t | FileCheck --check-prefix NM-CHECK %s +// RUN: not %run %t 2>&1 | FileCheck --check-prefix ASAN-CHECK %s + +int alive[1] = {}; +int dead[1] = {}; +// NM-CHECK: {{^_alive }} +// NM-CHECK-NOT: {{^_dead }} + +int main(int argc, char *argv[]) { + alive[argc] = 0; + // ASAN-CHECK: {{0x.* is located 0 bytes to the right of global variable}} + return 0; +} diff --git a/test/asan/TestCases/Darwin/dump_registers.cc b/test/asan/TestCases/Darwin/dump_registers.cc new file mode 100644 index 0000000000000..884ad2ed44c07 --- /dev/null +++ b/test/asan/TestCases/Darwin/dump_registers.cc @@ -0,0 +1,26 @@ +// Check that ASan dumps the CPU registers on a SIGSEGV. + +// RUN: %clangxx_asan %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <assert.h> +#include <stdio.h> + +int main() { + fprintf(stderr, "Hello\n"); + char *ptr; + + if (sizeof(void *) == 8) + ptr = (char *)0x6666666666666666; + else if (sizeof(void *) == 4) + ptr = (char *)0x55555555; + else + assert(0 && "Your computer is weird."); + + char c = *ptr; // BOOM + // CHECK: ERROR: AddressSanitizer: SEGV + // CHECK: Register values: + // CHECK: {{0x55555555|0x6666666666666666}} + fprintf(stderr, "World\n"); + return c; +} diff --git a/test/asan/TestCases/Darwin/malloc_destroy_zone.cc b/test/asan/TestCases/Darwin/malloc_destroy_zone.cc new file mode 100644 index 0000000000000..9144bd689f744 --- /dev/null +++ b/test/asan/TestCases/Darwin/malloc_destroy_zone.cc @@ -0,0 +1,21 @@ +// RUN: %clangxx_asan %s -o %t && %run %t 2>&1 | FileCheck %s + +#include <malloc/malloc.h> +#include <stdlib.h> +#include <stdio.h> + +int main() { + fprintf(stderr, "start\n"); + malloc_zone_t *zone = malloc_create_zone(0, 0); + fprintf(stderr, "zone = %p\n", zone); + malloc_set_zone_name(zone, "myzone"); + fprintf(stderr, "name changed\n"); + malloc_destroy_zone(zone); + fprintf(stderr, "done\n"); + return 0; +} + +// CHECK: start +// CHECK-NEXT: zone = 0x{{.*}} +// CHECK-NEXT: name changed +// CHECK-NEXT: done diff --git a/test/asan/TestCases/Darwin/odr-lto.cc b/test/asan/TestCases/Darwin/odr-lto.cc new file mode 100644 index 0000000000000..40abec5827d5f --- /dev/null +++ b/test/asan/TestCases/Darwin/odr-lto.cc @@ -0,0 +1,45 @@ +// Check that -asan-use-private-alias and use_odr_indicator=1 silence the false +// positive ODR violation on Darwin with LTO. + +// REQUIRES: lto + +// RUN: %clangxx_asan -DPART=0 -c %s -o %t-1.o -flto +// RUN: %clangxx_asan -DPART=1 -c %s -o %t-2.o -flto +// RUN: %clangxx_asan %t-1.o %t-2.o -o %t -flto +// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-ODR + +// RUN: %clangxx_asan -DPART=0 -c %s -o %t-1.o -flto -mllvm -asan-use-private-alias +// RUN: %clangxx_asan -DPART=1 -c %s -o %t-2.o -flto -mllvm -asan-use-private-alias +// RUN: %clangxx_asan %t-1.o %t-2.o -o %t -flto +// RUN: %env_asan_opts=use_odr_indicator=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-NO-ODR + +#include <stdio.h> +#include <stdlib.h> +void putstest(); + +#if PART == 1 + +static const char *my_global = "test\n\00abc"; + +int main() +{ + fputs(my_global, stderr); + putstest(); + fprintf(stderr, "Done.\n"); + return 0; +} + +#else // PART == 1 + +static const char *my_other_global = "test\n\00abc"; + +void putstest() +{ + fputs(my_other_global, stderr); +} + +#endif // PART == 1 + +// CHECK-ODR: ERROR: AddressSanitizer: odr-violation +// CHECK-NO-ODR-NOT: ERROR: AddressSanitizer: odr-violation +// CHECK-NO-ODR: Done. diff --git a/test/asan/TestCases/Linux/abort_on_error.cc b/test/asan/TestCases/Linux/abort_on_error.cc index 67fa9b83e65d9..3f70613e4c7c1 100644 --- a/test/asan/TestCases/Linux/abort_on_error.cc +++ b/test/asan/TestCases/Linux/abort_on_error.cc @@ -9,6 +9,8 @@ // lit doesn't set ASAN_OPTIONS anyway. // RUN: not %run %t 2>&1 | FileCheck %s +// UNSUPPORTED: android + #include <stdlib.h> int main() { char *x = (char*)malloc(10 * sizeof(char)); diff --git a/test/asan/TestCases/Linux/auto_memory_profile_test.cc b/test/asan/TestCases/Linux/auto_memory_profile_test.cc new file mode 100644 index 0000000000000..3f8ad4673e756 --- /dev/null +++ b/test/asan/TestCases/Linux/auto_memory_profile_test.cc @@ -0,0 +1,32 @@ +// Tests heap_profile=1. +// Printing memory profiling only works in the configuration where we can +// detect leaks. +// REQUIRES: leak-detection +// +// RUN: %clangxx_asan %s -o %t +// RUN: %env_asan_opts=heap_profile=1 %run %t 2>&1 | FileCheck %s +#include <sanitizer/common_interface_defs.h> + +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +char *sink[1000]; + +int main() { + + for (int i = 0; i < 3; i++) { + const size_t kSize = 13000000; + char *x = new char[kSize]; + memset(x, 0, kSize); + sink[i] = x; + sleep(1); + } +} + +// CHECK: HEAP PROFILE at RSS +// CHECK: 13000000 byte(s) +// CHECK: HEAP PROFILE at RSS +// CHECK: 26000000 byte(s) +// CHECK: HEAP PROFILE at RSS +// CHECK: 39000000 byte(s) diff --git a/test/asan/TestCases/Linux/coverage_html_report.cc b/test/asan/TestCases/Linux/coverage_html_report.cc deleted file mode 100644 index 78fbfb3724030..0000000000000 --- a/test/asan/TestCases/Linux/coverage_html_report.cc +++ /dev/null @@ -1,24 +0,0 @@ -// REQUIRES: has_sancovcc, x86_64-linux, asan-dynamic-runtime -// RUN: %clangxx_asan_static -fsanitize-coverage=func %s -o %t -// RUN: rm -rf %T/coverage_html_report -// RUN: mkdir -p %T/coverage_html_report -// RUN: cd %T/coverage_html_report -// RUN: %env_asan_opts=coverage=1:verbosity=1:html_cov_report=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-main -// RUN: ls *.html | FileCheck %s --check-prefix=CHECK-ls -// RUN: rm -r %T/coverage_html_report - -#include <stdio.h> -#include <unistd.h> - -void bar() { printf("bar\n"); } - -int main(int argc, char **argv) { - fprintf(stderr, "PID: %d\n", getpid()); - bar(); - return 0; -} - -// CHECK-main: PID: [[PID:[0-9]+]] -// CHECK-main: [[PID]].sancov: 2 PCs written -// CHECK-main: coverage report generated to ./coverage_html_report.cc.tmp.[[PID]].html -// CHECK-ls: coverage_html_report.cc.tmp.{{[0-9]+}}.html diff --git a/test/asan/TestCases/Linux/cuda_test.cc b/test/asan/TestCases/Linux/cuda_test.cc new file mode 100644 index 0000000000000..e87f56b0c20e2 --- /dev/null +++ b/test/asan/TestCases/Linux/cuda_test.cc @@ -0,0 +1,37 @@ +// Emulate the behavior of the NVIDIA CUDA driver +// that mmaps memory inside the asan's shadow gap. +// +// REQUIRES: x86_64-target-arch +// +// RUN: %clangxx_asan %s -o %t +// RUN: not %env_asan_opts=protect_shadow_gap=1 %t 2>&1 | FileCheck %s --check-prefix=CHECK-PROTECT1 +// RUN: not %t 2>&1 | FileCheck %s --check-prefix=CHECK-PROTECT1 +// RUN: not %env_asan_opts=protect_shadow_gap=0 %t 2>&1 | FileCheck %s --check-prefix=CHECK-PROTECT0 +#include <assert.h> +#include <unistd.h> +#include <sys/mman.h> +#include <stdint.h> + +#include "sanitizer/asan_interface.h" + +int main(void) { + uintptr_t Base = 0x200000000; + uintptr_t Size = 0x1100000000; + void *addr = + mmap((void *)Base, Size, PROT_READ | PROT_WRITE, + MAP_NORESERVE | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, 0, 0); + assert(addr == (void*)Base); + // Make sure we can access memory in shadow gap. + // W/o protect_shadow_gap=0 we should fail here. + for (uintptr_t Addr = Base; Addr < Base + Size; Addr += Size / 100) + *(char*)Addr = 1; + // CHECK-PROTECT1: AddressSanitizer: SEGV on unknown address 0x0000bfff8000 + + // Poison a part of gap's shadow: + __asan_poison_memory_region((void*)Base, 4096); + // Now we should fail with use-after-poison. + *(char*)(Base + 1234) = 1; + // CHECK-PROTECT0: AddressSanitizer: use-after-poison on address 0x0002000004d2 +} + + diff --git a/test/asan/TestCases/Linux/local_alias.cc b/test/asan/TestCases/Linux/local_alias.cc index d941ff2f9171a..8c80f878594df 100644 --- a/test/asan/TestCases/Linux/local_alias.cc +++ b/test/asan/TestCases/Linux/local_alias.cc @@ -6,7 +6,10 @@ // // FIXME: https://github.com/google/sanitizers/issues/316 // XFAIL: android -// XFAIL: mips64 +// +// This test requires the integrated assembler to be the default. +// XFAIL: target-is-mips64 +// XFAIL: target-is-mips64el // // RUN: %clangxx_asan -DBUILD_INSTRUMENTED_DSO=1 -fPIC -shared -mllvm -asan-use-private-alias %s -o %t-INSTRUMENTED-SO.so // RUN: %clangxx -DBUILD_UNINSTRUMENTED_DSO=1 -fPIC -shared %s -o %t-UNINSTRUMENTED-SO.so diff --git a/test/asan/TestCases/Linux/malloc_delete_mismatch.cc b/test/asan/TestCases/Linux/malloc_delete_mismatch.cc index 66eed33052c3b..50d920e43f38f 100644 --- a/test/asan/TestCases/Linux/malloc_delete_mismatch.cc +++ b/test/asan/TestCases/Linux/malloc_delete_mismatch.cc @@ -12,8 +12,7 @@ // Also works if no malloc context is available. // RUN: %env_asan_opts=alloc_dealloc_mismatch=1:malloc_context_size=0:fast_unwind_on_malloc=0 not %run %t 2>&1 | FileCheck %s // RUN: %env_asan_opts=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 +// REQUIRES: stable-runtime #include <stdlib.h> static volatile char *x; diff --git a/test/asan/TestCases/Linux/memmem_test.cc b/test/asan/TestCases/Linux/memmem_test.cc index 54883004e0aa6..661381cdd7b7f 100644 --- a/test/asan/TestCases/Linux/memmem_test.cc +++ b/test/asan/TestCases/Linux/memmem_test.cc @@ -1,6 +1,6 @@ // RUN: %clangxx_asan %s -o %t -// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=A1 -// RUN: not %run %t 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=A2 +// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=A1 +// RUN: not %run %t 1 2>&1 | FileCheck %s --check-prefix=A2 // RUN: %env_asan_opts=intercept_memmem=0 %run %t #include <string.h> @@ -12,10 +12,13 @@ int main(int argc, char **argv) { res = memmem(a1, sizeof(a1) + 1, a2, sizeof(a2)); // BOOM else res = memmem(a1, sizeof(a1), a2, sizeof(a2) + 1); // BOOM - // CHECK: AddressSanitizer: stack-buffer-overflow - // CHECK: {{#0.*memmem}} - // CHECK: {{#1.*main}} + // A1: AddressSanitizer: stack-buffer-overflow + // A1: {{#0.*memmem}} + // A1-NEXT: {{#1.*main}} // A1: 'a1' <== Memory access at offset + // + // A2: AddressSanitizer: stack-buffer-overflow + // A2: {{#0.*memmem}} // A2: 'a2' <== Memory access at offset return res == NULL; } diff --git a/test/asan/TestCases/Linux/new_delete_mismatch.cc b/test/asan/TestCases/Linux/new_delete_mismatch.cc index 1cfc0ef053127..3a71862fb732e 100644 --- a/test/asan/TestCases/Linux/new_delete_mismatch.cc +++ b/test/asan/TestCases/Linux/new_delete_mismatch.cc @@ -1,8 +1,8 @@ // Check that we report new[] vs delete as alloc-dealloc-mismatch and not as // new-delete-type-mismatch when -fsized-deallocation is enabled. -// RUN: %clangxx_asan -g %s -o %t && not %run %t |& FileCheck %s -// RUN: %clangxx_asan -fsized-deallocation -g %s -o %t && not %run %t |& FileCheck %s +// RUN: %clangxx_asan -g %s -o %t && %env_asan_opts=alloc_dealloc_mismatch=1 not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -fsized-deallocation -g %s -o %t && %env_asan_opts=alloc_dealloc_mismatch=1 not %run %t 2>&1 | FileCheck %s #include <stdlib.h> diff --git a/test/asan/TestCases/Linux/odr-violation.cc b/test/asan/TestCases/Linux/odr-violation.cc index 143fb6e14344f..d909143a86a13 100644 --- a/test/asan/TestCases/Linux/odr-violation.cc +++ b/test/asan/TestCases/Linux/odr-violation.cc @@ -1,6 +1,9 @@ // FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=316 // XFAIL: android -// XFAIL: mips64 +// +// This test requires the integrated assembler to be the default. +// XFAIL: target-is-mips64 +// XFAIL: target-is-mips64el // // We use fast_unwind_on_malloc=0 to have full unwinding even w/o frame // pointers. This setting is not on by default because it's too expensive. diff --git a/test/asan/TestCases/Linux/print_memory_profile_test.cc b/test/asan/TestCases/Linux/print_memory_profile_test.cc index d30dbea1cf6d1..8909ccad08d46 100644 --- a/test/asan/TestCases/Linux/print_memory_profile_test.cc +++ b/test/asan/TestCases/Linux/print_memory_profile_test.cc @@ -3,27 +3,31 @@ // REQUIRES: leak-detection // // RUN: %clangxx_asan %s -o %t -// RUN: %run %t 2>&1 | FileCheck %s +// RUN: %run %t 100 2>&1 | FileCheck %s --check-prefix=CHECK-100 +// RUN: %run %t 50 2>&1 | FileCheck %s --check-prefix=CHECK-50 #include <sanitizer/common_interface_defs.h> #include <stdio.h> +#include <stdlib.h> char *sink[1000]; -int main() { +int main(int argc, char **argv) { + if (argc < 2) + return 1; + int idx = 0; for (int i = 0; i < 17; i++) sink[idx++] = new char[131000]; for (int i = 0; i < 28; i++) sink[idx++] = new char[24000]; - __sanitizer_print_memory_profile(100); - __sanitizer_print_memory_profile(50); + __sanitizer_print_memory_profile(atoi(argv[1])); } -// CHECK: Live Heap Allocations: {{.*}}; showing top 100% -// CHECK: 2227000 byte(s) ({{.*}}%) in 17 allocation(s) -// CHECK: 672000 byte(s) ({{.*}}%) in 28 allocation(s) -// CHECK: Live Heap Allocations: {{.*}}; showing top 50% -// CHECK: 2227000 byte(s) ({{.*}}%) in 17 allocation(s) -// CHECK-NOT: 1008 byte +// CHECK-100: Live Heap Allocations: {{.*}}; showing top 100% +// CHECK-100: 2227000 byte(s) ({{.*}}%) in 17 allocation(s) +// CHECK-100: 672000 byte(s) ({{.*}}%) in 28 allocation(s) +// CHECK-50: Live Heap Allocations: {{.*}}; showing top 50% +// CHECK-50: 2227000 byte(s) ({{.*}}%) in 17 allocation(s) +// CHECK-50-NOT: allocation diff --git a/test/asan/TestCases/Linux/pthread_create_from_constructor.cc b/test/asan/TestCases/Linux/pthread_create_from_constructor.cc new file mode 100644 index 0000000000000..8f9b0b4fed1a5 --- /dev/null +++ b/test/asan/TestCases/Linux/pthread_create_from_constructor.cc @@ -0,0 +1,49 @@ +// Test that ASan doesn't deadlock in __interceptor_pthread_create called +// from dlopened shared library constructor. The deadlock happens only in shared +// ASan runtime with recent Glibc (2.23 fits) when __interceptor_pthread_create +// grabs global Glibc's GL(dl_load_lock) and waits for tls_get_addr_tail that +// also tries to acquire it. +// +// RUN: %clangxx_asan -DBUILD_SO=1 -fPIC -shared %s -o %t-so.so +// RUN: %clangxx_asan %s -o %t +// RUN: %run %t 2>&1 + +// dlopen() can not be intercepted on Android +// UNSUPPORTED: android +// REQUIRES: x86-target-arch + +#ifdef BUILD_SO + +#include <stdio.h> +#include <pthread.h> +#include <unistd.h> + +void *threadFn(void *) { + fprintf(stderr, "thread started\n"); + while (true) { + usleep(100000); + } + return 0; +} + +void __attribute__((constructor)) startPolling() { + fprintf(stderr, "initializing library\n"); + pthread_t t; + pthread_create(&t, 0, &threadFn, 0); + fprintf(stderr, "done\n"); +} + +#else + +#include <dlfcn.h> +#include <stdlib.h> +#include <string> + +int main(int argc, char **argv) { + std::string path = std::string(argv[0]) + "-so.so"; + void *handle = dlopen(path.c_str(), RTLD_LAZY); + if (!handle) + abort(); + return 0; +} +#endif diff --git a/test/asan/TestCases/Linux/quarantine_size_mb.cc b/test/asan/TestCases/Linux/quarantine_size_mb.cc index cbacec22fa1ea..239eeabee1707 100644 --- a/test/asan/TestCases/Linux/quarantine_size_mb.cc +++ b/test/asan/TestCases/Linux/quarantine_size_mb.cc @@ -4,7 +4,7 @@ // RUN: %env_asan_opts=quarantine_size_mb=10:verbosity=1:hard_rss_limit_mb=50 %run %t 2>&1 | FileCheck %s --check-prefix=Q10 // RUN: %env_asan_opts=quarantine_size_mb=10:quarantine_size=20:verbosity=1 not %run %t 2>&1 | FileCheck %s --check-prefix=BOTH // RUN: %env_asan_opts=quarantine_size_mb=1000:hard_rss_limit_mb=50 not %run %t 2>&1 | FileCheck %s --check-prefix=RSS_LIMIT -// RUN: %env_asan_opts=hard_rss_limit_mb=50 not %run %t 2>&1 | FileCheck %s --check-prefix=RSS_LIMIT +// RUN: %env_asan_opts=hard_rss_limit_mb=20 not %run %t 2>&1 | FileCheck %s --check-prefix=RSS_LIMIT #include <string.h> char *g; diff --git a/test/asan/TestCases/Linux/release_to_os_test.cc b/test/asan/TestCases/Linux/release_to_os_test.cc new file mode 100644 index 0000000000000..26402167d6b11 --- /dev/null +++ b/test/asan/TestCases/Linux/release_to_os_test.cc @@ -0,0 +1,46 @@ +// Tests ASAN_OPTIONS=allocator_release_to_os=1 +// + +// RUN: %clangxx_asan -std=c++11 %s -o %t +// RUN: %env_asan_opts=allocator_release_to_os_interval_ms=0 %run %t 2>&1 | FileCheck %s --check-prefix=RELEASE +// RUN: %env_asan_opts=allocator_release_to_os_interval_ms=-1 %run %t 2>&1 | FileCheck %s --check-prefix=NO_RELEASE +// +// REQUIRES: x86_64-target-arch +#include <stdlib.h> +#include <stdio.h> +#include <algorithm> +#include <stdint.h> +#include <assert.h> + +#include <sanitizer/asan_interface.h> + +void MallocReleaseStress() { + const size_t kNumChunks = 10000; + const size_t kAllocSize = 100; + const size_t kNumIter = 100; + uintptr_t *chunks[kNumChunks] = {0}; + + for (size_t iter = 0; iter < kNumIter; iter++) { + std::random_shuffle(chunks, chunks + kNumChunks); + size_t to_replace = rand() % kNumChunks; + for (size_t i = 0; i < kNumChunks; i++) { + if (chunks[i]) + assert(chunks[i][0] == (uintptr_t)chunks[i]); + if (i < to_replace) { + delete [] chunks[i]; + chunks[i] = new uintptr_t[kAllocSize]; + chunks[i][0] = (uintptr_t)chunks[i]; + } + } + } + for (auto p : chunks) + delete[] p; +} + +int main() { + MallocReleaseStress(); + __asan_print_accumulated_stats(); +} + +// RELEASE: mapped:{{.*}}releases: {{[1-9]}} +// NO_RELEASE: mapped:{{.*}}releases: 0 diff --git a/test/asan/TestCases/Linux/stack-trace-dlclose.cc b/test/asan/TestCases/Linux/stack-trace-dlclose.cc index 49c2089780108..e604f1e4f73f6 100644 --- a/test/asan/TestCases/Linux/stack-trace-dlclose.cc +++ b/test/asan/TestCases/Linux/stack-trace-dlclose.cc @@ -4,8 +4,7 @@ // RUN: %clangxx_asan -DSHARED %s -shared -o %T/stack_trace_dlclose.so -fPIC // RUN: %clangxx_asan -DSO_DIR=\"%T\" %s %libdl -o %t // RUN: %env_asan_opts=exitcode=0 %run %t 2>&1 | FileCheck %s -// XFAIL: arm-linux-gnueabi -// XFAIL: armv7l-unknown-linux-gnueabihf +// REQUIRES: stable-runtime #include <assert.h> #include <dlfcn.h> diff --git a/test/asan/TestCases/Linux/swapcontext_annotation.cc b/test/asan/TestCases/Linux/swapcontext_annotation.cc index 90aabaee205bb..56e811942b880 100644 --- a/test/asan/TestCases/Linux/swapcontext_annotation.cc +++ b/test/asan/TestCases/Linux/swapcontext_annotation.cc @@ -1,12 +1,17 @@ // Check that ASan plays well with annotated makecontext/swapcontext. -// RUN: %clangxx_asan -lpthread -O0 %s -o %t && %run %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -lpthread -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -lpthread -O2 %s -o %t && %run %t 2>&1 | FileCheck %s -// RUN: %clangxx_asan -lpthread -O3 %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -std=c++11 -lpthread -O0 %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -std=c++11 -lpthread -O1 %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -std=c++11 -lpthread -O2 %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -std=c++11 -lpthread -O3 %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -std=c++11 -lpthread -O0 %s -o %t && %run %t 2>&1 | FileCheck <( seq 60 | xargs -i -- grep LOOPCHECK %s ) --check-prefix LOOPCHECK +// RUN: %clangxx_asan -std=c++11 -lpthread -O1 %s -o %t && %run %t 2>&1 | FileCheck <( seq 60 | xargs -i -- grep LOOPCHECK %s ) --check-prefix LOOPCHECK +// RUN: %clangxx_asan -std=c++11 -lpthread -O2 %s -o %t && %run %t 2>&1 | FileCheck <( seq 60 | xargs -i -- grep LOOPCHECK %s ) --check-prefix LOOPCHECK +// RUN: %clangxx_asan -std=c++11 -lpthread -O3 %s -o %t && %run %t 2>&1 | FileCheck <( seq 60 | xargs -i -- grep LOOPCHECK %s ) --check-prefix LOOPCHECK + // // This test is too subtle to try on non-x86 arch for now. -// REQUIRES: x86_64-supported-target,i386-supported-target +// REQUIRES: x86-target-arch #include <pthread.h> #include <setjmp.h> @@ -25,9 +30,12 @@ char *next_child_stack; const int kStackSize = 1 << 20; -void *main_thread_stack; +const void *main_thread_stack; size_t main_thread_stacksize; +const void *from_stack; +size_t from_stacksize; + __attribute__((noinline, noreturn)) void LongJump(jmp_buf env) { longjmp(env, 1); _exit(1); @@ -44,14 +52,18 @@ __attribute__((noinline)) void CallNoReturn() { void NextChild() { CallNoReturn(); - __sanitizer_finish_switch_fiber(); + __sanitizer_finish_switch_fiber(nullptr, &from_stack, &from_stacksize); + + printf("NextChild from: %p %zu\n", from_stack, from_stacksize); char x[32] = {0}; // Stack gets poisoned. printf("NextChild: %p\n", x); CallNoReturn(); - __sanitizer_start_switch_fiber(main_thread_stack, main_thread_stacksize); + __sanitizer_start_switch_fiber(nullptr, + main_thread_stack, + main_thread_stacksize); CallNoReturn(); if (swapcontext(&next_child_context, &orig_context) < 0) { perror("swapcontext"); @@ -61,7 +73,9 @@ void NextChild() { void Child(int mode) { CallNoReturn(); - __sanitizer_finish_switch_fiber(); + __sanitizer_finish_switch_fiber(nullptr, + &main_thread_stack, + &main_thread_stacksize); char x[32] = {0}; // Stack gets poisoned. printf("Child: %p\n", x); CallNoReturn(); @@ -70,21 +84,28 @@ void Child(int mode) { // something. // (c) Jump to another function which will then jump back to the main function if (mode == 0) { - __sanitizer_start_switch_fiber(main_thread_stack, main_thread_stacksize); + __sanitizer_start_switch_fiber(nullptr, + main_thread_stack, + main_thread_stacksize); CallNoReturn(); } else if (mode == 1) { - __sanitizer_start_switch_fiber(main_thread_stack, main_thread_stacksize); + __sanitizer_start_switch_fiber(nullptr, + main_thread_stack, + main_thread_stacksize); CallNoReturn(); if (swapcontext(&child_context, &orig_context) < 0) { perror("swapcontext"); _exit(1); } } else if (mode == 2) { + printf("NextChild stack: %p\n", next_child_stack); + getcontext(&next_child_context); next_child_context.uc_stack.ss_sp = next_child_stack; next_child_context.uc_stack.ss_size = kStackSize / 2; makecontext(&next_child_context, (void (*)())NextChild, 0); - __sanitizer_start_switch_fiber(next_child_context.uc_stack.ss_sp, + __sanitizer_start_switch_fiber(nullptr, + next_child_context.uc_stack.ss_sp, next_child_context.uc_stack.ss_size); CallNoReturn(); if (swapcontext(&child_context, &next_child_context) < 0) { @@ -105,7 +126,9 @@ int Run(int arg, int mode, char *child_stack) { } makecontext(&child_context, (void (*)())Child, 1, mode); CallNoReturn(); - __sanitizer_start_switch_fiber(child_context.uc_stack.ss_sp, + void* fake_stack_save; + __sanitizer_start_switch_fiber(&fake_stack_save, + child_context.uc_stack.ss_sp, child_context.uc_stack.ss_size); CallNoReturn(); if (swapcontext(&orig_context, &child_context) < 0) { @@ -113,8 +136,11 @@ int Run(int arg, int mode, char *child_stack) { _exit(1); } CallNoReturn(); - __sanitizer_finish_switch_fiber(); + __sanitizer_finish_switch_fiber(fake_stack_save, + &from_stack, + &from_stacksize); CallNoReturn(); + printf("Main context from: %p %zu\n", from_stack, from_stacksize); // Touch childs's stack to make sure it's unpoisoned. for (int i = 0; i < kStackSize; i++) { @@ -125,17 +151,7 @@ int Run(int arg, int mode, char *child_stack) { void handler(int sig) { CallNoReturn(); } -void InitStackBounds() { - pthread_attr_t attr; - pthread_attr_init(&attr); - pthread_getattr_np(pthread_self(), &attr); - pthread_attr_getstack(&attr, &main_thread_stack, &main_thread_stacksize); - pthread_attr_destroy(&attr); -} - int main(int argc, char **argv) { - InitStackBounds(); - // set up a signal that will spam and trigger __asan_handle_no_return at // tricky moments struct sigaction act = {}; @@ -162,12 +178,22 @@ int main(int argc, char **argv) { // CHECK-NOT: ASan is ignoring requested __asan_handle_no_return for (unsigned int i = 0; i < 30; ++i) { ret += Run(argc - 1, 0, stack); + // LOOPCHECK: Child stack: [[CHILD_STACK:0x[0-9a-f]*]] + // LOOPCHECK: Main context from: [[CHILD_STACK]] 524288 ret += Run(argc - 1, 1, stack); + // LOOPCHECK: Child stack: [[CHILD_STACK:0x[0-9a-f]*]] + // LOOPCHECK: Main context from: [[CHILD_STACK]] 524288 ret += Run(argc - 1, 2, stack); + // LOOPCHECK: Child stack: [[CHILD_STACK:0x[0-9a-f]*]] + // LOOPCHECK: NextChild stack: [[NEXT_CHILD_STACK:0x[0-9a-f]*]] + // LOOPCHECK: NextChild from: [[CHILD_STACK]] 524288 + // LOOPCHECK: Main context from: [[NEXT_CHILD_STACK]] 524288 ret += Run(argc - 1, 0, heap); ret += Run(argc - 1, 1, heap); ret += Run(argc - 1, 2, heap); + printf("Iteration %d passed\n", i); } + // CHECK: Test passed printf("Test passed\n"); diff --git a/test/asan/TestCases/Linux/thread_local_quarantine_size_kb.cc b/test/asan/TestCases/Linux/thread_local_quarantine_size_kb.cc new file mode 100644 index 0000000000000..7176484ed21ce --- /dev/null +++ b/test/asan/TestCases/Linux/thread_local_quarantine_size_kb.cc @@ -0,0 +1,40 @@ +// Test thread_local_quarantine_size_kb + +// RUN: %clangxx_asan %s -o %t +// RUN: %env_asan_opts=thread_local_quarantine_size_kb=256:verbosity=1 %run %t 2>&1 | \ +// RUN: FileCheck %s --check-prefix=CHECK-VALUE +// RUN: %env_asan_opts=thread_local_quarantine_size_kb=64:quarantine_size_mb=64 %run %t 2>&1 | \ +// RUN: FileCheck %s --allow-empty --check-prefix=CHECK-SMALL-LOCAL-CACHE-SMALL-OVERHEAD +// RUN: %env_asan_opts=thread_local_quarantine_size_kb=0:quarantine_size_mb=64 %run %t 2>&1 | \ +// RUN: FileCheck %s --check-prefix=CHECK-NO-LOCAL-CACHE-HUGE-OVERHEAD + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sanitizer/allocator_interface.h> + +// The idea is allocate a lot of small blocks, totaling 5Mb of user memory +// total, and verify that quarantine does not incur too much memory overhead. +// There's always an overhead for red zones, shadow memory and such, but +// quarantine accounting should not significantly contribute to that. +static const int kNumAllocs = 20000; +static const int kAllocSize = 256; +static const size_t kHeapSizeLimit = 12 << 20; + +int main() { + size_t old_heap_size = __sanitizer_get_heap_size(); + for (int i = 0; i < kNumAllocs; i++) { + char *g = new char[kAllocSize]; + memset(g, -1, kAllocSize); + delete [] (g); + } + size_t new_heap_size = __sanitizer_get_heap_size(); + fprintf(stderr, "heap size: new: %zd old: %zd\n", new_heap_size, + old_heap_size); + if (new_heap_size - old_heap_size > kHeapSizeLimit) + fprintf(stderr, "Heap size limit exceeded"); +} + +// CHECK-VALUE: thread_local_quarantine_size_kb=256K +// CHECK-SMALL-LOCAL-CACHE-SMALL-OVERHEAD-NOT: Heap size limit exceeded +// CHECK-NO-LOCAL-CACHE-HUGE-OVERHEAD: Heap size limit exceeded diff --git a/test/asan/TestCases/Posix/asan-symbolize-sanity-test.cc b/test/asan/TestCases/Posix/asan-symbolize-sanity-test.cc index dd59e4a60774a..cb9ca53e8a9af 100644 --- a/test/asan/TestCases/Posix/asan-symbolize-sanity-test.cc +++ b/test/asan/TestCases/Posix/asan-symbolize-sanity-test.cc @@ -7,8 +7,8 @@ // RUN: %clangxx_asan -O0 -DSHARED_LIB %s -fPIC -shared -o %t-so.so // RUN: %clangxx_asan -O0 %s %libdl -o %t // RUN: %env_asan_opts=symbolize=0 not %run %t 2>&1 | %asan_symbolize | FileCheck %s -// XFAIL: arm-linux-gnueabi -// XFAIL: armv7l-unknown-linux-gnueabihf +// UNSUPPORTED: x86_64h-darwin,x86_64-darwin +// REQUIRES: stable-runtime #if !defined(SHARED_LIB) #include <dlfcn.h> diff --git a/test/asan/TestCases/Posix/coverage-fork.cc b/test/asan/TestCases/Posix/coverage-fork.cc index 799d71638a26e..40ce72ef5003b 100644 --- a/test/asan/TestCases/Posix/coverage-fork.cc +++ b/test/asan/TestCases/Posix/coverage-fork.cc @@ -3,7 +3,7 @@ // RUN: mkdir -p %T/coverage-fork && cd %T/coverage-fork // RUN: %env_asan_opts=coverage=1:coverage_direct=0:verbosity=1 %run %t 2>&1 | FileCheck %s // -// XFAIL: android +// UNSUPPORTED: android #include <stdio.h> #include <string.h> diff --git a/test/asan/TestCases/Posix/halt_on_error-signals.c b/test/asan/TestCases/Posix/halt_on_error-signals.c index 60916f6570fcb..6bdf30bb4dd3e 100644 --- a/test/asan/TestCases/Posix/halt_on_error-signals.c +++ b/test/asan/TestCases/Posix/halt_on_error-signals.c @@ -3,7 +3,7 @@ // RUN: %clang_asan -fsanitize-recover=address -pthread %s -o %t // // RUN: rm -f %t.log -// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false %run %t 100 >%t.log 2>&1 || true +// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false %run %t 100 >>%t.log 2>&1 || true // Collision will almost always get triggered but we still need to check the unlikely case: // RUN: FileCheck --check-prefix=CHECK-COLLISION %s < %t.log || FileCheck --check-prefix=CHECK-NO-COLLISION %s < %t.log diff --git a/test/asan/TestCases/Posix/halt_on_error-torture.cc b/test/asan/TestCases/Posix/halt_on_error-torture.cc index d3af1d0277035..5d7eff06e34e6 100644 --- a/test/asan/TestCases/Posix/halt_on_error-torture.cc +++ b/test/asan/TestCases/Posix/halt_on_error-torture.cc @@ -2,18 +2,21 @@ // // RUN: %clangxx_asan -fsanitize-recover=address -pthread %s -o %t // -// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false %run %t 1 10 >1.txt 2>&1 +// RUN: rm -f 1.txt +// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false %run %t 1 10 >>1.txt 2>&1 // RUN: FileCheck %s < 1.txt // RUN: [ $(grep -c 'ERROR: AddressSanitizer: use-after-poison' 1.txt) -eq 10 ] // RUN: FileCheck --check-prefix=CHECK-NO-COLLISION %s < 1.txt // // Collisions are unlikely but still possible so we need the ||. -// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false %run %t 10 20 >10.txt 2>&1 || true +// RUN: rm -f 10.txt +// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false %run %t 10 20 >>10.txt 2>&1 || true // RUN: FileCheck --check-prefix=CHECK-COLLISION %s < 10.txt || FileCheck --check-prefix=CHECK-NO-COLLISION %s < 10.txt // // Collisions are unlikely but still possible so we need the ||. -// RUN: %env_asan_opts=halt_on_error=false %run %t 10 20 >10.txt 2>&1 || true -// RUN: FileCheck --check-prefix=CHECK-COLLISION %s < 10.txt || FileCheck --check-prefix=CHECK-NO-COLLISION %s < 10.txt +// RUN: rm -f 20.txt +// RUN: %env_asan_opts=halt_on_error=false %run %t 10 20 >>20.txt 2>&1 || true +// RUN: FileCheck --check-prefix=CHECK-COLLISION %s < 20.txt || FileCheck --check-prefix=CHECK-NO-COLLISION %s < 20.txt #include <stdio.h> #include <stdlib.h> diff --git a/test/asan/TestCases/Posix/halt_on_error_suppress_equal_pcs.cc b/test/asan/TestCases/Posix/halt_on_error_suppress_equal_pcs.cc index 98b034812ef63..98ef851657b7d 100644 --- a/test/asan/TestCases/Posix/halt_on_error_suppress_equal_pcs.cc +++ b/test/asan/TestCases/Posix/halt_on_error_suppress_equal_pcs.cc @@ -6,14 +6,16 @@ // RUN: %env_asan_opts=halt_on_error=false %run %t 2>&1 | FileCheck %s // // Check that we die after reaching different reports number threshold. -// RUN: %env_asan_opts=halt_on_error=false not %run %t 1 > %t1.log 2>&1 +// RUN: rm -f %t1.log +// RUN: %env_asan_opts=halt_on_error=false not %run %t 1 >> %t1.log 2>&1 // RUN: [ $(grep -c 'ERROR: AddressSanitizer: stack-buffer-overflow' %t1.log) -eq 25 ] // // Check suppress_equal_pcs=true behavior is equal to default one. // RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=true %run %t 2>&1 | FileCheck %s // // Check suppress_equal_pcs=false behavior isn't equal to default one. -// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false %run %t > %t2.log 2>&1 +// RUN: rm -f %t2.log +// RUN: %env_asan_opts=halt_on_error=false:suppress_equal_pcs=false %run %t >> %t2.log 2>&1 // RUN: [ $(grep -c 'ERROR: AddressSanitizer: stack-buffer-overflow' %t2.log) -eq 30 ] #define ACCESS_ARRAY_FIVE_ELEMENTS(array, i) \ diff --git a/test/asan/TestCases/Posix/handle_abort_on_error.cc b/test/asan/TestCases/Posix/handle_abort_on_error.cc new file mode 100644 index 0000000000000..fa8cdd4ce0c86 --- /dev/null +++ b/test/asan/TestCases/Posix/handle_abort_on_error.cc @@ -0,0 +1,9 @@ +// Regression test: this used to abort() in SIGABRT handler in an infinite loop. +// RUN: %clangxx_asan -O0 %s -o %t && %env_asan_opts=handle_abort=1,abort_on_error=1 not --crash %run %t 2>&1 | FileCheck %s + +#include <stdlib.h> + +int main() { + abort(); + // CHECK: ERROR: AddressSanitizer: ABRT +} diff --git a/test/asan/TestCases/no_asan_gen_globals.c b/test/asan/TestCases/Posix/no_asan_gen_globals.c index 2b13deace4b5f..c686f83ac4a89 100644 --- a/test/asan/TestCases/no_asan_gen_globals.c +++ b/test/asan/TestCases/Posix/no_asan_gen_globals.c @@ -2,7 +2,6 @@ // XFAIL: android // FIXME: http://llvm.org/bugs/show_bug.cgi?id=22682 // REQUIRES: asan-64-bits -// // Make sure __asan_gen_* strings do not end up in the symbol table. // RUN: %clang_asan %s -o %t.exe diff --git a/test/asan/TestCases/Posix/start-deactivated.cc b/test/asan/TestCases/Posix/start-deactivated.cc index 187ee5e549efe..9691404ebcea9 100644 --- a/test/asan/TestCases/Posix/start-deactivated.cc +++ b/test/asan/TestCases/Posix/start-deactivated.cc @@ -2,8 +2,8 @@ // Main executable is uninstrumented, but linked to ASan runtime. The shared // library is instrumented. Memory errors before dlopen are not detected. -// RUN: %clangxx_asan -O0 -DSHARED_LIB %s -fPIC -shared -o %t-so.so -// RUN: %clangxx -O0 %s -c -o %t.o +// RUN: %clangxx_asan -O0 -DSHARED_LIB %s -std=c++11 -fPIC -shared -o %t-so.so +// RUN: %clangxx -O0 %s -std=c++11 -c -o %t.o // RUN: %clangxx_asan -O0 %t.o %libdl -o %t // RUN: %env_asan_opts=start_deactivated=1,allocator_may_return_null=0 \ // RUN: ASAN_ACTIVATION_OPTIONS=allocator_may_return_null=1 not %run %t 2>&1 | FileCheck %s @@ -32,18 +32,25 @@ #include "sanitizer/asan_interface.h" -void test_malloc_shadow() { - char *p = (char *)malloc(100); - char *q = (char *)__asan_region_is_poisoned(p + 95, 8); - fprintf(stderr, "=%zd=\n", q ? q - (p + 95) : -1); - free(p); +constexpr unsigned nPtrs = 200; +char *ptrs[nPtrs]; + +void test_malloc_shadow(char *p, size_t sz, bool expect_redzones) { + assert((char *)__asan_region_is_poisoned(p - 1, sz + 1) == + (expect_redzones ? p - 1 : nullptr)); + assert((char *)__asan_region_is_poisoned(p, sz) == nullptr); + assert((char *)__asan_region_is_poisoned(p, sz + 1) == + (expect_redzones ? p + sz : nullptr)); } typedef void (*Fn)(); int main(int argc, char *argv[]) { - test_malloc_shadow(); - // CHECK: =-1= + // Before activation: no redzones. + for (size_t sz = 1; sz < nPtrs; ++sz) { + ptrs[sz] = (char *)malloc(sz); + test_malloc_shadow(ptrs[sz], sz, false); + } std::string path = std::string(argv[0]) + "-so.so"; void *dso = dlopen(path.c_str(), RTLD_NOW); @@ -52,9 +59,6 @@ int main(int argc, char *argv[]) { return 1; } - test_malloc_shadow(); - // CHECK: =5= - // After this line ASan is activated and starts detecting errors. void *fn = dlsym(dso, "do_another_bad_thing"); if (!fn) { @@ -62,6 +66,19 @@ int main(int argc, char *argv[]) { return 1; } + // After activation: redzones. + { + char *p = (char *)malloc(100); + test_malloc_shadow(p, 100, true); + free(p); + } + + // Pre-existing allocations got redzones, too. + for (size_t sz = 1; sz < nPtrs; ++sz) { + test_malloc_shadow(ptrs[sz], sz, true); + free(ptrs[sz]); + } + // Test that ASAN_ACTIVATION_OPTIONS=allocator_may_return_null=1 has effect. void *p = malloc((unsigned long)-2); assert(!p); diff --git a/test/asan/TestCases/Windows/bind_io_completion_callback.cc b/test/asan/TestCases/Windows/bind_io_completion_callback.cc index 44b92ab914655..ef7e45867ede0 100644 --- a/test/asan/TestCases/Windows/bind_io_completion_callback.cc +++ b/test/asan/TestCases/Windows/bind_io_completion_callback.cc @@ -1,11 +1,6 @@ // Make sure we can throw exceptions from work items executed via // BindIoCompletionCallback. // -// Clang doesn't support exceptions on Windows yet, so for the time being we -// build this program in two parts: the code with exceptions is built with CL, -// the rest is built with Clang. This represents the typical scenario when we -// build a large project using "clang-cl -fallback -fsanitize=address". -// // RUN: %clangxx_asan %s -o %t.exe // RUN: %run %t.exe 2>&1 | FileCheck %s diff --git a/test/asan/TestCases/Windows/coverage-dll-stdio.cc b/test/asan/TestCases/Windows/coverage-dll-stdio.cc new file mode 100644 index 0000000000000..5e12e38554499 --- /dev/null +++ b/test/asan/TestCases/Windows/coverage-dll-stdio.cc @@ -0,0 +1,16 @@ +// Test that coverage and MSVC CRT stdio work from a DLL. This ensures that the +// __local_stdio_printf_options function isn't instrumented for coverage. + +// RUN: rm -rf %t && mkdir %t && cd %t +// RUN: %clang_cl_asan -fsanitize-coverage=func -O0 %p/dll_host.cc -Fet.exe +// RUN: %clang_cl_asan -fsanitize-coverage=func -LD -O0 %s -Fet.dll +// RUN: %run ./t.exe t.dll 2>&1 | FileCheck %s + +#include <stdio.h> + +extern "C" __declspec(dllexport) +int test_function() { + printf("hello world\n"); + // CHECK: hello world + return 0; +} diff --git a/test/asan/TestCases/Windows/default_options.cc b/test/asan/TestCases/Windows/default_options.cc deleted file mode 100644 index 6e0a28f336926..0000000000000 --- a/test/asan/TestCases/Windows/default_options.cc +++ /dev/null @@ -1,18 +0,0 @@ -// RUN: %clangxx_asan -O2 %s -o %t -// RUN: %run %t 2>&1 | FileCheck %s - -// FIXME: merge this with the common default_options test when we can run common -// tests on Windows. - -const char *kAsanDefaultOptions="verbosity=1 help=1"; - -extern "C" -__attribute__((no_sanitize_address)) -const char *__asan_default_options() { - // CHECK: Available flags for AddressSanitizer: - return kAsanDefaultOptions; -} - -int main() { - return 0; -} diff --git a/test/asan/TestCases/Windows/delay_dbghelp.cc b/test/asan/TestCases/Windows/delay_dbghelp.cc new file mode 100644 index 0000000000000..81cd2d389c3b4 --- /dev/null +++ b/test/asan/TestCases/Windows/delay_dbghelp.cc @@ -0,0 +1,18 @@ +// Build an executable with ASan, then extract the DLLs that it depends on. +// RUN: %clang_cl_asan %s -Fe%t.exe +// RUN: llvm-readobj -coff-imports %t.exe | grep Name: | sed -e 's/ *Name: *//' > %t +// +// Make sure the binary doesn't depend on dbghelp directly. +// RUN: not grep dbghelp.dll %t +// +// Make sure any clang_rt DLLs it depends on don't depend on dbghelp. In the +// static build, there won't be any clang_rt DLLs. +// RUN: not grep cl""ang_rt %t || \ +// RUN: grep cl""ang_rt %t | xargs which | \ +// RUN: xargs llvm-readobj -coff-imports | not grep dbghelp.dll %t + +extern "C" int puts(const char *); + +int main() { + puts("main"); +} diff --git a/test/asan/TestCases/Windows/dll_global_dead_strip.c b/test/asan/TestCases/Windows/dll_global_dead_strip.c new file mode 100644 index 0000000000000..2664f5baff6c0 --- /dev/null +++ b/test/asan/TestCases/Windows/dll_global_dead_strip.c @@ -0,0 +1,28 @@ +// RUN: %clang_cl_asan -O0 %p/dll_host.cc -Fe%t +// +// RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll +// RUN: %env_asan_opts=report_globals=2 %run %t %t.dll 2>&1 | FileCheck %s --check-prefix=NOSTRIP +// RUN: %clang_cl_asan -LD -O2 %s -Fe%t.dll -link -opt:ref +// RUN: %env_asan_opts=report_globals=2 %run %t %t.dll 2>&1 | FileCheck %s --check-prefix=STRIP + +#include <stdio.h> + +int dead_global = 42; +int live_global = 0; + +__declspec(dllexport) +int test_function() { + puts("main"); + return live_global; +} + +// Check that our global registration scheme works with MSVC's linker dead +// stripping (/OPT:REF). + +// NOSTRIP: Added Global{{.*}}name=dead_global +// NOSTRIP: Added Global{{.*}}name=live_global +// NOSTRIP: main + +// STRIP-NOT: Added Global{{.*}}name=dead_global +// STRIP: Added Global{{.*}}name=live_global +// STRIP: main diff --git a/test/asan/TestCases/Windows/dll_host.cc b/test/asan/TestCases/Windows/dll_host.cc index 71721fe29e888..6a029c96d4d8c 100644 --- a/test/asan/TestCases/Windows/dll_host.cc +++ b/test/asan/TestCases/Windows/dll_host.cc @@ -5,20 +5,41 @@ // RUN: %clang_cl_asan -O0 %s -Fe%t // // Get the list of ASan wrappers exported by the main module RTL: -// RUN: dumpbin /EXPORTS %t | grep -o "__asan_wrap[^ ]*" | grep -v @ | sort | uniq > %t.exported_wrappers +// note: The mangling decoration (i.e. @4 )is removed because calling convention +// differ from 32-bit and 64-bit. +// RUN: dumpbin /EXPORTS %t | grep -o "__asan_wrap[^ ]*" | sed -e s/@.*// > %t.exported_wrappers1 // FIXME: we should really check the other __asan exports too. -// RUN: dumpbin /EXPORTS %t | grep -o "__sanitizer_[^ ]*" | grep -v @ | sort | uniq >> %t.exported_wrappers +// RUN: dumpbin /EXPORTS %t | grep -o "__sanitizer_[^ ]*" | sed -e s/@.*// > %t.exported_wrappers2 // // Get the list of ASan wrappers imported by the DLL RTL: // [BEWARE: be really careful with the sed commands, as this test can be run // from different environemnts with different shells and seds] -// RUN: grep INTERCEPT_LIBRARY_FUNCTION %p/../../../../lib/asan/asan_win_dll_thunk.cc | grep -v define | sed -e s/.*(/__asan_wrap_/ | sed -e s/).*// | sort | uniq > %t.dll_imports -// RUN: grep "^INTERFACE_FUNCTION.*sanitizer" %p/../../../../lib/asan/asan_win_dll_thunk.cc | grep -v define | sed -e s/.*(// | sed -e s/).*// | sort | uniq >> %t.dll_imports +// RUN: grep INTERCEPT_LIBRARY_FUNCTION %p/../../../../lib/asan/asan_win_dll_thunk.cc | grep -v define | sed -e s/.*(/__asan_wrap_/ | sed -e s/).*// > %t.dll_imports1 +// RUN: grep "^INTERFACE_FUNCTION.*sanitizer" %p/../../../../lib/asan/asan_win_dll_thunk.cc | grep -v define | sed -e s/.*(// | sed -e s/).*// > %t.dll_imports2 +// +// Add functions interecepted in asan_malloc.win.cc and asan_win.cc. +// RUN: grep '[I]MPORT:' %s | sed -e 's/.*[I]MPORT: //' > %t.dll_imports3 +// IMPORT: __asan_wrap_HeapAlloc +// IMPORT: __asan_wrap_HeapFree +// IMPORT: __asan_wrap_HeapReAlloc +// IMPORT: __asan_wrap_HeapSize +// IMPORT: __asan_wrap_CreateThread +// IMPORT: __asan_wrap_RaiseException +// IMPORT: __asan_wrap_RtlRaiseException +// +// The exception handlers differ in 32-bit and 64-bit, so we ignore them: +// RUN: grep '[E]XPORT:' %s | sed -e 's/.*[E]XPORT: //' > %t.exported_wrappers3 +// EXPORT: __asan_wrap__except_handler3 +// EXPORT: __asan_wrap__except_handler4 +// EXPORT: __asan_wrap___C_specific_handler +// +// RUN: cat %t.dll_imports1 %t.dll_imports2 %t.dll_imports3 | sort | uniq > %t.dll_imports-sorted +// RUN: cat %t.exported_wrappers1 %t.exported_wrappers2 %t.exported_wrappers3 | sort | uniq > %t.exported_wrappers-sorted // // Now make sure the DLL thunk imports everything: // RUN: echo // RUN: echo "=== NOTE === If you see a mismatch below, please update asan_win_dll_thunk.cc" -// RUN: diff %t.dll_imports %t.exported_wrappers +// RUN: diff %t.dll_imports-sorted %t.exported_wrappers-sorted // REQUIRES: asan-static-runtime #include <stdio.h> diff --git a/test/asan/TestCases/Windows/dll_intercept_memchr.cc b/test/asan/TestCases/Windows/dll_intercept_memchr.cc index 1435bdc50127e..4f794a212706a 100644 --- a/test/asan/TestCases/Windows/dll_intercept_memchr.cc +++ b/test/asan/TestCases/Windows/dll_intercept_memchr.cc @@ -2,6 +2,12 @@ // RUN: %clang_cl_asan -LD -O0 %s -Fe%t.dll // RUN: not %run %t %t.dll 2>&1 | FileCheck %s +// On windows 64-bit, the memchr function is written in assembly and is not +// hookable with the interception library. There is not enough padding before +// the function and there is a short jump on the second instruction which +// doesn't not allow enough space to encode a 64-bit indirect jump. +// UNSUPPORTED: x86_64-windows + #include <string.h> extern "C" __declspec(dllexport) diff --git a/test/asan/TestCases/Windows/dll_intercept_memcpy_indirect.cc b/test/asan/TestCases/Windows/dll_intercept_memcpy_indirect.cc index c5f44df3faaf5..4e28905923cc2 100644 --- a/test/asan/TestCases/Windows/dll_intercept_memcpy_indirect.cc +++ b/test/asan/TestCases/Windows/dll_intercept_memcpy_indirect.cc @@ -24,7 +24,7 @@ int test_function() { call_memcpy(&memcpy, buff2, buff1, 6); // CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] // CHECK: WRITE of size 6 at [[ADDR]] thread T0 -// CHECK-NEXT: __asan_{{.*}}memcpy +// CHECK-NEXT: __asan_{{.*}}mem{{.*}} // CHECK-NEXT: call_memcpy // CHECK-NEXT: test_function {{.*}}dll_intercept_memcpy_indirect.cc:[[@LINE-5]] // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame diff --git a/test/asan/TestCases/Windows/dll_operator_array_new_with_dtor_left_oob.cc b/test/asan/TestCases/Windows/dll_operator_array_new_with_dtor_left_oob.cc index 8306a737bfffa..b514c994c1dfe 100644 --- a/test/asan/TestCases/Windows/dll_operator_array_new_with_dtor_left_oob.cc +++ b/test/asan/TestCases/Windows/dll_operator_array_new_with_dtor_left_oob.cc @@ -10,7 +10,7 @@ struct C { extern "C" __declspec(dllexport) int test_function() { C *buffer = new C[42]; - buffer[-2].x = 42; + buffer[-(1 + sizeof(void*) / 4)].x = 42; // CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] // CHECK: WRITE of size 4 at [[ADDR]] thread T0 // CHECK-NEXT: test_function {{.*}}dll_operator_array_new_with_dtor_left_oob.cc:[[@LINE-3]] @@ -19,7 +19,7 @@ int test_function() { // FIXME: Currently it says "4 bytes ... left of 172-byte region", // should be "8 bytes ... left of 168-byte region", see // https://code.google.com/p/address-sanitizer/issues/detail?id=314 -// CHECK: [[ADDR]] is located {{.*}} bytes to the left of 172-byte region +// CHECK: [[ADDR]] is located {{.*}} bytes to the left of {{(172|176)}}-byte region // FIXME: Should get rid of the malloc/free frames called from the inside of // operator new/delete in DLLs when using -MT CRT. // FIXME: The operator new frame should have []. diff --git a/test/asan/TestCases/Windows/free_hook_realloc.cc b/test/asan/TestCases/Windows/free_hook_realloc.cc index 297218bf8e99f..11e8c9975cf3b 100644 --- a/test/asan/TestCases/Windows/free_hook_realloc.cc +++ b/test/asan/TestCases/Windows/free_hook_realloc.cc @@ -5,6 +5,9 @@ // FIXME: merge this with the common free_hook_realloc test when we can run // common tests on Windows. +// FIXME: Doesn't work with DLLs +// XFAIL: win32-dynamic-asan + #include <stdlib.h> #include <io.h> #include <sanitizer/allocator_interface.h> diff --git a/test/asan/TestCases/Windows/global_dead_strip.c b/test/asan/TestCases/Windows/global_dead_strip.c new file mode 100644 index 0000000000000..e68549050be6f --- /dev/null +++ b/test/asan/TestCases/Windows/global_dead_strip.c @@ -0,0 +1,23 @@ +// RUN: %clang_cl_asan /O0 %s /Fe%t.exe +// RUN: %env_asan_opts=report_globals=2 %t.exe 2>&1 | FileCheck %s --check-prefix=NOSTRIP +// RUN: %clang_cl_asan /O2 %s /Fe%t.exe -link -opt:ref +// RUN: %env_asan_opts=report_globals=2 %t.exe 2>&1 | FileCheck %s --check-prefix=STRIP + +#include <stdio.h> +int dead_global = 42; +int live_global = 0; +int main() { + puts("main"); + return live_global; +} + +// Check that our global registration scheme works with MSVC's linker dead +// stripping (/OPT:REF). + +// NOSTRIP: Added Global{{.*}}name=dead_global +// NOSTRIP: Added Global{{.*}}name=live_global +// NOSTRIP: main + +// STRIP-NOT: Added Global{{.*}}name=dead_global +// STRIP: Added Global{{.*}}name=live_global +// STRIP: main diff --git a/test/asan/TestCases/Windows/intercept_memcpy.cc b/test/asan/TestCases/Windows/intercept_memcpy.cc index 9ee984b1873db..6e45e7fc6b309 100644 --- a/test/asan/TestCases/Windows/intercept_memcpy.cc +++ b/test/asan/TestCases/Windows/intercept_memcpy.cc @@ -22,8 +22,8 @@ int main() { call_memcpy(&memcpy, buff2, buff1, 6); // CHECK: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] // CHECK: WRITE of size 6 at [[ADDR]] thread T0 -// CHECK-NEXT: __asan_{{.*}}memcpy -// CHECK-NEXT: call_memcpy +// CHECK-NEXT: __asan_{{.*}}mem{{.*}} +// CHECK-NEXT: call_mem{{.*}} // CHECK-NEXT: main {{.*}}intercept_memcpy.cc:[[@LINE-5]] // CHECK: Address [[ADDR]] is located in stack of thread T0 at offset {{.*}} in frame // CHECK-NEXT: #0 {{.*}} main diff --git a/test/asan/TestCases/Windows/on_error_callback.cc b/test/asan/TestCases/Windows/on_error_callback.cc deleted file mode 100644 index 9e690a342b564..0000000000000 --- a/test/asan/TestCases/Windows/on_error_callback.cc +++ /dev/null @@ -1,20 +0,0 @@ -// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s - -// FIXME: merge this with the common on_error_callback test when we can run -// common tests on Windows. - -#include <stdio.h> -#include <stdlib.h> - -extern "C" -void __asan_on_error() { - fprintf(stderr, "__asan_on_error called"); - fflush(0); -} - -int main() { - char *x = (char*)malloc(10 * sizeof(char)); - free(x); - return x[5]; - // CHECK: __asan_on_error called -} diff --git a/test/asan/TestCases/Windows/oom.cc b/test/asan/TestCases/Windows/oom.cc index 3475af79e6a4c..59cc7ed0e9d12 100644 --- a/test/asan/TestCases/Windows/oom.cc +++ b/test/asan/TestCases/Windows/oom.cc @@ -1,5 +1,6 @@ // RUN: %clang_cl_asan -O0 %s -Fe%t // RUN: not %run %t 2>&1 | FileCheck %s +// REQUIRES: asan-32-bits #include <malloc.h> diff --git a/test/asan/TestCases/Windows/operator_array_new_with_dtor_left_oob.cc b/test/asan/TestCases/Windows/operator_array_new_with_dtor_left_oob.cc index 63f2929bd89be..aae9d5ec82be2 100644 --- a/test/asan/TestCases/Windows/operator_array_new_with_dtor_left_oob.cc +++ b/test/asan/TestCases/Windows/operator_array_new_with_dtor_left_oob.cc @@ -8,7 +8,7 @@ struct C { int main() { C *buffer = new C[42]; - buffer[-2].x = 42; + buffer[-(1 + sizeof(void*) / 4)].x = 42; // CHECK: AddressSanitizer: heap-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] // CHECK: WRITE of size 4 at [[ADDR]] thread T0 // CHECK-NEXT: {{#0 .* main .*operator_array_new_with_dtor_left_oob.cc}}:[[@LINE-3]] @@ -16,7 +16,7 @@ int main() { // FIXME: Currently it says "4 bytes ... left of 172-byte region", // should be "8 bytes ... left of 168-byte region", see // https://code.google.com/p/address-sanitizer/issues/detail?id=314 -// CHECK: [[ADDR]] is located {{.*}} bytes to the left of 172-byte region +// CHECK: [[ADDR]] is located {{.*}} bytes to the left of {{(172|176)}}-byte region // CHECK-LABEL: allocated by thread T0 here: // FIXME: The 'operator new' frame should have []. // CHECK-NEXT: {{#0 .* operator new}} diff --git a/test/asan/TestCases/Windows/queue_user_work_item.cc b/test/asan/TestCases/Windows/queue_user_work_item.cc index 2a0b622f62185..2a8beb828ee29 100644 --- a/test/asan/TestCases/Windows/queue_user_work_item.cc +++ b/test/asan/TestCases/Windows/queue_user_work_item.cc @@ -1,11 +1,6 @@ // Make sure we can throw exceptions from work items executed via // QueueUserWorkItem. // -// Clang doesn't support exceptions on Windows yet, so for the time being we -// build this program in two parts: the code with exceptions is built with CL, -// the rest is built with Clang. This represents the typical scenario when we -// build a large project using "clang-cl -fallback -fsanitize=address". -// // RUN: %clangxx_asan %s -o %t.exe // RUN: %run %t.exe 2>&1 | FileCheck %s diff --git a/test/asan/TestCases/Windows/queue_user_work_item_report.cc b/test/asan/TestCases/Windows/queue_user_work_item_report.cc index e500a919fdaed..26bd5e09d3ebd 100644 --- a/test/asan/TestCases/Windows/queue_user_work_item_report.cc +++ b/test/asan/TestCases/Windows/queue_user_work_item_report.cc @@ -12,8 +12,6 @@ DWORD CALLBACK work_item(LPVOID) { // CHECK: AddressSanitizer: stack-buffer-underflow on address [[ADDR:0x[0-9a-f]+]] // CHECK: WRITE of size 1 at [[ADDR]] thread T1 // CHECK: {{#0 .* work_item.*queue_user_work_item_report.cc}}:[[@LINE-3]] -// CHECK: Address [[ADDR]] is located in stack of thread T1 at offset {{.*}} in frame -// CHECK: work_item SetEvent(done); return 0; } diff --git a/test/asan/TestCases/Windows/report_after_syminitialize.cc b/test/asan/TestCases/Windows/report_after_syminitialize.cc index 20bf695141798..eec50297478c0 100644 --- a/test/asan/TestCases/Windows/report_after_syminitialize.cc +++ b/test/asan/TestCases/Windows/report_after_syminitialize.cc @@ -4,6 +4,8 @@ #include <windows.h> #include <dbghelp.h> +#pragma comment(lib, "dbghelp") + int main() { // Make sure the RTL recovers from "no options enabled" dbghelp setup. SymSetOptions(0); @@ -16,8 +18,8 @@ int main() { // CHECK: ERROR: AddressSanitizer: access-violation on unknown address // CHECK: The signal is caused by a WRITE memory access. // CHECK: Hint: address points to the zero page. - // CHECK-NEXT: {{WARNING: Failed to use and restart external symbolizer}} - // CHECK-NEXT: {{WARNING: .*DbgHelp}} + // CHECK: {{WARNING: .*DbgHelp}} + // CHECK: {{WARNING: Failed to use and restart external symbolizer}} // CHECK: {{#0 0x.* in main.*report_after_syminitialize.cc:}}[[@LINE-6]] // CHECK: AddressSanitizer can not provide additional info. } diff --git a/test/asan/TestCases/Windows/shadow_conflict_32.cc b/test/asan/TestCases/Windows/shadow_conflict_32.cc new file mode 100644 index 0000000000000..7c6d94b37483c --- /dev/null +++ b/test/asan/TestCases/Windows/shadow_conflict_32.cc @@ -0,0 +1,29 @@ +// Load this DLL at the default 32-bit ASan shadow base, and test how we dump +// the process memory layout. +// REQUIRES: asan-32-bits +// +// RUN: %clang_cl_asan -DBUILD_DLL -LD %s -Fe%t_dll.dll -link -base:0x30000000 -fixed -dynamicbase:no +// RUN: %clang_cl_asan %s -Fe%t.exe -link %t_dll.lib +// RUN: not %run %t.exe 2>&1 | FileCheck %s + +#ifndef BUILD_DLL +#include <stdio.h> + +extern "C" __declspec(dllimport) int test_function(); + +int main() { + fprintf(stderr, "should have failed to initialize, DLL got loaded near 0x%p\n", + (void *)&test_function); +} + +#else +extern "C" __declspec(dllexport) int test_function() { return 0; } +#endif + +// CHECK: =={{[0-9]+}}==Shadow memory range interleaves with an existing memory mapping. ASan cannot proceed correctly. ABORTING. +// CHECK: =={{[0-9]+}}==ASan shadow was supposed to be located in the [0x2fff0000-0x3fffffff] range. +// CHECK: =={{[0-9]+}}==Dumping process modules + +// CHECK-DAG: {{0x30000000-0x300.....}} {{.*}}\shadow_conflict_32.cc.tmp_dll.dll +// CHECK-DAG: {{0x........-0x........}} {{.*}}\shadow_conflict_32.cc.tmp.exe +// CHECK-DAG: {{0x........-0x........}} {{.*}}\ntdll.dll diff --git a/test/asan/TestCases/Windows/shadow_mapping_failure.cc b/test/asan/TestCases/Windows/shadow_mapping_failure.cc index 9b83947442ed0..510f169401dc3 100644 --- a/test/asan/TestCases/Windows/shadow_mapping_failure.cc +++ b/test/asan/TestCases/Windows/shadow_mapping_failure.cc @@ -1,5 +1,6 @@ // RUN: %clang_cl_asan -O0 %s -Fe%t // RUN: not %run %t 2>&1 | FileCheck %s +// REQUIRES: asan-32-bits #include <stdio.h> diff --git a/test/asan/TestCases/Windows/tls_init.cc b/test/asan/TestCases/Windows/tls_init.cc new file mode 100644 index 0000000000000..c29c4a377834b --- /dev/null +++ b/test/asan/TestCases/Windows/tls_init.cc @@ -0,0 +1,51 @@ +// RUN: %clang_cl_asan %s -Fe%t.exe +// RUN: %run %t.exe | FileCheck %s + +// CHECK: my_thread_callback +// CHECK: ran_before_main: 1 + +#include <windows.h> +#include <stdio.h> +#include <string.h> + +#pragma comment (lib, "dbghelp") + +static bool ran_before_main = false; + +extern "C" void __asan_init(void); + +static void NTAPI /*__attribute__((no_sanitize_address))*/ +my_thread_callback(PVOID module, DWORD reason, PVOID reserved) { + ran_before_main = true; + static const char str[] = "my_thread_callback\n"; + + // Fail the test if we aren't called for the expected reason or we can't write + // stdout. + if (reason != DLL_PROCESS_ATTACH) + return; + HANDLE out = GetStdHandle(STD_OUTPUT_HANDLE); + if (!out || out == INVALID_HANDLE_VALUE) + return; + + DWORD written = 0; + WriteFile(out, &str[0], sizeof(str), &written, NULL); +} + +extern "C" { +#pragma const_seg(".CRT$XLC") +extern const PIMAGE_TLS_CALLBACK p_thread_callback; +const PIMAGE_TLS_CALLBACK p_thread_callback = my_thread_callback; +#pragma const_seg() +} + +#ifdef _WIN64 +#pragma comment(linker, "/INCLUDE:_tls_used") +#pragma comment(linker, "/INCLUDE:p_thread_callback") +#else +#pragma comment(linker, "/INCLUDE:__tls_used") +#pragma comment(linker, "/INCLUDE:_p_thread_callback") +#endif + +int main() { + printf("ran_before_main: %d\n", ran_before_main); +} diff --git a/test/asan/TestCases/Windows/unsymbolized.cc b/test/asan/TestCases/Windows/unsymbolized.cc index e44b4bbabb87f..5854dc56d2e99 100644 --- a/test/asan/TestCases/Windows/unsymbolized.cc +++ b/test/asan/TestCases/Windows/unsymbolized.cc @@ -20,6 +20,6 @@ int do_uaf(void) { free(x); return x[5]; // CHECK: AddressSanitizer: heap-use-after-free - // CHECK: #0 {{0x[a-f0-9]+ \(.*[\\/]unsymbolized.cc.*.exe\+0x40[a-f0-9]{4}\)}} - // CHECK: #1 {{0x[a-f0-9]+ \(.*[\\/]unsymbolized.cc.*.exe\+0x40[a-f0-9]{4}\)}} + // CHECK: #0 {{0x[a-f0-9]+ \(.*[\\/]unsymbolized.cc.*.exe\+(0x40|0x14000)[a-f0-9]{4}\)}} + // CHECK: #1 {{0x[a-f0-9]+ \(.*[\\/]unsymbolized.cc.*.exe\+(0x40|0x14000)[a-f0-9]{4}\)}} } diff --git a/test/asan/TestCases/alloca_big_alignment.cc b/test/asan/TestCases/alloca_big_alignment.cc index 2ede3f949b24a..0b49424bfae5d 100644 --- a/test/asan/TestCases/alloca_big_alignment.cc +++ b/test/asan/TestCases/alloca_big_alignment.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-allocas %s -o %t +// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-dynamic-allocas %s -o %t // RUN: not %run %t 2>&1 | FileCheck %s // diff --git a/test/asan/TestCases/alloca_detect_custom_size_.cc b/test/asan/TestCases/alloca_detect_custom_size_.cc index 2b0f573de3d05..271359bf70973 100644 --- a/test/asan/TestCases/alloca_detect_custom_size_.cc +++ b/test/asan/TestCases/alloca_detect_custom_size_.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-allocas %s -o %t +// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-dynamic-allocas %s -o %t // RUN: not %run %t 2>&1 | FileCheck %s // diff --git a/test/asan/TestCases/alloca_instruments_all_paddings.cc b/test/asan/TestCases/alloca_instruments_all_paddings.cc index e2c7fafb193ed..5bf6f80ac4ce7 100644 --- a/test/asan/TestCases/alloca_instruments_all_paddings.cc +++ b/test/asan/TestCases/alloca_instruments_all_paddings.cc @@ -1,5 +1,5 @@ -// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-allocas %s -o %t -// RUN: %clangxx_asan -O3 -mllvm -asan-instrument-allocas %s -o %t +// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-dynamic-allocas %s -o %t +// RUN: %clangxx_asan -O3 -mllvm -asan-instrument-dynamic-allocas %s -o %t // RUN: %run %t 2>&1 // diff --git a/test/asan/TestCases/alloca_loop_unpoisoning.cc b/test/asan/TestCases/alloca_loop_unpoisoning.cc index 5392792926748..1efada10979ae 100644 --- a/test/asan/TestCases/alloca_loop_unpoisoning.cc +++ b/test/asan/TestCases/alloca_loop_unpoisoning.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-allocas %s -o %t +// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-dynamic-allocas %s -o %t // RUN: %run %t 2>&1 // // REQUIRES: stable-runtime diff --git a/test/asan/TestCases/alloca_overflow_partial.cc b/test/asan/TestCases/alloca_overflow_partial.cc index 590f35465dadb..afac40ce6b9a7 100644 --- a/test/asan/TestCases/alloca_overflow_partial.cc +++ b/test/asan/TestCases/alloca_overflow_partial.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-allocas %s -o %t +// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-dynamic-allocas %s -o %t // RUN: not %run %t 2>&1 | FileCheck %s // diff --git a/test/asan/TestCases/alloca_overflow_right.cc b/test/asan/TestCases/alloca_overflow_right.cc index caec846838eff..615dd1485be1b 100644 --- a/test/asan/TestCases/alloca_overflow_right.cc +++ b/test/asan/TestCases/alloca_overflow_right.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-allocas %s -o %t +// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-dynamic-allocas %s -o %t // RUN: not %run %t 2>&1 | FileCheck %s // diff --git a/test/asan/TestCases/alloca_safe_access.cc b/test/asan/TestCases/alloca_safe_access.cc index 240454fd55e42..1cd0dada7b45c 100644 --- a/test/asan/TestCases/alloca_safe_access.cc +++ b/test/asan/TestCases/alloca_safe_access.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-allocas %s -o %t +// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-dynamic-allocas %s -o %t // RUN: %run %t 2>&1 // diff --git a/test/asan/TestCases/alloca_underflow_left.cc b/test/asan/TestCases/alloca_underflow_left.cc index 6e7061f7cfe24..8720e8cce24b3 100644 --- a/test/asan/TestCases/alloca_underflow_left.cc +++ b/test/asan/TestCases/alloca_underflow_left.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-allocas %s -o %t +// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-dynamic-allocas %s -o %t // RUN: not %run %t 2>&1 | FileCheck %s // diff --git a/test/asan/TestCases/alloca_vla_interact.cc b/test/asan/TestCases/alloca_vla_interact.cc index 3873c3fceea85..4717c9d977ed5 100644 --- a/test/asan/TestCases/alloca_vla_interact.cc +++ b/test/asan/TestCases/alloca_vla_interact.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-allocas %s -o %t +// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-dynamic-allocas %s -o %t // RUN: %run %t 2>&1 // // REQUIRES: stable-runtime diff --git a/test/asan/TestCases/atexit_stats.cc b/test/asan/TestCases/atexit_stats.cc index 42a3fbf23f556..f0b5830b405aa 100644 --- a/test/asan/TestCases/atexit_stats.cc +++ b/test/asan/TestCases/atexit_stats.cc @@ -2,9 +2,9 @@ // RUN: %clangxx_asan -O3 %s -o %t // RUN: %env_asan_opts=atexit=1:print_stats=1 %run %t 2>&1 | FileCheck %s // -// No atexit output on Android due to +// No atexit output in older versions of Android due to // https://code.google.com/p/address-sanitizer/issues/detail?id=263 -// XFAIL: android +// UNSUPPORTED: android #include <stdlib.h> #if !defined(__APPLE__) && !defined(__FreeBSD__) diff --git a/test/asan/TestCases/coverage-order-pcs.cc b/test/asan/TestCases/coverage-order-pcs.cc index dcab69474a6c3..e81c910454556 100644 --- a/test/asan/TestCases/coverage-order-pcs.cc +++ b/test/asan/TestCases/coverage-order-pcs.cc @@ -19,7 +19,7 @@ // // RUN: rm -rf $DIR // Ordering works only in 64-bit mode for now. -// REQUIRES: asan-64-bits +// REQUIRES: asan-64-bits, shell // UNSUPPORTED: android #include <stdio.h> diff --git a/test/asan/TestCases/coverage-pc-buffer.cc b/test/asan/TestCases/coverage-pc-buffer.cc deleted file mode 100644 index 5895a5c45d153..0000000000000 --- a/test/asan/TestCases/coverage-pc-buffer.cc +++ /dev/null @@ -1,65 +0,0 @@ -// Test __sanitizer_coverage_pc_buffer(). - -// RUN: %clangxx_asan -fsanitize-coverage=edge %s -o %t && %run %t - -// UNSUPPORTED: android - -#include <assert.h> -#include <sanitizer/coverage_interface.h> -#include <stdio.h> - -static volatile int sink; -__attribute__((noinline)) void bar() { sink = 2; } -__attribute__((noinline)) void foo() { sink = 1; } - -void assertNotZeroPcs(uintptr_t *buf, uintptr_t size) { - assert(buf); - for (uintptr_t i = 0; i < size; ++i) - assert(buf[i]); -} - -int main() { - { - uintptr_t *buf = NULL; - uintptr_t sz = __sanitizer_get_coverage_pc_buffer(&buf); - assertNotZeroPcs(buf, sz); - assert(sz); - } - - { - uintptr_t *buf = NULL; - uintptr_t sz = __sanitizer_get_coverage_pc_buffer(&buf); - // call functions for the first time. - foo(); - bar(); - uintptr_t *buf1 = NULL; - uintptr_t sz1 = __sanitizer_get_coverage_pc_buffer(&buf1); - assertNotZeroPcs(buf1, sz1); - assert(buf1 == buf); - assert(sz1 > sz); - } - - { - uintptr_t *buf = NULL; - uintptr_t sz = __sanitizer_get_coverage_pc_buffer(&buf); - // second call shouldn't increase coverage. - bar(); - uintptr_t *buf1 = NULL; - uintptr_t sz1 = __sanitizer_get_coverage_pc_buffer(&buf1); - assertNotZeroPcs(buf1, sz1); - assert(buf1 == buf); - assert(sz1 == sz); - } - - { - uintptr_t *buf = NULL; - uintptr_t sz = __sanitizer_get_coverage_pc_buffer(&buf); - // reset coverage to 0. - __sanitizer_reset_coverage(); - uintptr_t *buf1 = NULL; - uintptr_t sz1 = __sanitizer_get_coverage_pc_buffer(&buf1); - assertNotZeroPcs(buf1, sz1); - assert(buf1 == buf); - assert(sz1 < sz); - } -} diff --git a/test/asan/TestCases/coverage-tracing.cc b/test/asan/TestCases/coverage-tracing.cc index b7755f847dbb6..278cfb141f07d 100644 --- a/test/asan/TestCases/coverage-tracing.cc +++ b/test/asan/TestCases/coverage-tracing.cc @@ -24,7 +24,7 @@ // RUN: not diff b.points bf.points // RUN: rm -rf %T/coverage-tracing // -// REQUIRES: asan-64-bits +// REQUIRES: asan-64-bits, shell // UNSUPPORTED: android #include <stdlib.h> diff --git a/test/asan/TestCases/debug_double_free.cc b/test/asan/TestCases/debug_double_free.cc new file mode 100644 index 0000000000000..c3699b9762d82 --- /dev/null +++ b/test/asan/TestCases/debug_double_free.cc @@ -0,0 +1,50 @@ +// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s + +#include <sanitizer/asan_interface.h> +#include <stdio.h> +#include <stdlib.h> + +// FIXME: Doesn't work with DLLs +// XFAIL: win32-dynamic-asan + +// If we use %p with MSVC, it comes out all upper case. Use %08x to get +// lowercase hex. +#ifdef _MSC_VER +# ifdef _WIN64 +# define PTR_FMT "0x%08llx" +# else +# define PTR_FMT "0x%08x" +# endif +#else +# define PTR_FMT "%p" +#endif + +char *heap_ptr; + +int main() { + // Disable stderr buffering. Needed on Windows. + setvbuf(stderr, NULL, _IONBF, 0); + + heap_ptr = (char *)malloc(10); + fprintf(stderr, "heap_ptr: " PTR_FMT "\n", heap_ptr); + // CHECK: heap_ptr: 0x[[ADDR:[0-9a-f]+]] + + free(heap_ptr); + free(heap_ptr); // BOOM + return 0; +} + +void __asan_on_error() { + int present = __asan_report_present(); + void *addr = __asan_get_report_address(); + const char *description = __asan_get_report_description(); + + fprintf(stderr, "%s\n", (present == 1) ? "report present" : ""); + // CHECK: report present + fprintf(stderr, "addr: " PTR_FMT "\n", addr); + // CHECK: addr: {{0x0*}}[[ADDR]] + fprintf(stderr, "description: %s\n", description); + // CHECK: description: double-free +} + +// CHECK: AddressSanitizer: attempting double-free on {{0x0*}}[[ADDR]] in thread T0 diff --git a/test/asan/TestCases/debug_mapping.cc b/test/asan/TestCases/debug_mapping.cc index bd05f6aab3533..40083f02853fc 100644 --- a/test/asan/TestCases/debug_mapping.cc +++ b/test/asan/TestCases/debug_mapping.cc @@ -6,6 +6,12 @@ #include <stdio.h> #include <stdlib.h> +#if _WIN64 +#define PTR "%llx" +#else +#define PTR "%lx" +#endif + // printed because of verbosity=1 // CHECK: SHADOW_SCALE: [[SCALE:[0-9]+]] // CHECK: SHADOW_OFFSET: [[OFFSET:0x[0-9a-f]+]] @@ -15,7 +21,7 @@ int main() { __asan_get_shadow_mapping(&scale, &offset); fprintf(stderr, "scale: %d\n", (int)scale); - fprintf(stderr, "offset: 0x%lx\n", offset); + fprintf(stderr, "offset: 0x" PTR "\n", (void*)offset); // CHECK: scale: [[SCALE]] // CHECK: offset: [[OFFSET]] diff --git a/test/asan/TestCases/debug_report.cc b/test/asan/TestCases/debug_report.cc index 124ae5d76642d..34bc06eba62c1 100644 --- a/test/asan/TestCases/debug_report.cc +++ b/test/asan/TestCases/debug_report.cc @@ -6,6 +6,9 @@ #include <stdio.h> #include <stdlib.h> +// FIXME: Doesn't work with DLLs +// XFAIL: win32-dynamic-asan + int main() { // Disable stderr buffering. Needed on Windows. setvbuf(stderr, NULL, _IONBF, 0); diff --git a/test/asan/TestCases/debug_stacks.cc b/test/asan/TestCases/debug_stacks.cc index 857e905094bee..7c320bfcb2d98 100644 --- a/test/asan/TestCases/debug_stacks.cc +++ b/test/asan/TestCases/debug_stacks.cc @@ -5,6 +5,12 @@ // FIXME: Figure out why allocation/free stack traces may be too short on ARM. // REQUIRES: stable-runtime +#if _WIN64 +#define PTR "%llx" +#else +#define PTR "%lx" +#endif + #include <sanitizer/asan_interface.h> #include <stdio.h> #include <stdlib.h> @@ -35,9 +41,9 @@ int main() { // CHECK: alloc stack retval ok fprintf(stderr, "thread id = %d\n", thread_id); // CHECK: thread id = 0 - fprintf(stderr, "0x%lx\n", trace[0]); + fprintf(stderr, "0x" PTR "\n", trace[0]); // CHECK: [[ALLOC_FRAME_0:0x[0-9a-f]+]] - fprintf(stderr, "0x%lx\n", trace[1]); + fprintf(stderr, "0x" PTR "\n", trace[1]); // CHECK: [[ALLOC_FRAME_1:0x[0-9a-f]+]] num_frames = 100; @@ -48,9 +54,9 @@ int main() { // CHECK: free stack retval ok fprintf(stderr, "thread id = %d\n", thread_id); // CHECK: thread id = 0 - fprintf(stderr, "0x%lx\n", trace[0]); + fprintf(stderr, "0x" PTR "\n", trace[0]); // CHECK: [[FREE_FRAME_0:0x[0-9a-f]+]] - fprintf(stderr, "0x%lx\n", trace[1]); + fprintf(stderr, "0x" PTR "\n", trace[1]); // CHECK: [[FREE_FRAME_1:0x[0-9a-f]+]] mem[0] = 'A'; // BOOM diff --git a/test/asan/TestCases/deep_stack_uaf.cc b/test/asan/TestCases/deep_stack_uaf.cc index 95032f2bd4f55..bdf0dbdb4a4bd 100644 --- a/test/asan/TestCases/deep_stack_uaf.cc +++ b/test/asan/TestCases/deep_stack_uaf.cc @@ -2,8 +2,7 @@ // RUN: %clangxx_asan -O0 %s -o %t 2>&1 // RUN: %env_asan_opts=malloc_context_size=120:redzone=512 not %run %t 2>&1 | FileCheck %s -// XFAIL: arm-linux-gnueabi -// XFAIL: armv7l-unknown-linux-gnueabihf +// REQUIRES: stable-runtime #include <stdlib.h> #include <stdio.h> diff --git a/test/asan/TestCases/default_options.cc b/test/asan/TestCases/default_options.cc index a3aa6637e8acd..27af76d7fe38a 100644 --- a/test/asan/TestCases/default_options.cc +++ b/test/asan/TestCases/default_options.cc @@ -1,6 +1,9 @@ // RUN: %clangxx_asan -O2 %s -o %t // RUN: %run %t 2>&1 | FileCheck %s +// FIXME: Doesn't work with DLLs +// XFAIL: win32-dynamic-asan + const char *kAsanDefaultOptions="verbosity=1 help=1"; extern "C" diff --git a/test/asan/TestCases/double-free.cc b/test/asan/TestCases/double-free.cc index 9bd418fc6c809..2a26b23fb1f10 100644 --- a/test/asan/TestCases/double-free.cc +++ b/test/asan/TestCases/double-free.cc @@ -7,9 +7,7 @@ // RUN: %clangxx_asan -O0 -fsanitize-recover=address %s -o %t 2>&1 // RUN: %env_asan_opts=halt_on_error=false %run %t 2>&1 | FileCheck %s --check-prefix CHECK-RECOVER - -// XFAIL: arm-linux-gnueabi -// XFAIL: armv7l-unknown-linux-gnueabihf +// REQUIRES: stable-runtime #include <stdlib.h> #include <string.h> diff --git a/test/asan/TestCases/exitcode.cc b/test/asan/TestCases/exitcode.cc new file mode 100644 index 0000000000000..cb10540999b7d --- /dev/null +++ b/test/asan/TestCases/exitcode.cc @@ -0,0 +1,130 @@ +// RUN: %clangxx_asan -g %stdcxx11 -Wno-deprecated-declarations %s -o %t +// RUN: %env_asan_opts=exitcode=42 %run %t | FileCheck %s + +// Android doesn't have spawn.h or posix_spawn. +// UNSUPPORTED: android + +// CHECK: got expected 42 exit code + +#include <stdlib.h> +#include <stdio.h> + +#ifdef _WIN32 +#include <windows.h> + +int spawn_child(char **argv) { + // Set an environment variable to tell the child process to interrupt + // itself. + if (!SetEnvironmentVariableW(L"CRASH_FOR_TEST", L"1")) { + printf("SetEnvironmentVariableW failed (0x%8lx).\n", GetLastError()); + fflush(stdout); + exit(1); + } + + STARTUPINFOW si; + memset(&si, 0, sizeof(si)); + si.cb = sizeof(si); + + PROCESS_INFORMATION pi; + memset(&pi, 0, sizeof(pi)); + + if (!CreateProcessW(nullptr, // No module name (use command line) + GetCommandLineW(), // Command line + nullptr, // Process handle not inheritable + nullptr, // Thread handle not inheritable + TRUE, // Set handle inheritance to TRUE + 0, // No flags + nullptr, // Use parent's environment block + nullptr, // Use parent's starting directory + &si, &pi)) { + printf("CreateProcess failed (0x%08lx).\n", GetLastError()); + fflush(stdout); + exit(1); + } + + WaitForSingleObject(pi.hProcess, INFINITE); + + DWORD exit_code; + if (!GetExitCodeProcess(pi.hProcess, &exit_code)) { + printf("GetExitCodeProcess failed (0x%08lx).\n", GetLastError()); + fflush(stdout); + exit(1); + } + + CloseHandle(pi.hProcess); + CloseHandle(pi.hThread); + + return exit_code; +} +#else +#include <spawn.h> +#include <errno.h> +#include <sys/wait.h> + +#if defined(__APPLE__) +#include <TargetConditionals.h> +#endif + +#if defined(__APPLE__) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE) +#define USE_NSGETENVIRON 1 +#else +#define USE_NSGETENVIRON 0 +#endif + +#if !USE_NSGETENVIRON +extern char **environ; +#else +#include <crt_externs.h> // _NSGetEnviron +#endif + +int spawn_child(char **argv) { + setenv("CRASH_FOR_TEST", "1", 1); + +#if !USE_NSGETENVIRON + char **envp = environ; +#else + char **envp = *_NSGetEnviron(); +#endif + + pid_t pid; + int err = posix_spawn(&pid, argv[0], nullptr, nullptr, argv, envp); + if (err) { + printf("posix_spawn failed: %d\n", err); + fflush(stdout); + exit(1); + } + + // Wait until the child exits. + int status; + pid_t wait_result_pid; + do { + wait_result_pid = waitpid(pid, &status, 0); + } while (wait_result_pid == -1 && errno == EINTR); + + if (wait_result_pid != pid || !WIFEXITED(status)) { + printf("error in waitpid\n"); + fflush(stdout); + exit(1); + } + + // Return the exit status. + return WEXITSTATUS(status); +} +#endif + +int main(int argc, char **argv) { + int r = 0; + if (getenv("CRASH_FOR_TEST")) { + // Generate an asan report to test ASAN_OPTIONS=exitcode=42 + int *p = new int; + delete p; + r = *p; + } else { + int exit_code = spawn_child(argv); + if (exit_code == 42) { + printf("got expected 42 exit code\n"); + fflush(stdout); + } + } + return r; +} diff --git a/test/asan/TestCases/global-address.cpp b/test/asan/TestCases/global-address.cpp new file mode 100644 index 0000000000000..0e56ca10c39c2 --- /dev/null +++ b/test/asan/TestCases/global-address.cpp @@ -0,0 +1,12 @@ +// RUN: %clangxx_asan -o %t %s +// RUN: not %run %t 2>&1 | FileCheck %s +#include <sanitizer/allocator_interface.h> + +int g_i = 42; +int main() { + // CHECK: AddressSanitizer: attempting to call __sanitizer_get_allocated_size() for pointer which is not owned + // CHECK-NOT: ASAN:DEADLYSIGNAL + // CHECK: SUMMARY: AddressSanitizer: bad-__sanitizer_get_allocated_size + // CHECK-NOT: ASAN:DEADLYSIGNAL + return (int)__sanitizer_get_allocated_size(&g_i); +} diff --git a/test/asan/TestCases/ill.cc b/test/asan/TestCases/ill.cc new file mode 100644 index 0000000000000..d7b5350916719 --- /dev/null +++ b/test/asan/TestCases/ill.cc @@ -0,0 +1,31 @@ +// Test the handle_sigill option. +// +// RUN: %clangxx_asan %s -o %t && %env_asan_opts=handle_sigill=0 not --crash %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 +// RUN: %clangxx_asan %s -o %t && %env_asan_opts=handle_sigill=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 +// REQUIRES: x86-target-arch + +#ifdef _WIN32 +#include <windows.h> +#endif + +int main(int argc, char **argv) { +#ifdef _WIN32 + // Sometimes on Windows this test generates a WER fault dialog. Suppress that. + UINT new_flags = SEM_FAILCRITICALERRORS | + SEM_NOGPFAULTERRORBOX | + SEM_NOOPENFILEERRORBOX; + // Preserve existing error mode, as discussed at + // http://blogs.msdn.com/oldnewthing/archive/2004/07/27/198410.aspx + UINT existing_flags = SetErrorMode(new_flags); + SetErrorMode(existing_flags | new_flags); +#endif + + if (argc) + __builtin_trap(); + // Unreachable code to avoid confusing the Windows unwinder. +#ifdef _WIN32 + SetErrorMode(0); +#endif +} +// CHECK0-NOT: ERROR: AddressSanitizer +// CHECK1: ERROR: AddressSanitizer: {{ILL|illegal-instruction}} on unknown address {{0x0*}} diff --git a/test/asan/TestCases/initialization-bug.cc b/test/asan/TestCases/initialization-bug.cc index 6f361cb2bad86..b28174f59aeb2 100644 --- a/test/asan/TestCases/initialization-bug.cc +++ b/test/asan/TestCases/initialization-bug.cc @@ -1,12 +1,12 @@ // Test to make sure basic initialization order errors are caught. -// RUN: %clangxx_asan -O0 %s %p/Helpers/initialization-bug-extra2.cc -o %t-INIT-ORDER-EXE +// RUN: %clangxx_asan %macos_min_target_10_11 -O0 %s %p/Helpers/initialization-bug-extra2.cc -o %t-INIT-ORDER-EXE // RUN: %env_asan_opts=check_initialization_order=true not %run %t-INIT-ORDER-EXE 2>&1 | FileCheck %s // Do not test with optimization -- the error may be optimized away. // FIXME: https://code.google.com/p/address-sanitizer/issues/detail?id=186 -// XFAIL: darwin,win32 +// XFAIL: win32 // The test is expected to fail on OS X Yosemite and older // UNSUPPORTED: osx-no-ld64-live_support diff --git a/test/asan/TestCases/interception_failure_test.cc b/test/asan/TestCases/interception_failure_test.cc index 63d8746678363..d85500b50486b 100644 --- a/test/asan/TestCases/interception_failure_test.cc +++ b/test/asan/TestCases/interception_failure_test.cc @@ -5,13 +5,20 @@ // 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 -// On Windows, defining strtoll results in linker errors. -// XFAIL: freebsd,win32 +// XFAIL: freebsd + +// On Windows, defining strtoll in a static build results in linker errors, but +// it works with the dynamic runtime. +// XFAIL: win32-static-asan + #include <stdlib.h> #include <stdio.h> +#include <string.h> extern "C" long strtol(const char *nptr, char **endptr, int base) { fprintf(stderr, "my_strtol_interceptor\n"); + if (endptr) + *endptr = (char*)nptr + strlen(nptr); return 0; } diff --git a/test/asan/TestCases/intra-object-overflow.cc b/test/asan/TestCases/intra-object-overflow.cc index e48a261f55cc3..4032cc1448582 100644 --- a/test/asan/TestCases/intra-object-overflow.cc +++ b/test/asan/TestCases/intra-object-overflow.cc @@ -4,6 +4,8 @@ // // FIXME: fix 32-bits. // REQUIRES: asan-64-bits +// FIXME: Implement ASan intra-object padding in Clang's MS record layout +// UNSUPPORTED: win32 #include <stdio.h> #include <stdlib.h> class Foo { diff --git a/test/asan/TestCases/invalid-free.cc b/test/asan/TestCases/invalid-free.cc index dd59f5af32f22..be45e438bd45a 100644 --- a/test/asan/TestCases/invalid-free.cc +++ b/test/asan/TestCases/invalid-free.cc @@ -4,8 +4,7 @@ // Also works if no malloc context is available. // RUN: %env_asan_opts=malloc_context_size=0:fast_unwind_on_malloc=0 not %run %t 2>&1 | FileCheck %s // RUN: %env_asan_opts=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 +// REQUIRES: stable-runtime #include <stdlib.h> #include <string.h> diff --git a/test/asan/TestCases/large_func_test.cc b/test/asan/TestCases/large_func_test.cc index 8d9afaeb4a75c..1f5f7ccd5a6dc 100644 --- a/test/asan/TestCases/large_func_test.cc +++ b/test/asan/TestCases/large_func_test.cc @@ -2,8 +2,7 @@ // RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK // RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK // RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK -// XFAIL: arm-linux-gnueabi -// XFAIL: armv7l-unknown-linux-gnueabihf +// REQUIRES: stable-runtime #include <stdlib.h> __attribute__((noinline)) diff --git a/test/asan/TestCases/on_error_callback.cc b/test/asan/TestCases/on_error_callback.cc index 88a4d2dca49fd..f37d1eb7f7f83 100644 --- a/test/asan/TestCases/on_error_callback.cc +++ b/test/asan/TestCases/on_error_callback.cc @@ -1,5 +1,8 @@ // RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s +// FIXME: Doesn't work with DLLs +// XFAIL: win32-dynamic-asan + #include <stdio.h> #include <stdlib.h> diff --git a/test/asan/TestCases/printf-m.c b/test/asan/TestCases/printf-m.c new file mode 100644 index 0000000000000..9cd5ae1c288e7 --- /dev/null +++ b/test/asan/TestCases/printf-m.c @@ -0,0 +1,14 @@ +// RUN: %clang_asan -O2 %s -o %t && %run %t + +// FIXME: printf is not intercepted on Windows yet. +// UNSUPPORTED: win32 + +#include <stdio.h> + +int main() { + char s[5] = {'w', 'o', 'r', 'l', 'd'}; + // Test that %m does not consume an argument. If it does, %s would apply to + // the 5-character buffer, resulting in a stack-buffer-overflow report. + printf("%m %s, %.5s\n", "hello", s); + return 0; +} diff --git a/test/asan/TestCases/sanity_check_pure_c.c b/test/asan/TestCases/sanity_check_pure_c.c index c3a43c8cacb2e..9d74996e43c55 100644 --- a/test/asan/TestCases/sanity_check_pure_c.c +++ b/test/asan/TestCases/sanity_check_pure_c.c @@ -3,10 +3,9 @@ // RUN: not %run %t 2>&1 | FileCheck %s // Sanity checking a test in pure C with -pie. -// RUN: %clang_asan -O2 %s -pie -fPIE -o %t +// RUN: %clang_asan -O2 %s %pie %fPIE -o %t // RUN: not %run %t 2>&1 | FileCheck %s -// XFAIL: arm-linux-gnueabi -// XFAIL: armv7l-unknown-linux-gnueabihf +// REQUIRES: stable-runtime #include <stdlib.h> int main() { diff --git a/test/asan/TestCases/Linux/scariness_score_test.cc b/test/asan/TestCases/scariness_score_test.cc index 24854132f539e..dee7a13b7b3be 100644 --- a/test/asan/TestCases/Linux/scariness_score_test.cc +++ b/test/asan/TestCases/scariness_score_test.cc @@ -1,7 +1,9 @@ // Test how we produce the scariness score. // RUN: %clangxx_asan -O0 %s -o %t -// RUN: export %env_asan_opts=detect_stack_use_after_return=1:handle_abort=1:print_scariness=1 +// On OSX and Windows, alloc_dealloc_mismatch=1 isn't 100% reliable, so it's +// off by default. It's safe for these tests, though, so we turn it on. +// RUN: export %env_asan_opts=detect_stack_use_after_return=1:handle_abort=1:print_scariness=1:alloc_dealloc_mismatch=1 // Make sure the stack is limited (may not be the default under GNU make) // RUN: ulimit -s 4096 // RUN: not %run %t 1 2>&1 | FileCheck %s --check-prefix=CHECK1 @@ -155,12 +157,12 @@ int main(int argc, char **argv) { case 19: *zero_ptr = 0; break; case 20: *wild_addr = 0; break; case 21: zero = *wild_addr; break; - case 22: abort(); break; - case 23: ((void (*)(void))wild_addr)(); break; - case 24: delete (new int[10]); break; - case 25: free((char*)malloc(100) + 10); break; - case 26: memcpy(arr, arr+10, 20); break; - case 27: UseAfterPoison(); break; + case 22: ((void (*)(void))wild_addr)(); break; + case 23: delete (new int[10]); break; + case 24: free((char*)malloc(100) + 10); break; + case 25: memcpy(arr, arr+10, 20); break; + case 26: UseAfterPoison(); break; + case 27: abort(); // CHECK1: SCARINESS: 12 (1-byte-read-heap-buffer-overflow) // CHECK2: SCARINESS: 17 (4-byte-read-heap-buffer-overflow) // CHECK3: SCARINESS: 33 (2-byte-write-heap-buffer-overflow) @@ -182,11 +184,11 @@ int main(int argc, char **argv) { // CHECK19: SCARINESS: 10 (null-deref) // CHECK20: SCARINESS: 30 (wild-addr-write) // CHECK21: SCARINESS: 20 (wild-addr-read) - // CHECK22: SCARINESS: 10 (signal) - // CHECK23: SCARINESS: 60 (wild-jump) - // CHECK24: SCARINESS: 10 (alloc-dealloc-mismatch) - // CHECK25: SCARINESS: 40 (bad-free) - // CHECK26: SCARINESS: 10 (memcpy-param-overlap) - // CHECK27: SCARINESS: 27 (4-byte-read-use-after-poison) + // CHECK22: SCARINESS: 60 (wild-jump) + // CHECK23: SCARINESS: 10 (alloc-dealloc-mismatch) + // CHECK24: SCARINESS: 40 (bad-free) + // CHECK25: SCARINESS: 10 (memcpy-param-overlap) + // CHECK26: SCARINESS: 27 (4-byte-read-use-after-poison) + // CHECK27: SCARINESS: 10 (signal) } } diff --git a/test/asan/TestCases/set_shadow_test.c b/test/asan/TestCases/set_shadow_test.c new file mode 100644 index 0000000000000..daa79a66a389b --- /dev/null +++ b/test/asan/TestCases/set_shadow_test.c @@ -0,0 +1,69 @@ +// RUN: %clang_asan -O0 %s -o %t +// RUN: %run %t 0x00 2>&1 | FileCheck %s -check-prefix=X00 +// RUN: not %run %t 0xf1 2>&1 | FileCheck %s -check-prefix=XF1 +// RUN: not %run %t 0xf2 2>&1 | FileCheck %s -check-prefix=XF2 +// RUN: not %run %t 0xf3 2>&1 | FileCheck %s -check-prefix=XF3 +// RUN: not %run %t 0xf5 2>&1 | FileCheck %s -check-prefix=XF5 +// RUN: not %run %t 0xf8 2>&1 | FileCheck %s -check-prefix=XF8 + +// XFAIL: win32 + +#include <assert.h> +#include <sanitizer/asan_interface.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> + +void __asan_set_shadow_00(size_t addr, size_t size); +void __asan_set_shadow_f1(size_t addr, size_t size); +void __asan_set_shadow_f2(size_t addr, size_t size); +void __asan_set_shadow_f3(size_t addr, size_t size); +void __asan_set_shadow_f5(size_t addr, size_t size); +void __asan_set_shadow_f8(size_t addr, size_t size); + +char a __attribute__((aligned(8))); + +void f(long arg) { + size_t shadow_offset; + size_t shadow_scale; + __asan_get_shadow_mapping(&shadow_scale, &shadow_offset); + size_t addr = (((size_t)&a) >> shadow_scale) + shadow_offset; + + switch (arg) { + // X00-NOT: AddressSanitizer + // X00: PASS + case 0x00: + return __asan_set_shadow_00(addr, 1); + // XF1: AddressSanitizer: stack-buffer-underflow + // XF1: [f1] + case 0xf1: + return __asan_set_shadow_f1(addr, 1); + // XF2: AddressSanitizer: stack-buffer-overflow + // XF2: [f2] + case 0xf2: + return __asan_set_shadow_f2(addr, 1); + // XF3: AddressSanitizer: stack-buffer-overflow + // XF3: [f3] + case 0xf3: + return __asan_set_shadow_f3(addr, 1); + // XF5: AddressSanitizer: stack-use-after-return + // XF5: [f5] + case 0xf5: + return __asan_set_shadow_f5(addr, 1); + // XF8: AddressSanitizer: stack-use-after-scope + // XF8: [f8] + case 0xf8: + return __asan_set_shadow_f8(addr, 1); + } + assert(0); +} + +int main(int argc, char **argv) { + assert(argc > 1); + + long arg = strtol(argv[1], 0, 16); + f(arg); + a = 1; + printf("PASS\n"); + return 0; +} diff --git a/test/asan/TestCases/speculative_load.cc b/test/asan/TestCases/speculative_load.cc index 2409d7a5eee34..fdf70eb39767a 100644 --- a/test/asan/TestCases/speculative_load.cc +++ b/test/asan/TestCases/speculative_load.cc @@ -27,6 +27,10 @@ struct S { __asan_poison_memory_region(_data._s._ch, 23); } + ~S() { + __asan_unpoison_memory_region(_data._s._ch, 23); + } + bool is_long() const { return _data._s._size & 1; } diff --git a/test/asan/TestCases/strdup_oob_test.cc b/test/asan/TestCases/strdup_oob_test.cc index 492555ad10194..60c5ef12a4735 100644 --- a/test/asan/TestCases/strdup_oob_test.cc +++ b/test/asan/TestCases/strdup_oob_test.cc @@ -9,6 +9,10 @@ // Unwind problem on arm: "main" is missing from the allocation stack trace. // UNSUPPORTED: armv7l-unknown-linux-gnueabihf +// FIXME: We fail to intercept strdup with the dynamic WinASan RTL, so it's not +// in the stack trace. +// XFAIL: win32-dynamic-asan + #include <string.h> char kString[] = "foo"; diff --git a/test/asan/TestCases/strncasecmp_strict.c b/test/asan/TestCases/strncasecmp_strict.c new file mode 100644 index 0000000000000..aa658402b42b3 --- /dev/null +++ b/test/asan/TestCases/strncasecmp_strict.c @@ -0,0 +1,67 @@ +// Test strict_string_checks option in strncmp function +// RUN: %clang_asan %s -o %t + +// RUN: %env_asan_opts=strict_string_checks=false %run %t a 2>&1 +// RUN: %env_asan_opts=strict_string_checks=true %run %t a 2>&1 +// RUN: not %run %t b 2>&1 | FileCheck %s +// RUN: not %run %t c 2>&1 | FileCheck %s +// RUN: not %run %t d 2>&1 | FileCheck %s +// RUN: not %run %t e 2>&1 | FileCheck %s +// RUN: not %run %t f 2>&1 | FileCheck %s +// RUN: not %run %t g 2>&1 | FileCheck %s +// RUN: %env_asan_opts=strict_string_checks=false %run %t h 2>&1 +// RUN: %env_asan_opts=strict_string_checks=true not %run %t h 2>&1 | FileCheck %s +// RUN: %env_asan_opts=strict_string_checks=false %run %t i 2>&1 +// RUN: %env_asan_opts=strict_string_checks=true not %run %t i 2>&1 | FileCheck %s + +// XFAIL: win32 + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +int main(int argc, char **argv) { + assert(argc >= 2); + const size_t size = 100; + char fill = 'o'; + char s1[size]; + char s2[size]; + memset(s1, fill, size); + memset(s2, fill, size); + + switch (argv[1][0]) { + case 'a': + s1[size - 1] = 'z'; + s2[size - 1] = 'x'; + for (int i = 0; i <= size; ++i) + assert((strncasecmp(s1, s2, i) == 0) == (i < size)); + s1[size - 1] = '\0'; + s2[size - 1] = '\0'; + assert(strncasecmp(s1, s2, 2*size) == 0); + break; + case 'b': + return strncasecmp(s1-1, s2, 1); + case 'c': + return strncasecmp(s1, s2-1, 1); + case 'd': + return strncasecmp(s1+size, s2, 1); + case 'e': + return strncasecmp(s1, s2+size, 1); + case 'f': + return strncasecmp(s1+1, s2, size); + case 'g': + return strncasecmp(s1, s2+1, size); + case 'h': + s1[size - 1] = '\0'; + assert(strncasecmp(s1, s2, 2*size) != 0); + break; + case 'i': + s2[size - 1] = '\0'; + assert(strncasecmp(s1, s2, 2*size) != 0); + break; + // CHECK: {{.*}}ERROR: AddressSanitizer: stack-buffer-{{ov|und}}erflow on address + } + return 0; +} diff --git a/test/asan/TestCases/strncmp_strict.c b/test/asan/TestCases/strncmp_strict.c new file mode 100644 index 0000000000000..5b5429064cedc --- /dev/null +++ b/test/asan/TestCases/strncmp_strict.c @@ -0,0 +1,65 @@ +// Test strict_string_checks option in strncmp function +// RUN: %clang_asan %s -o %t + +// RUN: %env_asan_opts=strict_string_checks=false %run %t a 2>&1 +// RUN: %env_asan_opts=strict_string_checks=true %run %t a 2>&1 +// RUN: not %run %t b 2>&1 | FileCheck %s +// RUN: not %run %t c 2>&1 | FileCheck %s +// RUN: not %run %t d 2>&1 | FileCheck %s +// RUN: not %run %t e 2>&1 | FileCheck %s +// RUN: not %run %t f 2>&1 | FileCheck %s +// RUN: not %run %t g 2>&1 | FileCheck %s +// RUN: %env_asan_opts=strict_string_checks=false %run %t h 2>&1 +// RUN: %env_asan_opts=strict_string_checks=true not %run %t h 2>&1 | FileCheck %s +// RUN: %env_asan_opts=strict_string_checks=false %run %t i 2>&1 +// RUN: %env_asan_opts=strict_string_checks=true not %run %t i 2>&1 | FileCheck %s + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <ctype.h> + +int main(int argc, char **argv) { + assert(argc >= 2); + const size_t size = 100; + char fill = 'o'; + char s1[size]; + char s2[size]; + memset(s1, fill, size); + memset(s2, fill, size); + + switch (argv[1][0]) { + case 'a': + s1[size - 1] = 'z'; + s2[size - 1] = 'x'; + for (int i = 0; i <= size; ++i) + assert((strncmp(s1, s2, i) == 0) == (i < size)); + s1[size - 1] = '\0'; + s2[size - 1] = '\0'; + assert(strncmp(s1, s2, 2*size) == 0); + break; + case 'b': + return strncmp(s1-1, s2, 1); + case 'c': + return strncmp(s1, s2-1, 1); + case 'd': + return strncmp(s1+size, s2, 1); + case 'e': + return strncmp(s1, s2+size, 1); + case 'f': + return strncmp(s1+1, s2, size); + case 'g': + return strncmp(s1, s2+1, size); + case 'h': + s1[size - 1] = '\0'; + assert(strncmp(s1, s2, 2*size) != 0); + break; + case 'i': + s2[size - 1] = '\0'; + assert(strncmp(s1, s2, 2*size) != 0); + break; + // CHECK: {{.*}}ERROR: AddressSanitizer: stack-buffer-{{ov|und}}erflow on address + } + return 0; +} diff --git a/test/asan/TestCases/strncpy-overflow.cc b/test/asan/TestCases/strncpy-overflow.cc index 651ae22795f15..7da9a8ff8eac5 100644 --- a/test/asan/TestCases/strncpy-overflow.cc +++ b/test/asan/TestCases/strncpy-overflow.cc @@ -4,8 +4,7 @@ // RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK // REQUIRES: compiler-rt-optimized -// XFAIL: arm-linux-gnueabi -// XFAIL: armv7l-unknown-linux-gnueabihf +// REQUIRES: stable-runtime #include <string.h> #include <stdlib.h> diff --git a/test/asan/TestCases/strstr-1.c b/test/asan/TestCases/strstr-1.c index d0fa25bc62ba3..06a8a8a55d999 100644 --- a/test/asan/TestCases/strstr-1.c +++ b/test/asan/TestCases/strstr-1.c @@ -15,7 +15,7 @@ int main(int argc, char **argv) { char s1[4] = "acb"; __asan_poison_memory_region ((char *)&s1[2], 2); r = strstr(s1, s2); - // CHECK:'s1' <== Memory access at offset {{[0-9]+}} partially overflows this variable + // CHECK:'s1' <== Memory access at offset {{[0-9]+}} {{partially overflows this variable|is inside this variable}} assert(r == s1 + 1); return 0; } diff --git a/test/asan/TestCases/strstr_strict.c b/test/asan/TestCases/strstr_strict.c index 35ad93c645ded..63e6b25a017c8 100644 --- a/test/asan/TestCases/strstr_strict.c +++ b/test/asan/TestCases/strstr_strict.c @@ -17,7 +17,7 @@ int main(int argc, char **argv) { s2[size - 1]='\0'; char* r = strstr(s1, s2); // CHECK: {{.*ERROR: AddressSanitizer: heap-buffer-overflow on address}} - // CHECK: READ of size 101 + // CHECK: READ of size {{101|100}} assert(r == s1); free(s1); free(s2); diff --git a/test/asan/TestCases/suppressions-library.cc b/test/asan/TestCases/suppressions-library.cc index ad6e09279b3dc..e95d339168ed8 100644 --- a/test/asan/TestCases/suppressions-library.cc +++ b/test/asan/TestCases/suppressions-library.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_asan -O0 -DSHARED_LIB %s -fPIC -shared -o %dynamiclib %ld_flags_rpath_so +// RUN: %clangxx_asan -O0 -DSHARED_LIB %s %fPIC -shared -o %dynamiclib %ld_flags_rpath_so // RUN: %clangxx_asan -O0 %s -o %t %ld_flags_rpath_exe // Check that without suppressions, we catch the issue. diff --git a/test/asan/TestCases/use-after-delete.cc b/test/asan/TestCases/use-after-delete.cc index 8fdec8d83c803..1cc8c2f079aca 100644 --- a/test/asan/TestCases/use-after-delete.cc +++ b/test/asan/TestCases/use-after-delete.cc @@ -2,8 +2,7 @@ // RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK // RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK // RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK -// XFAIL: arm-linux-gnueabi -// XFAIL: armv7l-unknown-linux-gnueabihf +// REQUIRES: stable-runtime #include <stdlib.h> int main() { diff --git a/test/asan/TestCases/use-after-free-right.cc b/test/asan/TestCases/use-after-free-right.cc index f714b44f2f1f4..d72370e72d816 100644 --- a/test/asan/TestCases/use-after-free-right.cc +++ b/test/asan/TestCases/use-after-free-right.cc @@ -2,8 +2,7 @@ // RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK // RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK // RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK -// XFAIL: arm-linux-gnueabi -// XFAIL: armv7l-unknown-linux-gnueabihf +// REQUIRES: stable-runtime // Test use-after-free report in the case when access is at the right border of // the allocation. diff --git a/test/asan/TestCases/use-after-free.cc b/test/asan/TestCases/use-after-free.cc index 7bc225b1ef863..c96d7f2e24e1f 100644 --- a/test/asan/TestCases/use-after-free.cc +++ b/test/asan/TestCases/use-after-free.cc @@ -2,8 +2,7 @@ // RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK // RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK // RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-%os --check-prefix=CHECK -// XFAIL: arm-linux-gnueabi -// XFAIL: armv7l-unknown-linux-gnueabihf +// REQUIRES: stable-runtime #include <stdlib.h> int main() { diff --git a/test/asan/TestCases/use-after-scope-capture.cc b/test/asan/TestCases/use-after-scope-capture.cc index 07aab672eecb3..113ce35366627 100644 --- a/test/asan/TestCases/use-after-scope-capture.cc +++ b/test/asan/TestCases/use-after-scope-capture.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_asan -std=c++11 -O1 -fsanitize-address-use-after-scope %s -o %t && \ +// RUN: %clangxx_asan %stdcxx11 -O1 -fsanitize-address-use-after-scope %s -o %t && \ // RUN: not %run %t 2>&1 | FileCheck %s #include <functional> diff --git a/test/asan/TestCases/use-after-scope-chars.cc b/test/asan/TestCases/use-after-scope-chars.cc deleted file mode 100644 index 51fc5fa387474..0000000000000 --- a/test/asan/TestCases/use-after-scope-chars.cc +++ /dev/null @@ -1,15 +0,0 @@ -// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \ -// RUN: not %run %t 2>&1 | FileCheck %s -// XFAIL: * - -// FIXME: This works only for arraysize <= 8. - -char *p = 0; - -int main() { - { - char x[1024] = {}; - p = x; - } - return *p; // BOOM -} diff --git a/test/asan/TestCases/use-after-scope-goto.cc b/test/asan/TestCases/use-after-scope-goto.cc new file mode 100644 index 0000000000000..351cbe995efb2 --- /dev/null +++ b/test/asan/TestCases/use-after-scope-goto.cc @@ -0,0 +1,73 @@ +// 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. + +#include <stdlib.h> + +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/test/asan/TestCases/use-after-scope-inlined.cc b/test/asan/TestCases/use-after-scope-inlined.cc index fc8c7f7bb87d8..98a455cbc0c7f 100644 --- a/test/asan/TestCases/use-after-scope-inlined.cc +++ b/test/asan/TestCases/use-after-scope-inlined.cc @@ -24,5 +24,5 @@ int main(int argc, char *argv[]) { // CHECK: Address 0x{{.*}} is located in stack of thread T0 at offset // CHECK: [[OFFSET:[^ ]*]] in frame // CHECK: main - // CHECK: {{\[}}[[OFFSET]], {{.*}}) 'x.i' + // CHECK: {{\[}}[[OFFSET]], {{.*}}) 'x.i:[[@LINE-15]]' } diff --git a/test/asan/TestCases/use-after-scope-loop-bug.cc b/test/asan/TestCases/use-after-scope-loop-bug.cc index 6ad9bf3260ccd..d4b12eca9808f 100644 --- a/test/asan/TestCases/use-after-scope-loop-bug.cc +++ b/test/asan/TestCases/use-after-scope-loop-bug.cc @@ -1,10 +1,7 @@ // RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \ // RUN: not %run %t 2>&1 | FileCheck %s -// -// FIXME: @llvm.lifetime.* are not emitted for x. -// XFAIL: * -int *p; +volatile int *p; int main() { // Variable goes in and out of scope. @@ -13,4 +10,8 @@ int main() { p = x + i; } return *p; // BOOM + // CHECK: ERROR: AddressSanitizer: stack-use-after-scope + // CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope-loop-bug.cc:[[@LINE-2]] + // CHECK: Address 0x{{.*}} is located in stack of thread T{{.*}} at offset [[OFFSET:[^ ]+]] in frame + // {{\[}}[[OFFSET]], {{[0-9]+}}) 'x' } diff --git a/test/asan/TestCases/use-after-scope-loop-removed.cc b/test/asan/TestCases/use-after-scope-loop-removed.cc index cd71a5046cd48..730bf3a3ebe33 100644 --- a/test/asan/TestCases/use-after-scope-loop-removed.cc +++ b/test/asan/TestCases/use-after-scope-loop-removed.cc @@ -1,9 +1,5 @@ // RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \ // RUN: not %run %t 2>&1 | FileCheck %s -// -// FIXME: Compiler removes for-loop but keeps x variable. For unknown reason -// @llvm.lifetime.* are not emitted for x. -// XFAIL: * #include <stdlib.h> @@ -14,6 +10,9 @@ int main() { int x; p = &x; } - return **p; // BOOM + return *p; // BOOM // CHECK: ERROR: AddressSanitizer: stack-use-after-scope + // CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope-loop-removed.cc:[[@LINE-2]] + // CHECK: Address 0x{{.*}} is located in stack of thread T{{.*}} at offset [[OFFSET:[^ ]+]] in frame + // {{\[}}[[OFFSET]], {{[0-9]+}}) 'x' } diff --git a/test/asan/TestCases/use-after-scope-temp.cc b/test/asan/TestCases/use-after-scope-temp.cc index 3736f914d0722..4dcef59a2ff12 100644 --- a/test/asan/TestCases/use-after-scope-temp.cc +++ b/test/asan/TestCases/use-after-scope-temp.cc @@ -1,8 +1,6 @@ -// RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \ +// RUN: %clangxx_asan %stdcxx11 -O1 -fsanitize-address-use-after-scope %s -o %t && \ // RUN: not %run %t 2>&1 | FileCheck %s -// -// Lifetime for temporaries is not emitted yet. -// XFAIL: * + struct IntHolder { int val; @@ -15,9 +13,9 @@ void save(const IntHolder &holder) { } int main(int argc, char *argv[]) { - save({10}); + save({argc}); int x = saved->val; // BOOM -// CHECK: ERROR: AddressSanitizer: stack-use-after-scope -// CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope-temp.cc:[[@LINE-2]] + // CHECK: ERROR: AddressSanitizer: stack-use-after-scope + // CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope-temp.cc:[[@LINE-2]] return x; } diff --git a/test/asan/TestCases/use-after-scope-temp2.cc b/test/asan/TestCases/use-after-scope-temp2.cc new file mode 100644 index 0000000000000..1ecd3cbe23ff1 --- /dev/null +++ b/test/asan/TestCases/use-after-scope-temp2.cc @@ -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 + + +struct IntHolder { + 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.cc:[[@LINE-2]] + return x; +} diff --git a/test/asan/TestCases/use-after-scope-types.cc b/test/asan/TestCases/use-after-scope-types.cc new file mode 100644 index 0000000000000..ec6742bbb24fc --- /dev/null +++ b/test/asan/TestCases/use-after-scope-types.cc @@ -0,0 +1,74 @@ +// 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 + +#include <stdlib.h> +#include <string> +#include <vector> + +template <class T> struct Ptr { + void Store(T *ptr) { t = ptr; } + + void Access() { *t = {}; } + + T *t; +}; + +template <class T, size_t N> struct Ptr<T[N]> { + using Type = T[N]; + void Store(Type *ptr) { t = *ptr; } + + void Access() { *t = {}; } + + T *t; +}; + +template <class T> __attribute__((noinline)) void test() { + Ptr<T> 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.cc + // 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<bool>, + &test<char>, + &test<int>, + &test<double>, + &test<float>, + &test<void*>, + &test<std::vector<std::string>>, + &test<int[3]>, + &test<int[1000]>, + &test<char[3]>, + &test<char[1000]>, + }; + + 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/test/asan/TestCases/use-after-scope.cc b/test/asan/TestCases/use-after-scope.cc index 1aa6758229dd1..d92dae6572cec 100644 --- a/test/asan/TestCases/use-after-scope.cc +++ b/test/asan/TestCases/use-after-scope.cc @@ -1,16 +1,17 @@ // RUN: %clangxx_asan -O1 -fsanitize-address-use-after-scope %s -o %t && \ // RUN: not %run %t 2>&1 | FileCheck %s -int *p = 0; +volatile int *p = 0; int main() { { int x = 0; p = &x; } - return *p; // BOOM + *p = 5; // BOOM // CHECK: ERROR: AddressSanitizer: stack-use-after-scope // CHECK: #0 0x{{.*}} in main {{.*}}use-after-scope.cc:[[@LINE-2]] // CHECK: Address 0x{{.*}} is located in stack of thread T{{.*}} at offset [[OFFSET:[^ ]+]] in frame // {{\[}}[[OFFSET]], {{[0-9]+}}) 'x' + return 0; } diff --git a/test/asan/TestCases/vla_chrome_testcase.cc b/test/asan/TestCases/vla_chrome_testcase.cc index 8ee040120c48a..a8771800609d8 100644 --- a/test/asan/TestCases/vla_chrome_testcase.cc +++ b/test/asan/TestCases/vla_chrome_testcase.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-allocas %s -o %t +// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-dynamic-allocas %s -o %t // RUN: not %run %t 2>&1 | FileCheck %s // diff --git a/test/asan/TestCases/vla_condition_overflow.cc b/test/asan/TestCases/vla_condition_overflow.cc index 17f28d823252e..cf42d794e9d5a 100644 --- a/test/asan/TestCases/vla_condition_overflow.cc +++ b/test/asan/TestCases/vla_condition_overflow.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-allocas %s -o %t +// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-dynamic-allocas %s -o %t // RUN: not %run %t 2>&1 | FileCheck %s // // REQUIRES: stable-runtime diff --git a/test/asan/TestCases/vla_loop_overfow.cc b/test/asan/TestCases/vla_loop_overfow.cc index 4f20c8d19d141..b6a5864c0f64b 100644 --- a/test/asan/TestCases/vla_loop_overfow.cc +++ b/test/asan/TestCases/vla_loop_overfow.cc @@ -1,4 +1,4 @@ -// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-allocas %s -o %t +// RUN: %clangxx_asan -O0 -mllvm -asan-instrument-dynamic-allocas %s -o %t // RUN: not %run %t 2>&1 | FileCheck %s // // REQUIRES: stable-runtime diff --git a/test/asan/android_commands/android_run.py b/test/asan/android_commands/android_run.py index 272d2110e5ade..f4ea52bec5880 100755 --- a/test/asan/android_commands/android_run.py +++ b/test/asan/android_commands/android_run.py @@ -1,6 +1,6 @@ #!/usr/bin/python -import os, sys, subprocess, tempfile +import os, signal, sys, subprocess, tempfile from android_common import * ANDROID_TMPDIR = '/data/local/tmp/Output' @@ -11,8 +11,7 @@ device_binary = os.path.join(ANDROID_TMPDIR, os.path.basename(sys.argv[0])) def build_env(): args = [] # Android linker ignores RPATH. Set LD_LIBRARY_PATH to Output dir. - args.append('LD_LIBRARY_PATH=%s:%s' % - (ANDROID_TMPDIR, os.environ.get('LD_LIBRARY_PATH', ''))) + args.append('LD_LIBRARY_PATH=%s' % (ANDROID_TMPDIR,)) for (key, value) in os.environ.items(): if key in ['ASAN_OPTIONS', 'ASAN_ACTIVATION_OPTIONS']: args.append('%s="%s"' % (key, value)) @@ -34,4 +33,9 @@ if ret != 0: sys.stdout.write(pull_from_device(device_stdout)) sys.stderr.write(pull_from_device(device_stderr)) -sys.exit(int(pull_from_device(device_exitcode))) +retcode = int(pull_from_device(device_exitcode)) +# If the device process died with a signal, do abort(). +# Not exactly the same, but good enough to fool "not --crash". +if retcode > 128: + os.kill(os.getpid(), signal.SIGABRT) +sys.exit(retcode) diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg index 894c3f859fbdb..1059f393ab34f 100644 --- a/test/asan/lit.cfg +++ b/test/asan/lit.cfg @@ -37,6 +37,12 @@ if config.host_os == 'Darwin': # Also, make sure we do not overwhelm the syslog while testing. default_asan_opts = 'abort_on_error=0' default_asan_opts += ':log_to_syslog=0' +elif config.android: + # The same as on Darwin, we default to "abort_on_error=1" which slows down + # testing. Also, all existing tests are using "not" instead of "not --crash" + # which does not work for abort()-terminated programs. + default_asan_opts = 'abort_on_error=0' + if default_asan_opts: config.environment['ASAN_OPTIONS'] = default_asan_opts default_asan_opts += ':' @@ -77,14 +83,26 @@ if config.target_arch == 's390x': clang_asan_static_cflags.append("-mbackchain") clang_asan_static_cxxflags = config.cxx_mode_flags + clang_asan_static_cflags +asan_dynamic_flags = [] if config.asan_dynamic: - clang_asan_cflags = clang_asan_static_cflags + ['-shared-libasan'] - clang_asan_cxxflags = clang_asan_static_cxxflags + ['-shared-libasan'] + asan_dynamic_flags = ["-shared-libasan"] + # On Windows, we need to simulate "clang-cl /MD" on the clang driver side. + if platform.system() == 'Windows': + asan_dynamic_flags += ["-D_MT", "-D_DLL", "-Wl,-nodefaultlib:libcmt,-defaultlib:msvcrt,-defaultlib:oldnames"] config.available_features.add("asan-dynamic-runtime") else: - clang_asan_cflags = clang_asan_static_cflags - clang_asan_cxxflags = clang_asan_static_cxxflags config.available_features.add("asan-static-runtime") +clang_asan_cflags = clang_asan_static_cflags + asan_dynamic_flags +clang_asan_cxxflags = clang_asan_static_cxxflags + asan_dynamic_flags + +# Add win32-(static|dynamic)-asan features to mark tests as passing or failing +# in those modes. lit doesn't support logical feature test combinations. +if platform.system() == 'Windows': + if config.asan_dynamic: + win_runtime_feature = "win32-dynamic-asan" + else: + win_runtime_feature = "win32-static-asan" + config.available_features.add(win_runtime_feature) asan_lit_source_dir = get_required_attr(config, "asan_lit_source_dir") if config.android == "1": @@ -98,11 +116,16 @@ else: def build_invocation(compile_flags): return " " + " ".join([clang_wrapper, config.clang] + compile_flags) + " " +# Clang driver link 'x86' (i686) architecture to 'i386'. +target_arch = config.target_arch +if (target_arch == "i686"): + target_arch = "i386" + config.substitutions.append( ("%clang ", build_invocation(target_cflags)) ) config.substitutions.append( ("%clangxx ", build_invocation(target_cxxflags)) ) config.substitutions.append( ("%clang_asan ", build_invocation(clang_asan_cflags)) ) config.substitutions.append( ("%clangxx_asan ", build_invocation(clang_asan_cxxflags)) ) -config.substitutions.append( ("%shared_libasan", "libclang_rt.asan-%s.so" % config.target_arch)) +config.substitutions.append( ("%shared_libasan", "libclang_rt.asan-%s.so" % target_arch)) if config.asan_dynamic: config.substitutions.append( ("%clang_asan_static ", build_invocation(clang_asan_static_cflags)) ) config.substitutions.append( ("%clangxx_asan_static ", build_invocation(clang_asan_static_cxxflags)) ) @@ -124,6 +147,14 @@ if platform.system() == 'Windows': config.substitutions.append( ("%asan_cxx_lib", base_lib % "_cxx") ) config.substitutions.append( ("%asan_dll_thunk", base_lib % "_dll_thunk") ) +if platform.system() == 'Windows': + # Don't use -std=c++11 on Windows, as the driver will detect the appropriate + # default needed to use with the STL. + config.substitutions.append(("%stdcxx11 ", "")) +else: + # Some tests uses C++11 features such as lambdas and need to pass -std=c++11. + config.substitutions.append(("%stdcxx11 ", "-std=c++11 ")) + # FIXME: De-hardcode this path. asan_source_dir = os.path.join( get_required_attr(config, "compiler_rt_src_root"), "lib", "asan") @@ -186,12 +217,27 @@ if config.compiler_id == 'GNU': libasan_dir = os.path.join(gcc_dir, "..", "lib" + config.bits) push_dynamic_library_lookup_path(config, libasan_dir) +# Add the RT libdir to PATH directly so that we can successfully run the gtest +# binary to list its tests. +if config.host_os == 'Windows' and config.asan_dynamic: + os.environ['PATH'] = os.path.pathsep.join([config.compiler_rt_libdir, + os.environ.get('PATH', '')]) + # Default test suffixes. config.suffixes = ['.c', '.cc', '.cpp'] if config.host_os == 'Darwin': config.suffixes.append('.mm') +if config.host_os == 'Windows': + config.substitutions.append(('%fPIC', '')) + config.substitutions.append(('%fPIE', '')) + config.substitutions.append(('%pie', '')) +else: + config.substitutions.append(('%fPIC', '-fPIC')) + config.substitutions.append(('%fPIE', '-fPIE')) + config.substitutions.append(('%pie', '-pie')) + # Only run the tests on supported OSs. if config.host_os not in ['Linux', 'Darwin', 'FreeBSD', 'Windows']: config.unsupported = True diff --git a/test/builtins/Unit/cpu_model_test.c b/test/builtins/Unit/cpu_model_test.c index 5a918bde7dda8..6a170372d970d 100644 --- a/test/builtins/Unit/cpu_model_test.c +++ b/test/builtins/Unit/cpu_model_test.c @@ -11,6 +11,8 @@ // //===----------------------------------------------------------------------===// +// REQUIRES: x86-target-arch + int main (void) { if(__builtin_cpu_supports("avx2")) return 4; diff --git a/test/builtins/Unit/negdf2vfp_test.c b/test/builtins/Unit/negdf2vfp_test.c index f0e66777e3a11..f673b92cfc874 100644 --- a/test/builtins/Unit/negdf2vfp_test.c +++ b/test/builtins/Unit/negdf2vfp_test.c @@ -11,14 +11,15 @@ // //===----------------------------------------------------------------------===// +#include "int_lib.h" #include <stdio.h> #include <stdlib.h> #include <math.h> +#if __arm__ extern COMPILER_RT_ABI double __negdf2vfp(double a); -#if __arm__ int test__negdf2vfp(double a) { double actual = __negdf2vfp(a); diff --git a/test/builtins/Unit/subdf3vfp_test.c b/test/builtins/Unit/subdf3vfp_test.c index 5d5d7117088f0..6e8d5a1aaa5ab 100644 --- a/test/builtins/Unit/subdf3vfp_test.c +++ b/test/builtins/Unit/subdf3vfp_test.c @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "int_lib.h" #include <stdio.h> #include <stdlib.h> #include <math.h> diff --git a/test/cfi/CMakeLists.txt b/test/cfi/CMakeLists.txt index 4c4debaf1a876..bd51eacb66754 100644 --- a/test/cfi/CMakeLists.txt +++ b/test/cfi/CMakeLists.txt @@ -11,16 +11,19 @@ configure_lit_site_cfg( ) set(CFI_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) +list(APPEND CFI_TEST_DEPS + ubsan + stats +) +if(COMPILER_RT_HAS_CFI) + list(APPEND CFI_TEST_DEPS cfi) +endif() + if(NOT COMPILER_RT_STANDALONE_BUILD) list(APPEND CFI_TEST_DEPS opt - ubsan - stats sanstats ) - if(COMPILER_RT_HAS_CFI) - list(APPEND CFI_TEST_DEPS cfi) - endif() if(LLVM_ENABLE_PIC AND LLVM_BINUTILS_INCDIR) list(APPEND CFI_TEST_DEPS LLVMgold diff --git a/test/cfi/cross-dso/stats.cpp b/test/cfi/cross-dso/stats.cpp index 3d25d7730c775..6566ea2fc2633 100644 --- a/test/cfi/cross-dso/stats.cpp +++ b/test/cfi/cross-dso/stats.cpp @@ -16,24 +16,24 @@ extern "C" void nvcall(A *a); #ifdef SHARED_LIB extern "C" __attribute__((noinline)) void vcall(A *a) { - // CHECK: stats.cpp:[[@LINE+1]] vcall cfi-vcall 37 + // CHECK: stats.cpp:[[@LINE+1]] vcall.cfi cfi-vcall 37 a->vf(); } extern "C" __attribute__((noinline)) void nvcall(A *a) { - // CHECK: stats.cpp:[[@LINE+1]] nvcall cfi-nvcall 51 + // CHECK: stats.cpp:[[@LINE+1]] nvcall.cfi cfi-nvcall 51 a->nvf(); } #else extern "C" __attribute__((noinline)) A *dcast(A *a) { - // CHECK: stats.cpp:[[@LINE+1]] dcast cfi-derived-cast 24 + // CHECK: stats.cpp:[[@LINE+1]] dcast.cfi cfi-derived-cast 24 return (A *)(ABase *)a; } extern "C" __attribute__((noinline)) A *ucast(A *a) { - // CHECK: stats.cpp:[[@LINE+1]] ucast cfi-unrelated-cast 81 + // CHECK: stats.cpp:[[@LINE+1]] ucast.cfi cfi-unrelated-cast 81 return (A *)(char *)a; } diff --git a/test/cfi/icall/weak.c b/test/cfi/icall/weak.c new file mode 100644 index 0000000000000..40739911109c8 --- /dev/null +++ b/test/cfi/icall/weak.c @@ -0,0 +1,15 @@ +// Test that weak symbols stay weak. +// RUN: %clang_cfi -lm -o %t1 %s && %t1 +// XFAIL: darwin + +__attribute__((weak)) void does_not_exist(void); + +__attribute__((noinline)) +void foo(void (*p)(void)) { + p(); +} + +int main(int argc, char **argv) { + if (does_not_exist) + foo(does_not_exist); +} diff --git a/test/cfi/simple-fail.cpp b/test/cfi/simple-fail.cpp index 92b1322718f89..595ca1617a02a 100644 --- a/test/cfi/simple-fail.cpp +++ b/test/cfi/simple-fail.cpp @@ -52,6 +52,9 @@ // RUN: %clangxx -o %t18 %s // RUN: %t18 2>&1 | FileCheck --check-prefix=NCFI %s +// RUN: %clangxx_cfi -DCHECK_NO_SANITIZE_CFI -o %t19 %s +// RUN: %t19 2>&1 | FileCheck --check-prefix=NCFI %s + // Tests that the CFI mechanism crashes the program when making a virtual call // to an object of the wrong class but with a compatible vtable, by casting a // pointer to such an object and attempting to make a call through it. @@ -73,6 +76,9 @@ struct B { void B::f() {} +#if defined(CHECK_NO_SANITIZE_CFI) +__attribute__((no_sanitize("cfi"))) +#endif int main() { create_derivers<B>(); diff --git a/test/cfi/two-vcalls.cpp b/test/cfi/two-vcalls.cpp new file mode 100644 index 0000000000000..854b3e0059c12 --- /dev/null +++ b/test/cfi/two-vcalls.cpp @@ -0,0 +1,60 @@ +// RUN: %clangxx_cfi_diag -o %t %s +// RUN: %t 2>&1 | FileCheck %s + +// This test checks that we don't generate two type checks, +// if two virtual calls are in the same function. + +// UNSUPPORTED: win32 +// REQUIRES: cxxabi + +// TODO(krasin): implement the optimization to not emit two type checks. +// XFAIL: * +#include <stdio.h> + +class Base { + public: + virtual void Foo() { + fprintf(stderr, "Base::Foo\n"); + } + + virtual void Bar() { + fprintf(stderr, "Base::Bar\n"); + } +}; + +class Derived : public Base { + public: + void Foo() override { + fprintf(stderr, "Derived::Foo\n"); + } + + void Bar() override { + printf("Derived::Bar\n"); + } +}; + +__attribute__((noinline)) void print(Base* ptr) { + ptr->Foo(); + // Corrupt the vtable pointer. We expect that the optimization will + // check vtable before the first vcall then store it in a local + // variable, and reuse it for the second vcall. With no optimization, + // CFI will complain about the virtual table being corrupted. + *reinterpret_cast<void**>(ptr) = 0; + ptr->Bar(); +} + + +int main() { + Base b; + Derived d; + // CHECK: Base::Foo + // CHECK: Base::Bar + print(&b); + + // CHECK: Derived::Foo + // CHECK-NOT: runtime error + // CHECK: Derived::Bar + print(&d); + + return 0; +} diff --git a/test/dfsan/CMakeLists.txt b/test/dfsan/CMakeLists.txt index c2baf930d7685..04035faeddfe9 100644 --- a/test/dfsan/CMakeLists.txt +++ b/test/dfsan/CMakeLists.txt @@ -10,16 +10,7 @@ endif() foreach(arch ${DFSAN_TEST_ARCH}) set(DFSAN_TEST_TARGET_ARCH ${arch}) string(TOLOWER "-${arch}" DFSAN_TEST_CONFIG_SUFFIX) - if(ANDROID OR ${arch} MATCHES "arm|aarch64") - # This is only true if we are cross-compiling. - # Build all tests with host compiler and use host tools. - set(DFSAN_TEST_TARGET_CC ${COMPILER_RT_TEST_COMPILER}) - set(DFSAN_TEST_TARGET_CFLAGS ${COMPILER_RT_TEST_COMPILER_CFLAGS}) - else() - get_target_flags_for_arch(${arch} DFSAN_TEST_TARGET_CFLAGS) - string(REPLACE ";" " " DFSAN_TEST_TARGET_CFLAGS "${DFSAN_TEST_TARGET_CFLAGS}") - endif() - + get_test_cc_for_arch(${arch} DFSAN_TEST_TARGET_CC DFSAN_TEST_TARGET_CFLAGS) string(TOUPPER ${arch} ARCH_UPPER_CASE) set(CONFIG_NAME ${ARCH_UPPER_CASE}Config) diff --git a/test/dfsan/custom.cc b/test/dfsan/custom.cc index 71422f7ce834f..c96d94053986e 100644 --- a/test/dfsan/custom.cc +++ b/test/dfsan/custom.cc @@ -3,6 +3,8 @@ // RUN: %clang_dfsan -DSTRICT_DATA_DEPENDENCIES %s -o %t && %run %t // RUN: %clang_dfsan -DSTRICT_DATA_DEPENDENCIES -mllvm -dfsan-args-abi %s -o %t && %run %t +// XFAIL: target-is-mips64el + // Tests custom implementations of various glibc functions. #include <sanitizer/dfsan_interface.h> diff --git a/test/dfsan/write_callback.c b/test/dfsan/write_callback.c index 3ba027a0a46ae..31470efa9e879 100644 --- a/test/dfsan/write_callback.c +++ b/test/dfsan/write_callback.c @@ -3,6 +3,7 @@ // Tests that the custom implementation of write() does writes with or without // a callback set using dfsan_set_write_callback(). +// REQUIRES: stable-runtime #include <sanitizer/dfsan_interface.h> diff --git a/test/esan/TestCases/mmap-shadow-conflict.c b/test/esan/TestCases/mmap-shadow-conflict.c index 4b3c58b06825c..8e86bba4adb1e 100644 --- a/test/esan/TestCases/mmap-shadow-conflict.c +++ b/test/esan/TestCases/mmap-shadow-conflict.c @@ -1,26 +1,40 @@ // RUN: %clang_esan_frag -O0 %s -o %t 2>&1 -// RUN: %env_esan_opts=verbosity=1 %run %t 2>&1 | FileCheck %s +// RUN: %env_esan_opts=verbosity=1 %run %t 2>&1 | FileCheck --check-prefix=%arch --check-prefix=CHECK %s #include <unistd.h> #include <sys/mman.h> #include <stdio.h> int main(int argc, char **argv) { +#if defined(__mips64) + void *Map = mmap((void *)0x0000001600000000ULL, 0x1000, PROT_READ, + MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0); +#else void *Map = mmap((void *)0x0000016000000000ULL, 0x1000, PROT_READ, MAP_ANON|MAP_PRIVATE|MAP_FIXED, -1, 0); +#endif if (Map == (void *)-1) fprintf(stderr, "map failed\n"); else fprintf(stderr, "mapped %p\n", Map); +#if defined(__mips64) + Map = mmap((void *)0x0000001600000000ULL, 0x1000, PROT_READ, + MAP_ANON|MAP_PRIVATE, -1, 0); +#else Map = mmap((void *)0x0000016000000000ULL, 0x1000, PROT_READ, MAP_ANON|MAP_PRIVATE, -1, 0); +#endif fprintf(stderr, "mapped %p\n", Map); // CHECK: in esan::initializeLibrary // (There can be a re-exec for stack limit here.) - // CHECK: Shadow scale=2 offset=0x440000000000 - // CHECK-NEXT: Shadow #0: [110000000000-114000000000) (256GB) - // CHECK-NEXT: Shadow #1: [124000000000-12c000000000) (512GB) - // CHECK-NEXT: Shadow #2: [148000000000-150000000000) (512GB) + // x86_64: Shadow scale=2 offset=0x440000000000 + // x86_64-NEXT: Shadow #0: [110000000000-114000000000) (256GB) + // x86_64-NEXT: Shadow #1: [124000000000-12c000000000) (512GB) + // x86_64-NEXT: Shadow #2: [148000000000-150000000000) (512GB) + // mips64: Shadow scale=2 offset=0x4400000000 + // mips64-NEXT: Shadow #0: [1140000000-1180000000) (1GB) + // mips64-NEXT: Shadow #1: [1380000000-13c0000000) (1GB) + // mips64-NEXT: Shadow #2: [14c0000000-1500000000) (1GB) // CHECK-NEXT: mmap conflict: {{.*}} // CHECK-NEXT: map failed // CHECK-NEXT: mmap conflict: {{.*}} diff --git a/test/esan/TestCases/struct-simple.cpp b/test/esan/TestCases/struct-simple.cpp index c52154e094210..7ec9761fffa85 100644 --- a/test/esan/TestCases/struct-simple.cpp +++ b/test/esan/TestCases/struct-simple.cpp @@ -115,21 +115,21 @@ int main(int argc, char **argv) { // CHECK: in esan::initializeCacheFrag // CHECK-NEXT: in esan::processCompilationUnitInit // CHECK-NEXT: in esan::processCacheFragCompilationUnitInit: {{.*}}struct-simple.cpp with 6 class(es)/struct(s) - // CHECK-NEXT: Register struct.A#2#11#11: 2 fields - // CHECK-NEXT: Register struct.B#2#3#2: 2 fields - // CHECK-NEXT: Register union.U#1#3: 1 fields - // CHECK-NEXT: Register struct.S#2#11#11: 2 fields - // CHECK-NEXT: Register struct.D#3#14#11#11: 3 fields - // CHECK-NEXT: Register struct.anon#3#11#11#11: 3 fields + // CHECK-NEXT: Register struct.A$2$11$11: 2 fields + // CHECK-NEXT: Register struct.B$2$3$2: 2 fields + // CHECK-NEXT: Register union.U$1$3: 1 fields + // CHECK-NEXT: Register struct.S$2$11$11: 2 fields + // CHECK-NEXT: Register struct.D$3$14$11$11: 3 fields + // CHECK-NEXT: Register struct.anon$3$11$11$11: 3 fields // CHECK-NEXT: in esan::processCompilationUnitInit // CHECK-NEXT: in esan::processCacheFragCompilationUnitInit: {{.*}}struct-simple.cpp with 0 class(es)/struct(s) // CHECK-NEXT: in esan::processCompilationUnitInit // CHECK-NEXT: in esan::processCacheFragCompilationUnitInit: {{.*}}struct-simple.cpp with 5 class(es)/struct(s) - // CHECK-NEXT: Register class.C#3#14#13#13: 3 fields - // CHECK-NEXT: Register struct.anon#2#11#11: 2 fields - // CHECK-NEXT: Register union.anon#1#3: 1 fields - // CHECK-NEXT: Duplicated struct.S#2#11#11: 2 fields - // CHECK-NEXT: Register struct.D#3#11#11#11: 3 fields + // CHECK-NEXT: Register class.C$3$14$13$13: 3 fields + // CHECK-NEXT: Register struct.anon$2$11$11: 2 fields + // CHECK-NEXT: Register union.anon$1$3: 1 fields + // CHECK-NEXT: Duplicated struct.S$2$11$11: 2 fields + // CHECK-NEXT: Register struct.D$3$11$11$11: 3 fields struct C c[2]; struct S s; struct D d; @@ -148,24 +148,24 @@ int main(int argc, char **argv) { // CHECK-NEXT: in esan::finalizeCacheFrag // CHECK-NEXT: in esan::processCompilationUnitExit // CHECK-NEXT: in esan::processCacheFragCompilationUnitExit: {{.*}}struct-simple.cpp with 5 class(es)/struct(s) - // CHECK-NEXT: Unregister class.C#3#14#13#13: 3 fields + // CHECK-NEXT: Unregister class.C$3$14$13$13: 3 fields // CHECK-NEXT: {{.*}} class C // CHECK-NEXT: {{.*}} size = 32, count = 5, ratio = 3, array access = 5 // CHECK-NEXT: {{.*}} # 0: offset = 0, size = 8, count = 2, type = %struct.anon = type { i32, i32 } // CHECK-NEXT: {{.*}} # 1: offset = 8, size = 8, count = 2, type = %union.anon = type { double } // CHECK-NEXT: {{.*}} # 2: offset = 16, size = 10, count = 1, type = [10 x i8] - // CHECK-NEXT: Unregister struct.anon#2#11#11: 2 fields + // CHECK-NEXT: Unregister struct.anon$2$11$11: 2 fields // CHECK-NEXT: {{.*}} struct anon // CHECK-NEXT: {{.*}} size = 8, count = 2, ratio = 1, array access = 0 // CHECK-NEXT: {{.*}} # 0: offset = 0, size = 4, count = 1, type = i32 // CHECK-NEXT: {{.*}} # 1: offset = 4, size = 4, count = 1, type = i32 - // CHECK-NEXT: Unregister union.anon#1#3: 1 fields - // CHECK-NEXT: Unregister struct.S#2#11#11: 2 fields + // CHECK-NEXT: Unregister union.anon$1$3: 1 fields + // CHECK-NEXT: Unregister struct.S$2$11$11: 2 fields // CHECK-NEXT: {{.*}} struct S // CHECK-NEXT: {{.*}} size = 8, count = 2, ratio = 2, array access = 0 // CHECK-NEXT: {{.*}} # 0: count = 2 // CHECK-NEXT: {{.*}} # 1: count = 0 - // CHECK-NEXT: Unregister struct.D#3#11#11#11: 3 fields + // CHECK-NEXT: Unregister struct.D$3$11$11$11: 3 fields // CHECK-NEXT: {{.*}} struct D // CHECK-NEXT: {{.*}} size = 12, count = 2, ratio = 2, array access = 0 // CHECK-NEXT: {{.*}} # 0: offset = 0, size = 4, count = 1, type = i32 @@ -175,25 +175,25 @@ int main(int argc, char **argv) { // CHECK-NEXT: in esan::processCacheFragCompilationUnitExit: {{.*}}struct-simple.cpp with 0 class(es)/struct(s) // CHECK-NEXT: in esan::processCompilationUnitExit // CHECK-NEXT: in esan::processCacheFragCompilationUnitExit: {{.*}}struct-simple.cpp with 6 class(es)/struct(s) - // CHECK-NEXT: Unregister struct.A#2#11#11: 2 fields + // CHECK-NEXT: Unregister struct.A$2$11$11: 2 fields // CHECK-NEXT: {{.*}} struct A // CHECK-NEXT: {{.*}} size = 8, count = 2049, ratio = 2048, array access = 0 // CHECK-NEXT: {{.*}} # 0: count = 2048 // CHECK-NEXT: {{.*}} # 1: count = 1 - // CHECK-NEXT: Unregister struct.B#2#3#2: 2 fields + // CHECK-NEXT: Unregister struct.B$2$3$2: 2 fields // CHECK-NEXT: {{.*}} struct B // CHECK-NEXT: {{.*}} size = 16, count = 2097153, ratio = 2097152, array access = 0 // CHECK-NEXT: {{.*}} # 0: count = 1 // CHECK-NEXT: {{.*}} # 1: count = 2097152 - // CHECK-NEXT: Unregister union.U#1#3: 1 fields - // CHECK-NEXT: Duplicated struct.S#2#11#11: 2 fields - // CHECK-NEXT: Unregister struct.D#3#14#11#11: 3 fields + // CHECK-NEXT: Unregister union.U$1$3: 1 fields + // CHECK-NEXT: Duplicated struct.S$2$11$11: 2 fields + // CHECK-NEXT: Unregister struct.D$3$14$11$11: 3 fields // CHECK-NEXT: {{.*}} struct D // CHECK-NEXT: {{.*}} size = 128, count = 2097153, ratio = 2097153, array access = 0 // CHECK-NEXT: {{.*}} # 0: count = 1 // CHECK-NEXT: {{.*}} # 1: count = 0 // CHECK-NEXT: {{.*}} # 2: count = 2097152 - // CHECK-NEXT: Unregister struct.anon#3#11#11#11: 3 fields + // CHECK-NEXT: Unregister struct.anon$3$11$11$11: 3 fields // CHECK-NEXT: {{.*}} struct anon // CHECK-NEXT: {{.*}} size = 12, count = 2097152, ratio = 4194304, array access = 2097152 // CHECK-NEXT: {{.*}} # 0: count = 0 diff --git a/test/esan/TestCases/verbose-simple.c b/test/esan/TestCases/verbose-simple.c index 0d867bf55d9ef..5ac37e159295f 100644 --- a/test/esan/TestCases/verbose-simple.c +++ b/test/esan/TestCases/verbose-simple.c @@ -1,14 +1,18 @@ // RUN: %clang_esan_frag -O0 %s -o %t 2>&1 -// RUN: %env_esan_opts="verbosity=1 log_exe_name=1" %run %t 2>&1 | FileCheck %s +// RUN: %env_esan_opts="verbosity=1 log_exe_name=1" %run %t 2>&1 | FileCheck --check-prefix=%arch --check-prefix=CHECK %s int main(int argc, char **argv) { // CHECK: in esan::initializeLibrary // (There can be a re-exec for stack limit here.) - // CHECK: Shadow scale=2 offset=0x440000000000 - // CHECK-NEXT: Shadow #0: [110000000000-114000000000) (256GB) - // CHECK-NEXT: Shadow #1: [124000000000-12c000000000) (512GB) - // CHECK-NEXT: Shadow #2: [148000000000-150000000000) (512GB) - // CHECK-NEXT: in esan::finalizeLibrary - // CHECK-NEXT: ==verbose-simple{{.*}}EfficiencySanitizer: total struct field access count = 0 + // x86_64: Shadow scale=2 offset=0x440000000000 + // x86_64-NEXT: Shadow #0: [110000000000-114000000000) (256GB) + // x86_64-NEXT: Shadow #1: [124000000000-12c000000000) (512GB) + // x86_64-NEXT: Shadow #2: [148000000000-150000000000) (512GB) + // mips64: Shadow scale=2 offset=0x4400000000 + // mips64-NEXT: Shadow #0: [1140000000-1180000000) (1GB) + // mips64-NEXT: Shadow #1: [1380000000-13c0000000) (1GB) + // mips64-NEXT: Shadow #2: [14c0000000-1500000000) (1GB) + // CHECK: in esan::finalizeLibrary + // CHECK: ==verbose-simple{{.*}}EfficiencySanitizer: total struct field access count = 0 return 0; } diff --git a/test/esan/Unit/hashtable.cpp b/test/esan/Unit/hashtable.cpp new file mode 100644 index 0000000000000..390a427da255b --- /dev/null +++ b/test/esan/Unit/hashtable.cpp @@ -0,0 +1,179 @@ +// RUN: %clangxx_unit -esan-instrument-loads-and-stores=0 -O0 %s -o %t 2>&1 +// RUN: %env_esan_opts="record_snapshots=0" %run %t 2>&1 | FileCheck %s + +#include "esan/esan_hashtable.h" +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +class MyData { + public: + MyData(const char *Str) : RefCount(0) { Buf = strdup(Str); } + ~MyData() { + fprintf(stderr, " Destructor: %s.\n", Buf); + free(Buf); + } + bool operator==(MyData &Cmp) { return strcmp(Buf, Cmp.Buf) == 0; } + operator size_t() const { + size_t Res = 0; + for (int i = 0; i < strlen(Buf); ++i) + Res ^= Buf[i]; + return Res; + } + char *Buf; + int RefCount; +}; + +// We use a smart pointer wrapper to free the payload on hashtable removal. +struct MyDataPayload { + MyDataPayload() : Data(nullptr) {} + explicit MyDataPayload(MyData *Data) : Data(Data) { ++Data->RefCount; } + ~MyDataPayload() { + if (Data && --Data->RefCount == 0) { + fprintf(stderr, "Deleting %s.\n", Data->Buf); + delete Data; + } + } + MyDataPayload(const MyDataPayload &Copy) { + Data = Copy.Data; + ++Data->RefCount; + } + MyDataPayload & operator=(const MyDataPayload &Copy) { + if (this != &Copy) { + this->~MyDataPayload(); + Data = Copy.Data; + ++Data->RefCount; + } + return *this; + } + bool operator==(MyDataPayload &Cmp) { return *Data == *Cmp.Data; } + operator size_t() const { return (size_t)*Data; } + MyData *Data; +}; + +int main() +{ + __esan::HashTable<int, int> IntTable; + assert(IntTable.size() == 0); + + // Test iteration on an empty table. + int Count = 0; + for (auto Iter = IntTable.begin(); Iter != IntTable.end(); + ++Iter, ++Count) { + // Empty. + } + assert(Count == 0); + + bool Added = IntTable.add(4, 42); + assert(Added); + assert(!IntTable.add(4, 42)); + assert(IntTable.size() == 1); + int Value; + bool Found = IntTable.lookup(4, Value); + assert(Found && Value == 42); + + // Test iterator. + IntTable.lock(); + for (auto Iter = IntTable.begin(); Iter != IntTable.end(); + ++Iter, ++Count) { + assert((*Iter).Key == 4); + assert((*Iter).Data == 42); + } + IntTable.unlock(); + assert(Count == 1); + assert(Count == IntTable.size()); + assert(!IntTable.remove(5)); + assert(IntTable.remove(4)); + + // Test a more complex payload. + __esan::HashTable<int, MyDataPayload> DataTable(4); + MyDataPayload NewData(new MyData("mystring")); + Added = DataTable.add(4, NewData); + assert(Added); + MyDataPayload FoundData; + Found = DataTable.lookup(4, FoundData); + assert(Found && strcmp(FoundData.Data->Buf, "mystring") == 0); + assert(!DataTable.remove(5)); + assert(DataTable.remove(4)); + // Test resize. + for (int i = 0; i < 4; ++i) { + MyDataPayload MoreData(new MyData("delete-at-end")); + Added = DataTable.add(i+1, MoreData); + assert(Added); + assert(!DataTable.add(i+1, MoreData)); + } + for (int i = 0; i < 4; ++i) { + Found = DataTable.lookup(i+1, FoundData); + assert(Found && strcmp(FoundData.Data->Buf, "delete-at-end") == 0); + } + DataTable.lock(); + Count = 0; + for (auto Iter = DataTable.begin(); Iter != DataTable.end(); + ++Iter, ++Count) { + int Key = (*Iter).Key; + FoundData = (*Iter).Data; + assert(Key >= 1 && Key <= 4); + assert(strcmp(FoundData.Data->Buf, "delete-at-end") == 0); + } + DataTable.unlock(); + assert(Count == 4); + assert(Count == DataTable.size()); + + // Ensure the iterator supports a range-based for loop. + DataTable.lock(); + Count = 0; + for (auto Pair : DataTable) { + assert(Pair.Key >= 1 && Pair.Key <= 4); + assert(strcmp(Pair.Data.Data->Buf, "delete-at-end") == 0); + ++Count; + } + DataTable.unlock(); + assert(Count == 4); + assert(Count == DataTable.size()); + + // Test payload freeing via smart pointer wrapper. + __esan::HashTable<MyDataPayload, MyDataPayload, true> DataKeyTable; + MyDataPayload DataA(new MyData("string AB")); + DataKeyTable.lock(); + Added = DataKeyTable.add(DataA, DataA); + assert(Added); + Found = DataKeyTable.lookup(DataA, FoundData); + assert(Found && strcmp(FoundData.Data->Buf, "string AB") == 0); + MyDataPayload DataB(new MyData("string AB")); + Added = DataKeyTable.add(DataB, DataB); + assert(!Added); + DataKeyTable.remove(DataB); // Should free the DataA payload. + DataKeyTable.unlock(); + + // Test custom functors. + struct CustomHash { + size_t operator()(int Key) const { return Key % 4; } + }; + struct CustomEqual { + bool operator()(int Key1, int Key2) const { return Key1 %4 == Key2 % 4; } + }; + __esan::HashTable<int, int, false, CustomHash, CustomEqual> ModTable; + Added = ModTable.add(2, 42); + assert(Added); + Added = ModTable.add(6, 42); + assert(!Added); + + fprintf(stderr, "All checks passed.\n"); + return 0; +} +// CHECK: Deleting mystring. +// CHECK-NEXT: Destructor: mystring. +// CHECK-NEXT: All checks passed. +// CHECK-NEXT: Deleting string AB. +// CHECK-NEXT: Destructor: string AB. +// CHECK-NEXT: Deleting string AB. +// CHECK-NEXT: Destructor: string AB. +// CHECK-NEXT: Deleting delete-at-end. +// CHECK-NEXT: Destructor: delete-at-end. +// CHECK-NEXT: Deleting delete-at-end. +// CHECK-NEXT: Destructor: delete-at-end. +// CHECK-NEXT: Deleting delete-at-end. +// CHECK-NEXT: Destructor: delete-at-end. +// CHECK-NEXT: Deleting delete-at-end. +// CHECK-NEXT: Destructor: delete-at-end. diff --git a/test/esan/lit.cfg b/test/esan/lit.cfg index cf16a6b5df44b..8b8457d66e00d 100644 --- a/test/esan/lit.cfg +++ b/test/esan/lit.cfg @@ -40,5 +40,5 @@ config.substitutions.append(('%env_esan_opts=', config.suffixes = ['.c', '.cpp'] # EfficiencySanitizer tests are currently supported on Linux x86-64 only. -if config.host_os not in ['Linux'] or config.target_arch != 'x86_64': +if config.host_os not in ['Linux'] or config.target_arch not in ['x86_64', 'mips64'] : config.unsupported = True diff --git a/test/interception/CMakeLists.txt b/test/interception/CMakeLists.txt new file mode 100644 index 0000000000000..ff9e4b0adb86d --- /dev/null +++ b/test/interception/CMakeLists.txt @@ -0,0 +1,17 @@ +set(INTERCEPTION_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) +set(INTERCEPTION_TESTSUITES) + +# Unit tests. There are currently no unit tests capable to running on Apple or +# Android targets. +if(COMPILER_RT_INCLUDE_TESTS AND NOT ANDROID AND NOT APPLE) + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg) + list(APPEND INTERCEPTION_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit) + list(APPEND INTERCEPTION_TEST_DEPS InterceptionUnitTests) +endif() + +add_lit_testsuite(check-interception "Running the Interception tests" + ${INTERCEPTION_TESTSUITES} + DEPENDS ${INTERCEPTION_TEST_DEPS}) +set_target_properties(check-interception PROPERTIES FOLDER "Compiler-RT Misc") diff --git a/test/interception/Unit/lit.site.cfg.in b/test/interception/Unit/lit.site.cfg.in new file mode 100644 index 0000000000000..5d3e2f94f8ac7 --- /dev/null +++ b/test/interception/Unit/lit.site.cfg.in @@ -0,0 +1,14 @@ +@LIT_SITE_CFG_IN_HEADER@ + +# Load common config for all compiler-rt unit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/unittests/lit.common.unit.configured") + +# Setup config name. +config.name = 'Interception-Unit' + +# Setup test source and exec root. For unit tests, we define +# it as build directory with interception tests. +# FIXME: De-hardcode this path. +config.test_exec_root = os.path.join("@COMPILER_RT_BINARY_DIR@", "lib", + "interception", "tests") +config.test_source_root = config.test_exec_root diff --git a/test/lit.common.cfg b/test/lit.common.cfg index f19fde2f89eb0..1048c46f11bcb 100644 --- a/test/lit.common.cfg +++ b/test/lit.common.cfg @@ -52,7 +52,8 @@ possibly_dangerous_env_vars = ['ASAN_OPTIONS', 'DFSAN_OPTIONS', 'LSAN_OPTIONS', 'LIBCLANG_LOGGING', 'LIBCLANG_BGPRIO_INDEX', 'LIBCLANG_BGPRIO_EDIT', 'LIBCLANG_NOTHREADS', 'LIBCLANG_RESOURCE_USAGE', - 'LIBCLANG_CODE_COMPLETION_LOGGING'] + 'LIBCLANG_CODE_COMPLETION_LOGGING', + 'XRAY_OPTIONS'] # Clang/Win32 may refer to %INCLUDE%. vsvarsall.bat sets it. if platform.system() != 'Windows': possibly_dangerous_env_vars.append('INCLUDE') @@ -87,6 +88,9 @@ config.substitutions.append( ('%run', config.emulator) ) # Define CHECK-%os to check for OS-dependent output. config.substitutions.append( ('CHECK-%os', ("CHECK-" + config.host_os))) +# Define %arch to check for architecture-dependent output. +config.substitutions.append( ('%arch', (config.host_arch))) + if config.host_os == 'Windows': # FIXME: This isn't quite right. Specifically, it will succeed if the program # does not crash but exits with a non-zero exit code. We ought to merge @@ -103,6 +107,7 @@ if target_arch: config.available_features.add(target_arch + '-target-arch') if target_arch in ['x86_64', 'i386', 'i686']: config.available_features.add('x86-target-arch') + config.available_features.add(target_arch + '-' + config.host_os.lower()) compiler_rt_debug = getattr(config, 'compiler_rt_debug', False) if not compiler_rt_debug: @@ -136,6 +141,10 @@ if config.host_os == 'Darwin': except: pass + config.substitutions.append( ("%macos_min_target_10_11", "-mmacosx-version-min=10.11") ) +else: + config.substitutions.append( ("%macos_min_target_10_11", "") ) + sancovcc_path = os.path.join(llvm_tools_dir, "sancov") if os.path.exists(sancovcc_path): config.available_features.add("has_sancovcc") @@ -148,7 +157,7 @@ def is_linux_lto_supported(): if not os.path.exists(os.path.join(config.llvm_shlib_dir, 'LLVMgold.so')): return False - ld_cmd = subprocess.Popen([config.gold_executable, '--help'], stdout = subprocess.PIPE) + ld_cmd = subprocess.Popen([config.gold_executable, '--help'], stdout = subprocess.PIPE, env={'LANG': 'C'}) ld_out = ld_cmd.stdout.read().decode() ld_cmd.wait() @@ -175,6 +184,9 @@ elif config.host_os == 'Windows' and is_windows_lto_supported(): else: config.lto_supported = False +if config.lto_supported: + config.available_features.add('lto') + # Ask llvm-config about assertion mode. try: llvm_config_cmd = subprocess.Popen( diff --git a/test/lit.common.configured.in b/test/lit.common.configured.in index 35aa78c984f09..862d06bf2947d 100644 --- a/test/lit.common.configured.in +++ b/test/lit.common.configured.in @@ -17,7 +17,7 @@ set_default("llvm_obj_root", "@LLVM_BINARY_DIR@") set_default("compiler_rt_src_root", "@COMPILER_RT_SOURCE_DIR@") set_default("compiler_rt_obj_root", "@COMPILER_RT_BINARY_DIR@") set_default("llvm_tools_dir", "@LLVM_TOOLS_BINARY_DIR@") -set_default("llvm_shlib_dir", "@SHLIBDIR@") +set_default("llvm_shlib_dir", "@LLVM_LIBRARY_OUTPUT_INTDIR@") set_default("gold_executable", "@GOLD_EXECUTABLE@") set_default("clang", "@COMPILER_RT_TEST_COMPILER@") set_default("compiler_id", "@COMPILER_RT_TEST_COMPILER_ID@") @@ -28,6 +28,7 @@ set_default("emulator", "@COMPILER_RT_EMULATOR@") set_default("sanitizer_can_use_cxxabi", @SANITIZER_CAN_USE_CXXABI_PYBOOL@) set_default("has_lld", @COMPILER_RT_HAS_LLD_SOURCES_PYBOOL@) set_default("can_symbolize", @CAN_SYMBOLIZE@) +config.available_features.add('target-is-%s' % config.target_arch) # LLVM tools dir can be passed in lit parameters, so try to # apply substitution. diff --git a/test/lsan/CMakeLists.txt b/test/lsan/CMakeLists.txt index e3d363a1f2759..3324928ddb1c1 100644 --- a/test/lsan/CMakeLists.txt +++ b/test/lsan/CMakeLists.txt @@ -10,16 +10,7 @@ endif() foreach(arch ${LSAN_TEST_ARCH}) set(LSAN_TEST_TARGET_ARCH ${arch}) string(TOLOWER "-${arch}" LSAN_TEST_CONFIG_SUFFIX) - if(ANDROID OR ${arch} MATCHES "arm|aarch64") - # This is only true if we are cross-compiling. - # Build all tests with host compiler and use host tools. - set(LSAN_TEST_TARGET_CC ${COMPILER_RT_TEST_COMPILER}) - set(LSAN_TEST_TARGET_CFLAGS ${COMPILER_RT_TEST_COMPILER_CFLAGS}) - else() - get_target_flags_for_arch(${arch} LSAN_TEST_TARGET_CFLAGS) - string(REPLACE ";" " " LSAN_TEST_TARGET_CFLAGS "${LSAN_TEST_TARGET_CFLAGS}") - endif() - + get_test_cc_for_arch(${arch} LSAN_TEST_TARGET_CC LSAN_TEST_TARGET_CFLAGS) string(TOUPPER ${arch} ARCH_UPPER_CASE) set(LSAN_LIT_TEST_MODE "Standalone") set(CONFIG_NAME ${ARCH_UPPER_CASE}LsanConfig) diff --git a/test/lsan/TestCases/cleanup_in_tsd_destructor.c b/test/lsan/TestCases/cleanup_in_tsd_destructor.c index debf05c20473f..6da759563451c 100644 --- a/test/lsan/TestCases/cleanup_in_tsd_destructor.c +++ b/test/lsan/TestCases/cleanup_in_tsd_destructor.c @@ -14,6 +14,7 @@ #include <stdlib.h> #include "sanitizer/lsan_interface.h" +#include "sanitizer_common/print_address.h" pthread_key_t key; __thread void *p; @@ -25,7 +26,7 @@ void key_destructor(void *arg) { void *thread_func(void *arg) { p = malloc(1337); - fprintf(stderr, "Test alloc: %p.\n", p); + print_address("Test alloc: ", 1, p); int res = pthread_setspecific(key, (void*)1); assert(res == 0); return 0; @@ -41,5 +42,5 @@ int main() { assert(res == 0); return 0; } -// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] // CHECK: [[ADDR]] (1337 bytes) diff --git a/test/lsan/TestCases/guard-page.c b/test/lsan/TestCases/guard-page.c index 5c70a9f08aca5..25d63e2720c3a 100644 --- a/test/lsan/TestCases/guard-page.c +++ b/test/lsan/TestCases/guard-page.c @@ -22,6 +22,7 @@ static void die(const char* msg, int err) { static void ctxfunc() { pthread_mutex_lock(&mutex); ctxfunc_started = 1; + // printf("ctxfunc\n"); pthread_cond_signal(&cond); pthread_mutex_unlock(&mutex); // Leave this context alive when the program exits. @@ -35,11 +36,11 @@ static void* thread(void* arg) { if (getcontext(&ctx) < 0) die("getcontext", 0); - stack = malloc(1 << 10); + stack = malloc(1 << 11); if (stack == NULL) die("malloc", 0); ctx.uc_stack.ss_sp = stack; - ctx.uc_stack.ss_size = 1 << 10; + ctx.uc_stack.ss_size = 1 << 11; makecontext(&ctx, ctxfunc, 0); setcontext(&ctx); die("setcontext", 0); diff --git a/test/lsan/TestCases/large_allocation_leak.cc b/test/lsan/TestCases/large_allocation_leak.cc index f41143a8a501d..9d5698c9f8a65 100644 --- a/test/lsan/TestCases/large_allocation_leak.cc +++ b/test/lsan/TestCases/large_allocation_leak.cc @@ -5,14 +5,15 @@ #include <stdio.h> #include <stdlib.h> +#include "sanitizer_common/print_address.h" int main() { // maxsize in primary allocator is always less than this (1 << 25). void *large_alloc = malloc(33554432); - fprintf(stderr, "Test alloc: %p.\n", large_alloc); + print_address("Test alloc: ", 1, large_alloc); return 0; } -// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] // CHECK: LeakSanitizer: detected memory leaks // CHECK: [[ADDR]] (33554432 bytes) // CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/pointer_to_self.cc b/test/lsan/TestCases/pointer_to_self.cc index 63bde2ccf35df..40c122811f181 100644 --- a/test/lsan/TestCases/pointer_to_self.cc +++ b/test/lsan/TestCases/pointer_to_self.cc @@ -6,13 +6,14 @@ #include <stdio.h> #include <stdlib.h> +#include "sanitizer_common/print_address.h" int main() { void *p = malloc(1337); *reinterpret_cast<void **>(p) = p; - fprintf(stderr, "Test alloc: %p.\n", p); + print_address("Test alloc: ", 1, p); } -// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] // CHECK: LeakSanitizer: detected memory leaks // CHECK: [[ADDR]] (1337 bytes) // CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/stale_stack_leak.cc b/test/lsan/TestCases/stale_stack_leak.cc index 4b8a54edf4cc5..770096b088883 100644 --- a/test/lsan/TestCases/stale_stack_leak.cc +++ b/test/lsan/TestCases/stale_stack_leak.cc @@ -6,6 +6,7 @@ #include <stdio.h> #include <stdlib.h> +#include "sanitizer_common/print_address.h" void **pp; @@ -18,7 +19,7 @@ void *PutPointerOnStaleStack(void *p) { void *locals[2048]; locals[0] = p; pp = &locals[0]; - fprintf(stderr, "Test alloc: %p.\n", locals[0]); + print_address("Test alloc: ", 1, locals[0]); return 0; } @@ -33,11 +34,11 @@ int main() { __attribute__((destructor)) __attribute__((no_sanitize_address)) void ConfirmPointerHasSurvived() { - fprintf(stderr, "Value after LSan: %p.\n", *pp); + print_address("Value after LSan: ", 1, *pp); } -// CHECK: Test alloc: [[ADDR:.*]]. -// CHECK-sanity: Test alloc: [[ADDR:.*]]. +// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] +// CHECK-sanity: Test alloc: [[ADDR:0x[0-9,a-f]+]] // CHECK: LeakSanitizer: detected memory leaks // CHECK: [[ADDR]] (1337 bytes) // CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: -// CHECK-sanity: Value after LSan: [[ADDR]]. +// CHECK-sanity: Value after LSan: [[ADDR]] diff --git a/test/lsan/TestCases/strace_test.cc b/test/lsan/TestCases/strace_test.cc new file mode 100644 index 0000000000000..b3568d0b44e80 --- /dev/null +++ b/test/lsan/TestCases/strace_test.cc @@ -0,0 +1,14 @@ +// Test that lsan reports a proper error when running under strace. +// RUN: %clangxx_lsan %s -o %t +// RUN: not strace -o /dev/null %run %t 2>&1 | FileCheck %s + +#include <stdio.h> +#include <stdlib.h> + +static volatile void *sink; + +int main() { + sink = malloc(42); +} +// CHECK: LeakSanitizer has encountered a fatal error +// CHECK: HINT: LeakSanitizer does not work under ptrace (strace, gdb, etc) diff --git a/test/lsan/TestCases/use_after_return.cc b/test/lsan/TestCases/use_after_return.cc index eb917c01ea80b..ed9cc785f0f5c 100644 --- a/test/lsan/TestCases/use_after_return.cc +++ b/test/lsan/TestCases/use_after_return.cc @@ -8,16 +8,17 @@ #include <stdio.h> #include <stdlib.h> +#include "sanitizer_common/print_address.h" int main() { void *stack_var = malloc(1337); - fprintf(stderr, "Test alloc: %p.\n", stack_var); + print_address("Test alloc: ", 1, stack_var); // Take pointer to variable, to ensure it's not optimized into a register. - fprintf(stderr, "Stack var at: %p.\n", &stack_var); + print_address("Stack var at: ", 1, &stack_var); // Do not return from main to prevent the pointer from going out of scope. exit(0); } -// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] // CHECK: LeakSanitizer: detected memory leaks // CHECK: [[ADDR]] (1337 bytes) // CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/use_globals_initialized.cc b/test/lsan/TestCases/use_globals_initialized.cc index 172d22a9f0564..45c12dc4e120b 100644 --- a/test/lsan/TestCases/use_globals_initialized.cc +++ b/test/lsan/TestCases/use_globals_initialized.cc @@ -7,15 +7,16 @@ #include <stdio.h> #include <stdlib.h> +#include "sanitizer_common/print_address.h" void *data_var = (void *)1; int main() { data_var = malloc(1337); - fprintf(stderr, "Test alloc: %p.\n", data_var); + print_address("Test alloc: ", 1, data_var); return 0; } -// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] // CHECK: LeakSanitizer: detected memory leaks // CHECK: [[ADDR]] (1337 bytes) // CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/use_globals_uninitialized.cc b/test/lsan/TestCases/use_globals_uninitialized.cc index 2daa661611f42..c198fcc7cbbb1 100644 --- a/test/lsan/TestCases/use_globals_uninitialized.cc +++ b/test/lsan/TestCases/use_globals_uninitialized.cc @@ -7,15 +7,16 @@ #include <stdio.h> #include <stdlib.h> +#include "sanitizer_common/print_address.h" void *bss_var; int main() { bss_var = malloc(1337); - fprintf(stderr, "Test alloc: %p.\n", bss_var); + print_address("Test alloc: ", 1, bss_var); return 0; } -// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] // CHECK: LeakSanitizer: detected memory leaks // CHECK: [[ADDR]] (1337 bytes) // CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/use_poisoned_asan.cc b/test/lsan/TestCases/use_poisoned_asan.cc index a1c544c55f288..5acceeb8ce0a2 100644 --- a/test/lsan/TestCases/use_poisoned_asan.cc +++ b/test/lsan/TestCases/use_poisoned_asan.cc @@ -9,17 +9,18 @@ #include <stdlib.h> #include <sanitizer/asan_interface.h> #include <assert.h> +#include "sanitizer_common/print_address.h" void **p; int main() { p = new void *; *p = malloc(1337); - fprintf(stderr, "Test alloc: %p.\n", *p); + print_address("Test alloc: ", 1, *p); __asan_poison_memory_region(p, sizeof(*p)); return 0; } -// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] // CHECK: LeakSanitizer: detected memory leaks // CHECK: [[ADDR]] (1337 bytes) // CHECK: SUMMARY: AddressSanitizer: diff --git a/test/lsan/TestCases/use_registers.cc b/test/lsan/TestCases/use_registers.cc index 74301a26c32c6..7647679f4796c 100644 --- a/test/lsan/TestCases/use_registers.cc +++ b/test/lsan/TestCases/use_registers.cc @@ -10,6 +10,7 @@ #include <sched.h> #include <stdio.h> #include <stdlib.h> +#include "sanitizer_common/print_address.h" extern "C" void *registers_thread_func(void *arg) { @@ -35,7 +36,7 @@ void *registers_thread_func(void *arg) { #else #error "Test is not supported on this architecture." #endif - fprintf(stderr, "Test alloc: %p.\n", p); + print_address("Test alloc: ", 1, p); fflush(stderr); __sync_fetch_and_xor(sync, 1); while (true) @@ -51,7 +52,7 @@ int main() { sched_yield(); return 0; } -// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] // CHECK: LeakSanitizer: detected memory leaks // CHECK: [[ADDR]] (1337 bytes) // CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/use_stacks.cc b/test/lsan/TestCases/use_stacks.cc index 7afcde15c733c..c32af68412606 100644 --- a/test/lsan/TestCases/use_stacks.cc +++ b/test/lsan/TestCases/use_stacks.cc @@ -7,14 +7,15 @@ #include <stdio.h> #include <stdlib.h> +#include "sanitizer_common/print_address.h" int main() { void *stack_var = malloc(1337); - fprintf(stderr, "Test alloc: %p.\n", stack_var); + print_address("Test alloc: ", 1, stack_var); // Do not return from main to prevent the pointer from going out of scope. exit(0); } -// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] // CHECK: LeakSanitizer: detected memory leaks // CHECK: [[ADDR]] (1337 bytes) // CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/use_stacks_threaded.cc b/test/lsan/TestCases/use_stacks_threaded.cc index a1d4383e95696..ac1fb466fa030 100644 --- a/test/lsan/TestCases/use_stacks_threaded.cc +++ b/test/lsan/TestCases/use_stacks_threaded.cc @@ -10,12 +10,13 @@ #include <sched.h> #include <stdio.h> #include <stdlib.h> +#include "sanitizer_common/print_address.h" extern "C" void *stacks_thread_func(void *arg) { int *sync = reinterpret_cast<int *>(arg); void *p = malloc(1337); - fprintf(stderr, "Test alloc: %p.\n", p); + print_address("Test alloc: ", 1, p); fflush(stderr); __sync_fetch_and_xor(sync, 1); while (true) @@ -31,7 +32,7 @@ int main() { sched_yield(); return 0; } -// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] // CHECK: LeakSanitizer: detected memory leaks // CHECK: [[ADDR]] (1337 bytes) // CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/use_tls_dynamic.cc b/test/lsan/TestCases/use_tls_dynamic.cc index 207894b0fffd4..927c5c4f768ea 100644 --- a/test/lsan/TestCases/use_tls_dynamic.cc +++ b/test/lsan/TestCases/use_tls_dynamic.cc @@ -12,6 +12,7 @@ #include <stdio.h> #include <stdlib.h> #include <string> +#include "sanitizer_common/print_address.h" int main(int argc, char *argv[]) { std::string path = std::string(argv[0]) + "-so.so"; @@ -26,10 +27,10 @@ int main(int argc, char *argv[]) { // If we don't know about dynamic TLS, we will return a false leak above. void **p_in_tls = StoreToTLS(p); assert(*p_in_tls == p); - fprintf(stderr, "Test alloc: %p.\n", p); + print_address("Test alloc: ", 1, p); return 0; } -// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] // CHECK: LeakSanitizer: detected memory leaks // CHECK: [[ADDR]] (1337 bytes) // CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/use_tls_pthread_specific_dynamic.cc b/test/lsan/TestCases/use_tls_pthread_specific_dynamic.cc index 14883712e6083..9ab4e1cdbc0e5 100644 --- a/test/lsan/TestCases/use_tls_pthread_specific_dynamic.cc +++ b/test/lsan/TestCases/use_tls_pthread_specific_dynamic.cc @@ -9,6 +9,7 @@ #include <pthread.h> #include <stdio.h> #include <stdlib.h> +#include "sanitizer_common/print_address.h" // From glibc: this many keys are stored in the thread descriptor directly. const unsigned PTHREAD_KEY_2NDLEVEL_SIZE = 32; @@ -28,10 +29,10 @@ int main() { void *p = malloc(1337); res = pthread_setspecific(key, p); assert(res == 0); - fprintf(stderr, "Test alloc: %p.\n", p); + print_address("Test alloc: ", 1, p); return 0; } -// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] // CHECK: LeakSanitizer: detected memory leaks // CHECK: [[ADDR]] (1337 bytes) // CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/use_tls_pthread_specific_static.cc b/test/lsan/TestCases/use_tls_pthread_specific_static.cc index 1fd5681b60808..be0bcf6287548 100644 --- a/test/lsan/TestCases/use_tls_pthread_specific_static.cc +++ b/test/lsan/TestCases/use_tls_pthread_specific_static.cc @@ -9,6 +9,7 @@ #include <pthread.h> #include <stdio.h> #include <stdlib.h> +#include "sanitizer_common/print_address.h" // From glibc: this many keys are stored in the thread descriptor directly. const unsigned PTHREAD_KEY_2NDLEVEL_SIZE = 32; @@ -22,10 +23,10 @@ int main() { void *p = malloc(1337); res = pthread_setspecific(key, p); assert(res == 0); - fprintf(stderr, "Test alloc: %p.\n", p); + print_address("Test alloc: ", 1, p); return 0; } -// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] // CHECK: LeakSanitizer: detected memory leaks // CHECK: [[ADDR]] (1337 bytes) // CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/use_tls_static.cc b/test/lsan/TestCases/use_tls_static.cc index 50db23abb825a..5ffaf166bcd5d 100644 --- a/test/lsan/TestCases/use_tls_static.cc +++ b/test/lsan/TestCases/use_tls_static.cc @@ -7,15 +7,16 @@ #include <stdio.h> #include <stdlib.h> +#include "sanitizer_common/print_address.h" __thread void *tls_var; int main() { tls_var = malloc(1337); - fprintf(stderr, "Test alloc: %p.\n", tls_var); + print_address("Test alloc: ", 1, tls_var); return 0; } -// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] // CHECK: LeakSanitizer: detected memory leaks // CHECK: [[ADDR]] (1337 bytes) // CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/use_unaligned.cc b/test/lsan/TestCases/use_unaligned.cc index 3e43ed4c092cb..86c3ed5200a36 100644 --- a/test/lsan/TestCases/use_unaligned.cc +++ b/test/lsan/TestCases/use_unaligned.cc @@ -7,17 +7,18 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include "sanitizer_common/print_address.h" void *arr[2]; int main() { void *p = malloc(1337); - fprintf(stderr, "Test alloc: %p.\n", p); + print_address("Test alloc: ", 1, p); char *char_arr = (char *)arr; memcpy(char_arr + 1, &p, sizeof(p)); return 0; } -// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Test alloc: [[ADDR:0x[0-9,a-f]+]] // CHECK: LeakSanitizer: detected memory leaks // CHECK: [[ADDR]] (1337 bytes) // CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg index a04c113269f29..6002e2d694442 100644 --- a/test/lsan/lit.common.cfg +++ b/test/lsan/lit.common.cfg @@ -31,8 +31,9 @@ config.name += config.name_suffix clang_cflags = ["-O0", config.target_cflags] + config.debug_info_flags clang_cxxflags = config.cxx_mode_flags + clang_cflags -clang_lsan_cflags = clang_cflags + lsan_cflags -clang_lsan_cxxflags = clang_cxxflags + lsan_cflags +lsan_incdir = config.test_source_root + "/../" +clang_lsan_cflags = clang_cflags + lsan_cflags + ["-I%s" % lsan_incdir] +clang_lsan_cxxflags = clang_cxxflags + lsan_cflags + ["-I%s" % lsan_incdir] config.clang_cflags = clang_cflags config.clang_cxxflags = clang_cxxflags diff --git a/test/msan/CMakeLists.txt b/test/msan/CMakeLists.txt index 176fb4ae1846b..171bcb9618ffe 100644 --- a/test/msan/CMakeLists.txt +++ b/test/msan/CMakeLists.txt @@ -10,16 +10,7 @@ endif() foreach(arch ${MSAN_TEST_ARCH}) set(MSAN_TEST_TARGET_ARCH ${arch}) string(TOLOWER "-${arch}" MSAN_TEST_CONFIG_SUFFIX) - if(ANDROID OR ${arch} MATCHES "arm|aarch64") - # This is only true if we are cross-compiling. - # Build all tests with host compiler and use host tools. - set(MSAN_TEST_TARGET_CC ${COMPILER_RT_TEST_COMPILER}) - set(MSAN_TEST_TARGET_CFLAGS ${COMPILER_RT_TEST_COMPILER_CFLAGS}) - else() - get_target_flags_for_arch(${arch} MSAN_TEST_TARGET_CFLAGS) - string(REPLACE ";" " " MSAN_TEST_TARGET_CFLAGS "${MSAN_TEST_TARGET_CFLAGS}") - endif() - + get_test_cc_for_arch(${arch} MSAN_TEST_TARGET_CC MSAN_TEST_TARGET_CFLAGS) string(TOUPPER ${arch} ARCH_UPPER_CASE) set(CONFIG_NAME ${ARCH_UPPER_CASE}Config) diff --git a/test/msan/Linux/forkpty.cc b/test/msan/Linux/forkpty.cc index ae5c7d96ca8a3..c9f04376fd743 100644 --- a/test/msan/Linux/forkpty.cc +++ b/test/msan/Linux/forkpty.cc @@ -1,6 +1,9 @@ // RUN: %clangxx_msan -O0 -g %s -lutil -o %t && %run %t + #include <assert.h> #include <pty.h> +#include <unistd.h> +#include <cstring> #include <sanitizer/msan_interface.h> @@ -12,6 +15,10 @@ main (int argc, char** argv) assert(__msan_test_shadow(&master, sizeof(master)) == -1); assert(__msan_test_shadow(&slave, sizeof(slave)) == -1); + char ttyname[255]; + ttyname_r(master, ttyname, sizeof(ttyname)); + assert(__msan_test_shadow(ttyname, strlen(ttyname) + 1) == -1); + int master2; forkpty(&master2, NULL, NULL, NULL); assert(__msan_test_shadow(&master2, sizeof(master2)) == -1); diff --git a/test/msan/Linux/obstack.cc b/test/msan/Linux/obstack.cc index f1f53be4c9b2c..0a81d8704f1e8 100644 --- a/test/msan/Linux/obstack.cc +++ b/test/msan/Linux/obstack.cc @@ -1,5 +1,5 @@ // RUN: %clangxx_msan -O0 -g %s -o %t && %run %t -// RUN: %clangxx_msan -O0 -g -DPOSITIVE %s -o %t && not %run %t |& FileCheck %s +// RUN: %clangxx_msan -O0 -g -DPOSITIVE %s -o %t && not %run %t 2>&1 | FileCheck %s #include <obstack.h> #include <sanitizer/msan_interface.h> @@ -30,7 +30,7 @@ int main(void) { __msan_check_mem_is_initialized(p, sizeof(data) + 1); } // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value - // CHECK: #0 0x{{.*}} in main{{.*}}obstack.cc:[[@LINE-30]] + // CHECK: #0 0x{{.*}} in main{{.*}}obstack.cc:[[@LINE-3]] #endif } obstack_free(&obs, 0); diff --git a/test/msan/Linux/process_vm_readv.cc b/test/msan/Linux/process_vm_readv.cc index b61578d1bfdad..0a0e0274b8a5c 100644 --- a/test/msan/Linux/process_vm_readv.cc +++ b/test/msan/Linux/process_vm_readv.cc @@ -1,5 +1,5 @@ // RUN: %clangxx_msan -std=c++11 -O0 %s -o %t && %run %t -// RUN: %clangxx_msan -std=c++11 -O0 %s -o %t -DPOSITIVE && not %run %t |& FileCheck %s +// RUN: %clangxx_msan -std=c++11 -O0 %s -o %t -DPOSITIVE && not %run %t 2>&1 | FileCheck %s #include <assert.h> #include <dlfcn.h> diff --git a/test/msan/Linux/syscalls_sigaction.cc b/test/msan/Linux/syscalls_sigaction.cc index 1297fae13d122..975ca2ba68772 100644 --- a/test/msan/Linux/syscalls_sigaction.cc +++ b/test/msan/Linux/syscalls_sigaction.cc @@ -11,7 +11,11 @@ #include <sanitizer/msan_interface.h> struct my_kernel_sigaction { +#if defined(__mips__) + long flags, handler; +#else long handler, flags, restorer; +#endif uint64_t mask[20]; // larger than any known platform }; @@ -35,6 +39,10 @@ int main() { memset(&act, 0, sizeof(act)); __msan_poison(&oldact, sizeof(oldact)); __sanitizer_syscall_post_rt_sigaction(0, SIGUSR1, &act, &oldact, 5); +#if defined(__mips__) + assert(__msan_test_shadow(&oldact, sizeof(oldact)) == sizeof(long)*2 + 5); +#else assert(__msan_test_shadow(&oldact, sizeof(oldact)) == sizeof(long)*3 + 5); #endif +#endif } diff --git a/test/msan/allocator_mapping.cc b/test/msan/allocator_mapping.cc index f47d9a63e09f8..533128f9a0f41 100644 --- a/test/msan/allocator_mapping.cc +++ b/test/msan/allocator_mapping.cc @@ -8,7 +8,7 @@ // This test only makes sense for the 64-bit allocator. The 32-bit allocator // does not have a fixed mapping. Exclude platforms that use the 32-bit // allocator. -// UNSUPPORTED: mips64,aarch64 +// UNSUPPORTED: target-is-mips64,target-is-mips64el,aarch64 #include <assert.h> #include <stdio.h> diff --git a/test/msan/backtrace.cc b/test/msan/backtrace.cc index 9cb883c5cf7d0..cde4e8fc1c9eb 100644 --- a/test/msan/backtrace.cc +++ b/test/msan/backtrace.cc @@ -15,7 +15,7 @@ void f() { if (!buf[i]) exit(1); char **s = backtrace_symbols(buf, sz); - assert(s > 0); + assert(s != 0); for (int i = 0; i < sz; ++i) printf("%d\n", (int)strlen(s[i])); } diff --git a/test/msan/chained_origin.cc b/test/msan/chained_origin.cc index ae72c10b6ac8d..7cab15284d2bc 100644 --- a/test/msan/chained_origin.cc +++ b/test/msan/chained_origin.cc @@ -1,21 +1,20 @@ // RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -O3 %s -o %t && \ // RUN: not %run %t >%t.out 2>&1 -// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-STACK < %t.out +// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%short-stack --check-prefix=CHECK-STACK < %t.out // RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -DHEAP=1 -O3 %s -o %t && \ // RUN: not %run %t >%t.out 2>&1 -// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-HEAP < %t.out +// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%short-stack --check-prefix=CHECK-HEAP < %t.out // RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -O3 %s -o %t && \ // RUN: not %run %t >%t.out 2>&1 -// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-STACK < %t.out +// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-%short-stack --check-prefix=CHECK-STACK < %t.out // RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -DHEAP=1 -O3 %s -o %t && \ // RUN: not %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-HEAP < %t.out - #include <stdio.h> volatile int x, y; @@ -48,19 +47,21 @@ int main(int argc, char *argv[]) { } // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value -// CHECK: {{#0 .* in main.*chained_origin.cc:47}} +// CHECK: {{#0 .* in main.*chained_origin.cc:}}[[@LINE-4]] // CHECK: Uninitialized value was stored to memory at -// CHECK: {{#0 .* in fn_h.*chained_origin.cc:35}} -// CHECK: {{#1 .* in main.*chained_origin.cc:46}} +// CHECK-FULL-STACK: {{#0 .* in fn_h.*chained_origin.cc:}}[[@LINE-19]] +// CHECK-FULL-STACK: {{#1 .* in main.*chained_origin.cc:}}[[@LINE-9]] +// CHECK-SHORT-STACK: {{#0 .* in fn_h.*chained_origin.cc:}}[[@LINE-21]] // CHECK: Uninitialized value was stored to memory at -// CHECK: {{#0 .* in fn_g.*chained_origin.cc:25}} -// CHECK: {{#1 .* in fn_f.*chained_origin.cc:30}} -// CHECK: {{#2 .* in main.*chained_origin.cc:45}} +// CHECK-FULL-STACK: {{#0 .* in fn_g.*chained_origin.cc:}}[[@LINE-34]] +// CHECK-FULL-STACK: {{#1 .* in fn_f.*chained_origin.cc:}}[[@LINE-30]] +// CHECK-FULL-STACK: {{#2 .* in main.*chained_origin.cc:}}[[@LINE-16]] +// CHECK-SHORT-STACK: {{#0 .* in fn_g.*chained_origin.cc:}}[[@LINE-37]] // CHECK-STACK: Uninitialized value was created by an allocation of 'z' in the stack frame of function 'main' -// CHECK-STACK: {{#0 .* in main.*chained_origin.cc:38}} +// CHECK-STACK: {{#0 .* in main.*chained_origin.cc:}}[[@LINE-27]] // CHECK-HEAP: Uninitialized value was created by a heap allocation -// CHECK-HEAP: {{#1 .* in main.*chained_origin.cc:40}} +// CHECK-HEAP: {{#1 .* in main.*chained_origin.cc:}}[[@LINE-28]] diff --git a/test/msan/chained_origin_limits.cc b/test/msan/chained_origin_limits.cc index 90fd09a86b292..9585889eb37a9 100644 --- a/test/msan/chained_origin_limits.cc +++ b/test/msan/chained_origin_limits.cc @@ -10,7 +10,7 @@ // RUN: FileCheck %s --check-prefix=CHECK2 < %t.out // RUN: MSAN_OPTIONS=origin_history_per_stack_limit=1 not %run %t >%t.out 2>&1 -// RUN: FileCheck %s --check-prefix=CHECK-PER-STACK < %t.out +// RUN: FileCheck %s --check-prefix=CHECK-PER-STACK --check-prefix=CHECK-%short-stack < %t.out // RUN: MSAN_OPTIONS=origin_history_size=7,origin_history_per_stack_limit=0 not %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK7 < %t.out @@ -25,7 +25,7 @@ // RUN: FileCheck %s --check-prefix=CHECK2 < %t.out // RUN: MSAN_OPTIONS=origin_history_per_stack_limit=1 not %run %t >%t.out 2>&1 -// RUN: FileCheck %s --check-prefix=CHECK-PER-STACK < %t.out +// RUN: FileCheck %s --check-prefix=CHECK-PER-STACK --check-prefix=CHECK-%short-stack < %t.out // RUN: MSAN_OPTIONS=origin_history_size=7,origin_history_per_stack_limit=0 not %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK7 < %t.out @@ -41,7 +41,7 @@ // RUN: FileCheck %s --check-prefix=CHECK2 < %t.out // RUN: MSAN_OPTIONS=origin_history_per_stack_limit=1 not %run %t >%t.out 2>&1 -// RUN: FileCheck %s --check-prefix=CHECK-PER-STACK < %t.out +// RUN: FileCheck %s --check-prefix=CHECK-PER-STACK --check-prefix=CHECK-%short-stack < %t.out // RUN: MSAN_OPTIONS=origin_history_size=7,origin_history_per_stack_limit=0 not %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK7 < %t.out @@ -57,7 +57,7 @@ // RUN: FileCheck %s --check-prefix=CHECK2 < %t.out // RUN: MSAN_OPTIONS=origin_history_per_stack_limit=1 not %run %t >%t.out 2>&1 -// RUN: FileCheck %s --check-prefix=CHECK-PER-STACK < %t.out +// RUN: FileCheck %s --check-prefix=CHECK-PER-STACK --check-prefix=CHECK-%short-stack < %t.out // RUN: MSAN_OPTIONS=origin_history_size=7,origin_history_per_stack_limit=0 not %run %t >%t.out 2>&1 // RUN: FileCheck %s --check-prefix=CHECK7 < %t.out @@ -147,13 +147,21 @@ int main(void) { // CHECK2-NOT: Uninitialized value was stored to memory at // CHECK2: Uninitialized value was created +// For architectures with short stack all the stacks in the chain are same +// because the stack trace does not contain frames upto the functions fn1, fn2, +// fn3 from where the uninitialized stores actually originate. Since we report +// uninitialized value store once for each stack frame +// (origin_history_per_stack_limit = 1) we expect only one instance of +// "Uninitialized value was stored to memory at". + // CHECK-PER-STACK: WARNING: MemorySanitizer: use-of-uninitialized-value // CHECK-PER-STACK: Uninitialized value was stored to memory at -// CHECK-PER-STACK: in fn3 -// CHECK-PER-STACK: Uninitialized value was stored to memory at -// CHECK-PER-STACK: in fn2 -// CHECK-PER-STACK: Uninitialized value was stored to memory at -// CHECK-PER-STACK: in fn1 +// CHECK-SHORT-STACK: in __msan_memmove +// CHECK-FULL-STACK: in fn3 +// CHECK-FULL-STACK: Uninitialized value was stored to memory at +// CHECK-FULL-STACK: in fn2 +// CHECK-FULL-STACK: Uninitialized value was stored to memory at +// CHECK-FULL-STACK: in fn1 // CHECK-PER-STACK: Uninitialized value was created // CHECK-UNLIMITED: WARNING: MemorySanitizer: use-of-uninitialized-value diff --git a/test/msan/chained_origin_memcpy.cc b/test/msan/chained_origin_memcpy.cc index 3fe0b77a06140..bfe50dfec3f51 100644 --- a/test/msan/chained_origin_memcpy.cc +++ b/test/msan/chained_origin_memcpy.cc @@ -1,20 +1,19 @@ // RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -DOFFSET=0 -O3 %s -o %t && \ // RUN: not %run %t >%t.out 2>&1 -// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z1 < %t.out +// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z1 --check-prefix=CHECK-%short-stack < %t.out // RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -DOFFSET=10 -O3 %s -o %t && \ // RUN: not %run %t >%t.out 2>&1 -// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z2 < %t.out +// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z2 --check-prefix=CHECK-%short-stack < %t.out // RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -DOFFSET=0 -O3 %s -o %t && \ // RUN: not %run %t >%t.out 2>&1 -// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z1 < %t.out +// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z1 --check-prefix=CHECK-%short-stack < %t.out // RUN: %clangxx_msan -mllvm -msan-instrumentation-with-call-threshold=0 -fsanitize-memory-track-origins=2 -DOFFSET=10 -O3 %s -o %t && \ // RUN: not %run %t >%t.out 2>&1 -// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z2 < %t.out - +// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-Z2 --check-prefix=CHECK-%short-stack < %t.out #include <stdio.h> #include <string.h> @@ -47,15 +46,17 @@ int main(int argc, char *argv[]) { } // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value -// CHECK: {{#0 .* in main .*chained_origin_memcpy.cc:46}} +// CHECK: {{#0 .* in main .*chained_origin_memcpy.cc:}}[[@LINE-4]] // CHECK: Uninitialized value was stored to memory at -// CHECK: {{#1 .* in fn_h.*chained_origin_memcpy.cc:38}} +// CHECK-FULL-STACK: {{#1 .* in fn_h.*chained_origin_memcpy.cc:}}[[@LINE-15]] +// CHECK-SHORT-STACK: {{#0 .* in __msan_memcpy .*msan_interceptors.cc:}} // CHECK: Uninitialized value was stored to memory at -// CHECK: {{#0 .* in fn_g.*chained_origin_memcpy.cc:28}} -// CHECK: {{#1 .* in fn_f.*chained_origin_memcpy.cc:33}} +// CHECK-FULL-STACK: {{#0 .* in fn_g.*chained_origin_memcpy.cc:}}[[@LINE-29]] +// CHECK-FULL-STACK: {{#1 .* in fn_f.*chained_origin_memcpy.cc:}}[[@LINE-25]] +// CHECK-SHORT-STACK: {{#0 .* in fn_g.*chained_origin_memcpy.cc:}}[[@LINE-31]] // CHECK-Z1: Uninitialized value was created by an allocation of 'z1' in the stack frame of function 'main' // CHECK-Z2: Uninitialized value was created by an allocation of 'z2' in the stack frame of function 'main' -// CHECK: {{#0 .* in main.*chained_origin_memcpy.cc:41}} +// CHECK: {{#0 .* in main.*chained_origin_memcpy.cc:}}[[@LINE-22]] diff --git a/test/msan/coverage-levels.cc b/test/msan/coverage-levels.cc index 710a69aff53a4..b881cecac7e91 100644 --- a/test/msan/coverage-levels.cc +++ b/test/msan/coverage-levels.cc @@ -9,7 +9,7 @@ // RUN: MSAN_OPTIONS=coverage=1:verbosity=1:coverage_dir=%T/coverage-levels not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 --check-prefix=CHECK_WARN // RUN: %clangxx_msan -O1 -fsanitize-coverage=edge %s -o %t // RUN: MSAN_OPTIONS=coverage=1:verbosity=1:coverage_dir=%T/coverage-levels not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3 --check-prefix=CHECK_WARN -// + volatile int sink; int main(int argc, char **argv) { int var; diff --git a/test/msan/fork.cc b/test/msan/fork.cc index 78a62d549ec3c..e4dc5490887c7 100644 --- a/test/msan/fork.cc +++ b/test/msan/fork.cc @@ -3,13 +3,16 @@ // and verify that origin reads do not deadlock in the child process. // RUN: %clangxx_msan -std=c++11 -fsanitize-memory-track-origins=2 -g -O3 %s -o %t -// RUN: MSAN_OPTIONS=store_context_size=1000,origin_history_size=0,origin_history_per_stack_limit=0 %run %t |& FileCheck %s +// RUN: MSAN_OPTIONS=store_context_size=1000,origin_history_size=0,origin_history_per_stack_limit=0 %run %t 2>&1 | FileCheck %s // Fun fact: if test output is redirected to a file (as opposed to // being piped directly to FileCheck), we may lose some "done"s due to // a kernel bug: // https://lkml.org/lkml/2014/2/17/324 +// Flaky on PPC64. +// UNSUPPORTED: powerpc64-target-arch +// UNSUPPORTED: powerpc64le-target-arch #include <pthread.h> #include <unistd.h> @@ -89,7 +92,7 @@ int main() { exit(0); } } - + for (int i = 0; i < kChildren; ++i) { pid_t p; while ((p = wait(NULL)) == -1) { } diff --git a/test/msan/getutent.cc b/test/msan/getutent.cc new file mode 100644 index 0000000000000..36f9e1f1f7e30 --- /dev/null +++ b/test/msan/getutent.cc @@ -0,0 +1,17 @@ +// RUN: %clangxx_msan -O0 -g %s -o %t && %run %t + +#include <utmp.h> +#include <utmpx.h> +#include <sanitizer/msan_interface.h> + +int main(void) { + setutent(); + while (struct utmp *ut = getutent()) + __msan_check_mem_is_initialized(ut, sizeof(*ut)); + endutent(); + + setutxent(); + while (struct utmpx *utx = getutxent()) + __msan_check_mem_is_initialized(utx, sizeof(*utx)); + endutxent(); +} diff --git a/test/msan/iconv.cc b/test/msan/iconv.cc index c2da938169b3a..e5fbbf9241e78 100644 --- a/test/msan/iconv.cc +++ b/test/msan/iconv.cc @@ -1,5 +1,5 @@ // RUN: %clangxx_msan -O0 -g %s -o %t && %run %t -// RUN: %clangxx_msan -O0 -g -DPOSITIVE %s -o %t && not %run %t |& FileCheck %s +// RUN: %clangxx_msan -O0 -g -DPOSITIVE %s -o %t && not %run %t 2>&1 | FileCheck %s #include <assert.h> #include <iconv.h> diff --git a/test/msan/lit.cfg b/test/msan/lit.cfg index d23ff31bc7483..eb0ed43897caf 100644 --- a/test/msan/lit.cfg +++ b/test/msan/lit.cfg @@ -35,3 +35,11 @@ if config.host_os not in ['Linux']: if config.target_arch != 'aarch64': config.available_features.add('stable-runtime') + +# For mips64, mips64el we have forced store_context_size to 1 because these +# archs use slow unwinder which is not async signal safe. Therefore we only +# check the first frame since store_context size is 1. +if config.host_arch in ['mips64', 'mips64el']: + config.substitutions.append( ('CHECK-%short-stack', 'CHECK-SHORT-STACK')) +else: + config.substitutions.append( ('CHECK-%short-stack', 'CHECK-FULL-STACK')) diff --git a/test/msan/mmap.cc b/test/msan/mmap.cc index 27a8bb2d6eb5c..65d8beeefe3a7 100644 --- a/test/msan/mmap.cc +++ b/test/msan/mmap.cc @@ -19,7 +19,9 @@ bool AddrIsApp(void *p) { (addr >= 0x510000000000ULL && addr < 0x600000000000ULL) || (addr >= 0x700000000000ULL && addr < 0x800000000000ULL); #elif defined(__mips64) - return addr >= 0x00e000000000ULL; + return (addr >= 0x0000000000ULL && addr <= 0x0200000000ULL) || + (addr >= 0xa200000000ULL && addr <= 0xc000000000ULL) || + addr >= 0xe200000000ULL; #elif defined(__powerpc64__) return addr < 0x000100000000ULL || addr >= 0x300000000000ULL; #elif defined(__aarch64__) @@ -37,6 +39,12 @@ bool AddrIsApp(void *p) { {0x2E000000000ULL, 0x2F000000000ULL}, {0x3B000000000ULL, 0x3C000000000ULL}, {0x3F000000000ULL, 0x40000000000ULL}, + {0x0041000000000ULL, 0x0042000000000ULL}, + {0x0050000000000ULL, 0x0051000000000ULL}, + {0x0058000000000ULL, 0x0059000000000ULL}, + {0x0061000000000ULL, 0x0062000000000ULL}, + {0x0AAAAA0000000ULL, 0x0AAAB00000000ULL}, + {0x0FFFF00000000ULL, 0x1000000000000ULL}, }; const size_t mappingsSize = sizeof (mappings) / sizeof (mappings[0]); diff --git a/test/msan/msan_check_mem_is_initialized.cc b/test/msan/msan_check_mem_is_initialized.cc index 599cf2d7dd463..2991501921e91 100644 --- a/test/msan/msan_check_mem_is_initialized.cc +++ b/test/msan/msan_check_mem_is_initialized.cc @@ -1,5 +1,5 @@ // RUN: %clangxx_msan -O0 -g -DPOSITIVE %s -o %t -// RUN: not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK +// RUN: not %run %t 2>&1 | FileCheck %s // RUN: MSAN_OPTIONS=verbosity=1 not %run %t 2>&1 | \ // RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-VERBOSE diff --git a/test/msan/msan_copy_shadow.cc b/test/msan/msan_copy_shadow.cc index a1c6347ff4e3c..19da73810509c 100644 --- a/test/msan/msan_copy_shadow.cc +++ b/test/msan/msan_copy_shadow.cc @@ -1,7 +1,7 @@ // Test that __msan_copy_shadow copies shadow, updates origin and does not touch // the application memory. // RUN: %clangxx_msan -fsanitize-memory-track-origins=0 -O0 %s -o %t && not %run %t 2>&1 -// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -O0 %s -o %t && not %run %t 2>&1 | FileCheck --check-prefix=CHECK --check-prefix=CHECK-%short-stack %s #include <assert.h> #include <string.h> @@ -28,7 +28,8 @@ int main() { // CHECK: use-of-uninitialized-value // CHECK: {{in main.*msan_copy_shadow.cc:}}[[@LINE-2]] // CHECK: Uninitialized value was stored to memory at - // CHECK: {{in main.*msan_copy_shadow.cc:}}[[@LINE-8]] + // CHECK-FULL-STACK: {{in main.*msan_copy_shadow.cc:}}[[@LINE-8]] + // CHECK-SHORT-STACK: {{in __msan_copy_shadow .*msan_interceptors.cc:}} // CHECK: Uninitialized value was created by a heap allocation - // CHECK: {{in main.*msan_copy_shadow.cc:}}[[@LINE-22]] + // CHECK: {{in main.*msan_copy_shadow.cc:}}[[@LINE-23]] } diff --git a/test/msan/print_stats.cc b/test/msan/print_stats.cc index 39af504179d60..5b46d4ebbff24 100644 --- a/test/msan/print_stats.cc +++ b/test/msan/print_stats.cc @@ -1,22 +1,22 @@ // RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -g %s -o %t // RUN: %run %t 2>&1 | \ -// RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-NOSTATS %s +// RUN: FileCheck --check-prefixes=CHECK,CHECK-NOSTATS %s // RUN: MSAN_OPTIONS=print_stats=1 %run %t 2>&1 | \ -// RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-NOSTATS %s +// RUN: FileCheck --check-prefixes=CHECK,CHECK-NOSTATS %s // RUN: MSAN_OPTIONS=print_stats=1,atexit=1 %run %t 2>&1 | \ -// RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-STATS %s +// RUN: FileCheck --check-prefixes=CHECK,CHECK-STATS %s // RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -g -DPOSITIVE=1 %s -o %t // RUN: not %run %t 2>&1 | \ -// RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-NOSTATS %s +// RUN: FileCheck --check-prefixes=CHECK,CHECK-NOSTATS %s // RUN: MSAN_OPTIONS=print_stats=1 not %run %t 2>&1 | \ -// RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-STATS %s +// RUN: FileCheck --check-prefixes=CHECK,CHECK-STATS %s -// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -g -DPOSITIVE=1 -mllvm -msan-keep-going=1 %s -o %t +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -fsanitize-recover=memory -g -DPOSITIVE=1 %s -o %t // RUN: not %run %t 2>&1 | \ -// RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-NOSTATS --check-prefix=CHECK-KEEPGOING %s +// RUN: FileCheck --check-prefixes=CHECK,CHECK-NOSTATS,CHECK-RECOVER %s // RUN: MSAN_OPTIONS=print_stats=1 not %run %t 2>&1 | \ -// RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-STATS --check-prefix=CHECK-KEEPGOING %s +// RUN: FileCheck --check-prefixes=CHECK,CHECK-STATS,CHECK-RECOVER %s #include <stdio.h> int main(int argc, char **argv) { @@ -42,4 +42,4 @@ int main(int argc, char **argv) { // CHECK-NOSTATS-NOT: Unique origin histories: // CHECK-NOSTATS-NOT: History depot allocated bytes: -// CHECK-KEEPGOING: MemorySanitizer: 1 warnings reported. +// CHECK-RECOVER: MemorySanitizer: 1 warnings reported. diff --git a/test/msan/realloc-large-origin.cc b/test/msan/realloc-large-origin.cc index ce25ad8c47fdf..6893c1d17c48e 100644 --- a/test/msan/realloc-large-origin.cc +++ b/test/msan/realloc-large-origin.cc @@ -1,7 +1,7 @@ // RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -O0 %s -o %t && not %run %t >%t.out 2>&1 -// RUN: FileCheck %s < %t.out +// RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-%short-stack %s < %t.out // RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -O2 %s -o %t && not %run %t >%t.out 2>&1 -// RUN: FileCheck %s < %t.out +// RUN: FileCheck --check-prefix=CHECK --check-prefix=CHECK-%short-stack %s < %t.out // This is a regression test: there used to be broken "stored to memory at" // stacks with @@ -21,10 +21,11 @@ int main(int argc, char **argv) { // CHECK: {{#0 0x.* in main .*realloc-large-origin.cc:}}[[@LINE-3]] // CHECK: Uninitialized value was stored to memory at -// CHECK: {{#0 0x.* in .*realloc}} -// CHECK: {{#1 0x.* in main .*realloc-large-origin.cc:}}[[@LINE-10]] +// CHECK-FULL-STACK: {{#0 0x.* in .*realloc}} +// CHECK-FULL-STACK: {{#1 0x.* in main .*realloc-large-origin.cc:}}[[@LINE-10]] +// CHECK-SHORT-STACK: {{#0 0x.* in .*realloc}} // CHECK: Uninitialized value was created by a heap allocation // CHECK: {{#0 0x.* in .*malloc}} -// CHECK: {{#1 0x.* in main .*realloc-large-origin.cc:}}[[@LINE-15]] +// CHECK: {{#1 0x.* in main .*realloc-large-origin.cc:}}[[@LINE-16]] } diff --git a/test/msan/keep-going-dso.cc b/test/msan/recover-dso.cc index f32a513ea9e7a..2f4225659dd43 100644 --- a/test/msan/keep-going-dso.cc +++ b/test/msan/recover-dso.cc @@ -1,22 +1,28 @@ // RUN: %clangxx_msan -O0 %s -o %t && not %run %t >%t.out 2>&1 -// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out +// FileCheck --check-prefix=CHECK-RECOVER %s <%t.out // RUN: %clangxx_msan -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %run %t >%t.out 2>&1 // FileCheck %s <%t.out // RUN: %clangxx_msan -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %run %t >%t.out 2>&1 -// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out +// FileCheck --check-prefix=CHECK-RECOVER %s <%t.out -// RUN: %clangxx_msan -mllvm -msan-keep-going=1 -O0 %s -o %t && not %run %t >%t.out 2>&1 -// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out -// RUN: %clangxx_msan -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %run %t >%t.out 2>&1 -// FileCheck %s <%t.out -// RUN: %clangxx_msan -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %run %t >%t.out 2>&1 -// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out - -// Test how -mllvm -msan-keep-going and MSAN_OPTIONS=keep_going affect reports +// Test how -fsanitize-recover=memory and MSAN_OPTIONS=keep_going affect reports // from interceptors. -// -mllvm -msan-keep-going provides the default value of keep_going flag, but is +// -fsanitize-recover=memory provides the default value of keep_going flag, but is // always overwritten by MSAN_OPTIONS +// RUN: %clangxx_msan -fsanitize-recover=memory -O0 %s -o %t && not %run %t >%t.out 2>&1 +// FileCheck --check-prefix=CHECK-RECOVER %s <%t.out +// RUN: %clangxx_msan -fsanitize-recover=memory -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %run %t >%t.out 2>&1 +// FileCheck %s <%t.out +// RUN: %clangxx_msan -fsanitize-recover=memory -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %run %t >%t.out 2>&1 +// FileCheck --check-prefix=CHECK-RECOVER %s <%t.out + +// Test how legacy -mllvm -msan-keep-going and MSAN_OPTIONS=keep_going affect +// reports from interceptors. + +// RUN: %clangxx_msan -mllvm -msan-keep-going=1 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// FileCheck --check-prefix=CHECK-RECOVER %s <%t.out + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -28,6 +34,6 @@ int main(int argc, char **argv) { exit(0); fprintf(stderr, "Done\n"); // CHECK-NOT: Done - // CHECK-KEEP-GOING: Done + // CHECK-RECOVER: Done return 0; } diff --git a/test/msan/keep-going.cc b/test/msan/recover.cc index 57729756357d6..cb9916ef4755b 100644 --- a/test/msan/keep-going.cc +++ b/test/msan/recover.cc @@ -5,20 +5,27 @@ // RUN: %clangxx_msan -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %run %t >%t.out 2>&1 // FileCheck %s <%t.out -// RUN: %clangxx_msan -mllvm -msan-keep-going=1 -O0 %s -o %t && not %run %t >%t.out 2>&1 -// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out -// RUN: %clangxx_msan -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %run %t >%t.out 2>&1 +// Test behavior of -fsanitize-recover=memory and MSAN_OPTIONS=keep_going. +// -fsanitize-recover=memory provides the default value of keep_going flag; value +// of 1 can be overwritten by MSAN_OPTIONS, value of 0 can not. + +// RUN: %clangxx_msan -fsanitize-recover=memory -O0 %s -o %t && not %run %t >%t.out 2>&1 +// FileCheck --check-prefix=CHECK-RECOVER %s <%t.out +// RUN: %clangxx_msan -fsanitize-recover=memory -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %run %t >%t.out 2>&1 // FileCheck %s <%t.out -// RUN: %clangxx_msan -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %run %t >%t.out 2>&1 -// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out -// RUN: %clangxx_msan -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=halt_on_error=1 not %run %t >%t.out 2>&1 +// RUN: %clangxx_msan -fsanitize-recover=memory -O0 %s -o %t && MSAN_OPTIONS=keep_going=1 not %run %t >%t.out 2>&1 +// FileCheck --check-prefix=CHECK-RECOVER %s <%t.out +// RUN: %clangxx_msan -fsanitize-recover=memory -O0 %s -o %t && MSAN_OPTIONS=halt_on_error=1 not %run %t >%t.out 2>&1 // FileCheck %s <%t.out -// RUN: %clangxx_msan -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=halt_on_error=0 not %run %t >%t.out 2>&1 -// FileCheck --check-prefix=CHECK-KEEP-GOING %s <%t.out +// RUN: %clangxx_msan -fsanitize-recover=memory -O0 %s -o %t && MSAN_OPTIONS=halt_on_error=0 not %run %t >%t.out 2>&1 +// FileCheck --check-prefix=CHECK-RECOVER %s <%t.out -// Test behaviour of -mllvm -msan-keep-going and MSAN_OPTIONS=keep_going. -// -mllvm -msan-keep-going provides the default value of keep_going flag; value -// of 1 can be overwritten by MSAN_OPTIONS, value of 0 can not. +// Basic test of legacy -mllvm -msan-keep-going and MSAN_OPTIONS=keep_going. + +// RUN: %clangxx_msan -mllvm -msan-keep-going=1 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// FileCheck --check-prefix=CHECK-RECOVER %s <%t.out +// RUN: %clangxx_msan -mllvm -msan-keep-going=1 -O0 %s -o %t && MSAN_OPTIONS=keep_going=0 not %run %t >%t.out 2>&1 +// FileCheck %s <%t.out #include <stdio.h> #include <stdlib.h> @@ -29,6 +36,6 @@ int main(int argc, char **argv) { exit(0); fprintf(stderr, "Done\n"); // CHECK-NOT: Done - // CHECK-KEEP-GOING: Done + // CHECK-RECOVER: Done return 0; } diff --git a/test/msan/strlen_of_shadow.cc b/test/msan/strlen_of_shadow.cc index 3066dd5b61ae9..b9cf5f065d2da 100644 --- a/test/msan/strlen_of_shadow.cc +++ b/test/msan/strlen_of_shadow.cc @@ -14,7 +14,7 @@ const char *mem_to_shadow(const char *p) { #if defined(__x86_64__) return (char *)((uintptr_t)p ^ 0x500000000000ULL); #elif defined (__mips64) - return (char *)((uintptr_t)p & ~0x4000000000ULL); + return (char *)((uintptr_t)p ^ 0x8000000000ULL); #elif defined(__powerpc64__) #define LINEARIZE_MEM(mem) \ (((uintptr_t)(mem) & ~0x200000000000ULL) ^ 0x100000000000ULL) diff --git a/test/profile/CMakeLists.txt b/test/profile/CMakeLists.txt index 0eb2b894748c9..5a4cfa1012b08 100644 --- a/test/profile/CMakeLists.txt +++ b/test/profile/CMakeLists.txt @@ -14,13 +14,7 @@ endif() foreach(arch ${PROFILE_TEST_ARCH}) set(PROFILE_TEST_TARGET_ARCH ${arch}) - if(${arch} MATCHES "arm|aarch64") - # This is only true if we're cross-compiling. - set(PROFILE_TEST_TARGET_CFLAGS ${COMPILER_RT_TEST_COMPILER_CFLAGS}) - else() - get_target_flags_for_arch(${arch} PROFILE_TEST_TARGET_CFLAGS) - string(REPLACE ";" " " PROFILE_TEST_TARGET_CFLAGS "${PROFILE_TEST_TARGET_CFLAGS}") - endif() + get_test_cc_for_arch(${arch} PROFILE_TEST_TARGET_CC PROFILE_TEST_TARGET_CFLAGS) set(CONFIG_NAME Profile-${arch}) configure_lit_site_cfg( ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in diff --git a/test/profile/Inputs/comdat_rename.h b/test/profile/Inputs/comdat_rename.h new file mode 100644 index 0000000000000..d30628f13b63c --- /dev/null +++ b/test/profile/Inputs/comdat_rename.h @@ -0,0 +1,13 @@ +struct FOO { + FOO() : a(0), b(0) {} + int callee(); + __attribute__((noinline)) void caller(int n) { + int r = callee(); + if (r == 0) { + a += n; + b += 1; + } + } + int a; + int volatile b; +}; diff --git a/test/profile/Inputs/comdat_rename_1.cc b/test/profile/Inputs/comdat_rename_1.cc new file mode 100644 index 0000000000000..688e305310c52 --- /dev/null +++ b/test/profile/Inputs/comdat_rename_1.cc @@ -0,0 +1,33 @@ +#include "comdat_rename.h" +// callee's out-of-line instance profile data -- it comes +// from external calls to it from comdat_rename_2.cc. +// Its inline instance copy's profile data is different and +// is collected in 'caller''s context. +int FOO::callee() { + // CHECK-LABEL: define {{.*}}callee{{.*}} + // CHECK-NOT: br i1 {{.*}} + // CHECK: br {{.*}}label{{.*}}, label %[[BB1:.*]], !prof ![[PD1:[0-9]+]] + // CHECK: {{.*}}[[BB1]]: + if (b != 0) + return a / b; + if (a != 0) + return 10 / a; + return 0; +} + +// This is the 'caller''s comdat copy (after renaming) in this module. +// The profile counters include a copy of counters from 'callee': +// +// CHECK-LABEL: define {{.*}}caller{{.*}} +// CHECK-NOT: br i1 {{.*}} +// CHECK: br {{.*}}label{{.*}}, label %[[BB2:.*]], !prof ![[PD2:[0-9]+]] +// CHECK: {{.*}}[[BB2]]: +// CHECK: br {{.*}}label{{.*}}, label %{{.*}}, !prof !{{.*}} +// CHECK: br {{.*}}label %[[BB3:.*]], label %{{.*}} !prof ![[PD3:[0-9]+]] +// CHECK: {{.*}}[[BB3]]: +// +// CHECK:![[PD1]] = !{!"branch_weights", i32 0, i32 1} +// CHECK:![[PD2]] = !{!"branch_weights", i32 1, i32 0} +// CHECK:![[PD3]] = !{!"branch_weights", i32 {{.*}}, i32 0} + +void test(FOO *foo) { foo->caller(10); } diff --git a/test/profile/Inputs/comdat_rename_2.cc b/test/profile/Inputs/comdat_rename_2.cc new file mode 100644 index 0000000000000..5cad79c9f9d8b --- /dev/null +++ b/test/profile/Inputs/comdat_rename_2.cc @@ -0,0 +1,18 @@ +#include "comdat_rename.h" +extern void test(FOO *); +FOO foo; +int main() { + test(&foo); + foo.caller(20); + return 0; +} + +// The copy of 'caller' defined in this module -- it has +// 'callee' call remaining. +// +// CHECK-LABEL: define {{.*}}caller{{.*}} +// CHECK: {{.*}} call {{.*}} +// CHECK-NOT: br i1 {{.*}} +// CHECK: br {{.*}}label %[[BB1:.*]], label{{.*}}!prof ![[PD1:[0-9]+]] +// CHECK: {{.*}}[[BB1]]: +// CHECK:![[PD1]] = !{!"branch_weights", i32 0, i32 1} diff --git a/test/profile/Inputs/extern_template.h b/test/profile/Inputs/extern_template.h index 01c1d1abfff54..aa59f6c1e6006 100644 --- a/test/profile/Inputs/extern_template.h +++ b/test/profile/Inputs/extern_template.h @@ -1,10 +1,10 @@ template <typename T> struct Test { Test() : M(10) {} - void doIt(int N) { // CHECK: 2| [[@LINE]]| void doIt - if (N > 10) { // CHECK: 2| [[@LINE]]| if (N > 10) { - M += 2; // CHECK: 1| [[@LINE]]| M += 2; - } else // CHECK: 1| [[@LINE]]| } else - M -= 2; // CHECK: 1| [[@LINE]]| M -= 2; + void doIt(int N) { // CHECK: [[@LINE]]| 2| void doIt + if (N > 10) { // CHECK: [[@LINE]]| 2| if (N > 10) { + M += 2; // CHECK: [[@LINE]]| 1| M += 2; + } else // CHECK: [[@LINE]]| 1| } else + M -= 2; // CHECK: [[@LINE]]| 1| M -= 2; } T M; }; diff --git a/test/profile/Inputs/instrprof-comdat.h b/test/profile/Inputs/instrprof-comdat.h index db1a5ba63e589..61e283cc878ed 100644 --- a/test/profile/Inputs/instrprof-comdat.h +++ b/test/profile/Inputs/instrprof-comdat.h @@ -12,12 +12,12 @@ private: T t; }; -template <class T> T FOO<T>::DoIt(T ti) { // HEADER: 2| [[@LINE]]|template - for (T I = 0; I < ti; I++) { // HEADER: 22| [[@LINE]]| for (T - t += I; // HEADER: 20| [[@LINE]]| t += I; - if (I > ti / 2) // HEADER: 20| [[@LINE]]| if (I > ti - t -= 1; // HEADER: 8| [[@LINE]]| t -= 1; - } // HEADER: 10| [[@LINE]]| } - // HEADER: 1| [[@LINE]]| - return t; // HEADER: 1| [[@LINE]]| return t; +template <class T> T FOO<T>::DoIt(T ti) { // HEADER: [[@LINE]]| 2|template + for (T I = 0; I < ti; I++) { // HEADER: [[@LINE]]| 22| for (T + t += I; // HEADER: [[@LINE]]| 20| t += I; + if (I > ti / 2) // HEADER: [[@LINE]]| 20| if (I > ti + t -= 1; // HEADER: [[@LINE]]| 8| t -= 1; + } // HEADER: [[@LINE]]| 10| } + // HEADER: [[@LINE]]| 1| + return t; // HEADER: [[@LINE]]| 1| return t; } diff --git a/test/profile/Inputs/instrprof-dynamic-a.cpp b/test/profile/Inputs/instrprof-dynamic-a.cpp index 5faa9c2b2a80f..7468cd4eb04ef 100644 --- a/test/profile/Inputs/instrprof-dynamic-a.cpp +++ b/test/profile/Inputs/instrprof-dynamic-a.cpp @@ -1,7 +1,7 @@ #include "instrprof-dynamic-header.h" -void a() { // COV: 1| [[@LINE]]|void a - if (true) { // COV: 1| [[@LINE]]| if - bar<void>(1); // COV: 1| [[@LINE]]| bar - bar<char>(1); // COV: 1| [[@LINE]]| bar - } // COV: 1| [[@LINE]]| } +void a() { // COV: [[@LINE]]| 1|void a + if (true) { // COV: [[@LINE]]| 1| if + bar<void>(1); // COV: [[@LINE]]| 1| bar + bar<char>(1); // COV: [[@LINE]]| 1| bar + } // COV: [[@LINE]]| 1| } } diff --git a/test/profile/Linux/comdat_rename.test b/test/profile/Linux/comdat_rename.test new file mode 100644 index 0000000000000..cd5c672de4f25 --- /dev/null +++ b/test/profile/Linux/comdat_rename.test @@ -0,0 +1,6 @@ +// RUN: rm -fr %t.prof +// RUN: %clangxx_pgogen=%t.prof/ -o %t.gen -O2 %S/../Inputs/comdat_rename_1.cc %S/../Inputs/comdat_rename_2.cc +// RUN: %run %t.gen +// RUN: llvm-profdata merge -o %t.profdata %t.prof/ +// RUN: %clangxx_profuse=%t.profdata -O2 -emit-llvm -S %S/../Inputs/comdat_rename_1.cc -o - | FileCheck %S/../Inputs/comdat_rename_1.cc +// RUN: %clangxx_profuse=%t.profdata -O2 -emit-llvm -S %S/../Inputs/comdat_rename_2.cc -o - | FileCheck %S/../Inputs/comdat_rename_2.cc diff --git a/test/profile/Linux/coverage_ctors.cpp b/test/profile/Linux/coverage_ctors.cpp index 317dcfe18b501..021d9df5e7347 100644 --- a/test/profile/Linux/coverage_ctors.cpp +++ b/test/profile/Linux/coverage_ctors.cpp @@ -15,9 +15,9 @@ struct Base { }; struct Derived : public Base { - Derived(const Derived &) = default; // CHECK: 2| [[@LINE]]| Derived(const Derived &) = default; - Derived(Derived &&) = default; // CHECK: 1| [[@LINE]]| Derived(Derived &&) = default; - Derived() = default; // CHECK: 1| [[@LINE]]| Derived() = default + Derived(const Derived &) = default; // CHECK: [[@LINE]]| 2| Derived(const Derived &) = default; + Derived(Derived &&) = default; // CHECK: [[@LINE]]| 1| Derived(Derived &&) = default; + Derived() = default; // CHECK: [[@LINE]]| 1| Derived() = default }; Derived dd; @@ -27,6 +27,6 @@ int main() { Derived dd4(static_cast<Derived &&>(dd3)); if (dd.B != 0 || dd2.B != 5 || dd3.B != 10 || dd4.B != 20) - return 1; // CHECK: 0| [[@LINE]]| return 1; + return 1; // CHECK: [[@LINE]]| 0| return 1; return 0; } diff --git a/test/profile/Linux/coverage_dtor.cpp b/test/profile/Linux/coverage_dtor.cpp index f35eb100fa12c..16415122040c9 100644 --- a/test/profile/Linux/coverage_dtor.cpp +++ b/test/profile/Linux/coverage_dtor.cpp @@ -12,7 +12,7 @@ struct Base { struct Derived : public Base { Derived(int K) : Base(K) {} - ~Derived() = default; // CHECK: 2| [[@LINE]]| ~Derived() = default; + ~Derived() = default; // CHECK: [[@LINE]]| 2| ~Derived() = default; }; int main() { @@ -21,6 +21,6 @@ int main() { Derived dd2(90); } if (g != 0) - return 1; // CHECK: 0| [[@LINE]]| return 1; + return 1; // CHECK: [[@LINE]]| 0| return 1; return 0; } diff --git a/test/profile/Linux/coverage_test.cpp b/test/profile/Linux/coverage_test.cpp index 9b4ba073cf0a6..db9a14e26e3c8 100644 --- a/test/profile/Linux/coverage_test.cpp +++ b/test/profile/Linux/coverage_test.cpp @@ -17,19 +17,19 @@ // RUN: llvm-profdata merge -o %t.pie.profdata %t.pie.profraw // RUN: llvm-cov show %t.pie -instr-profile %t.pie.profdata -filename-equivalence 2>&1 | FileCheck %s -void foo(bool cond) { // CHECK: 1| [[@LINE]]|void foo( - if (cond) { // CHECK: 1| [[@LINE]]| if (cond) { - } // CHECK: 0| [[@LINE]]| } -} // CHECK: 1| [[@LINE]]|} -void bar() { // CHECK: 1| [[@LINE]]|void bar() { -} // CHECK: 1| [[@LINE]]|} -void func() { // CHECK: 0| [[@LINE]]|void func( -} // CHECK: 0| [[@LINE]]|} -int main() { // CHECK: 1| [[@LINE]]|int main( - foo(false); // CHECK: 1| [[@LINE]]| foo( - bar(); // CHECK: 1| [[@LINE]]| bar( - return 0; // CHECK: 1| [[@LINE]]| return -} // CHECK: 1| [[@LINE]]|} +void foo(bool cond) { // CHECK: [[@LINE]]| 1|void foo( + if (cond) { // CHECK: [[@LINE]]| 1| if (cond) { + } // CHECK: [[@LINE]]| 0| } +} // CHECK: [[@LINE]]| 1|} +void bar() { // CHECK: [[@LINE]]| 1|void bar() { +} // CHECK: [[@LINE]]| 1|} +void func() { // CHECK: [[@LINE]]| 0|void func( +} // CHECK: [[@LINE]]| 0|} +int main() { // CHECK: [[@LINE]]| 1|int main( + foo(false); // CHECK: [[@LINE]]| 1| foo( + bar(); // CHECK: [[@LINE]]| 1| bar( + return 0; // CHECK: [[@LINE]]| 1| return +} // CHECK: [[@LINE]]| 1|} // COVMAP: __llvm_covmap {{.*}} diff --git a/test/profile/Linux/extern_template.test b/test/profile/Linux/extern_template.test index ada4d230e9bc4..3ce362783199b 100644 --- a/test/profile/Linux/extern_template.test +++ b/test/profile/Linux/extern_template.test @@ -1,12 +1,12 @@ // RUN: %clang -O2 -c -o %t.0.o %S/../Inputs/extern_template.cpp // RUN: %clang_profgen -O2 -c -o %t.o %S/../Inputs/extern_template.cpp // RUN: %clang_profgen -O2 -fcoverage-mapping %S/../Inputs/extern_template1.cpp %S/../Inputs/extern_template2.cpp %t.o -o %t -// RUN: env LLVM_PROFILE_FILE=%t.profraw %t +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t // RUN: llvm-profdata show --all-functions %t.profraw | FileCheck %s // RUN: llvm-profdata merge -o %t.profdata %t.profraw // RUN: llvm-cov show -instr-profile=%t.profdata %t | FileCheck %S/../Inputs/extern_template.h // RUN: %clang_profgen -O2 -fcoverage-mapping %S/../Inputs/extern_template1.cpp %S/../Inputs/extern_template2.cpp %t.0.o -o %t.0 -// RUN: env LLVM_PROFILE_FILE=%t.0.profraw %t.0 +// RUN: env LLVM_PROFILE_FILE=%t.0.profraw %run %t.0 // RUN: llvm-profdata show --all-functions %t.0.profraw | FileCheck %s // RUN: llvm-profdata merge -o %t.0.profdata %t.0.profraw // RUN: llvm-cov show -instr-profile=%t.0.profdata %t.0 | FileCheck %S/../Inputs/extern_template.h diff --git a/test/profile/Linux/instrprof-comdat.test b/test/profile/Linux/instrprof-comdat.test index b933e96b45042..5a11a241ae6f8 100644 --- a/test/profile/Linux/instrprof-comdat.test +++ b/test/profile/Linux/instrprof-comdat.test @@ -1,6 +1,6 @@ RUN: mkdir -p %t.d RUN: %clangxx_profgen -o %t.d/comdat -fcoverage-mapping -fuse-ld=gold %S/../Inputs/instrprof-comdat-1.cpp %S/../Inputs/instrprof-comdat-2.cpp -RUN: LLVM_PROFILE_FILE=%t-comdat.profraw %t.d/comdat +RUN: LLVM_PROFILE_FILE=%t-comdat.profraw %run %t.d/comdat RUN: llvm-profdata merge -o %t.d/comdat.prof %t-comdat.profraw RUN: llvm-cov show --filename-equivalence --instr-profile=%t.d/comdat.prof %t.d/comdat | FileCheck --check-prefix=HEADER %S/../Inputs/instrprof-comdat.h diff --git a/test/profile/Linux/instrprof-cs.c b/test/profile/Linux/instrprof-cs.c new file mode 100644 index 0000000000000..d825525a532db --- /dev/null +++ b/test/profile/Linux/instrprof-cs.c @@ -0,0 +1,35 @@ +// RUN: rm -fr %t.prof +// RUN: %clang_pgogen=%t.prof/ -o %t.gen.cs -O2 %s +// RUN: %run %t.gen.cs +// RUN: llvm-profdata merge -o %t.cs.profdata %t.prof/ +// Check context sensitive profile +// RUN: %clang_profuse=%t.cs.profdata -O2 -emit-llvm -S %s -o - | FileCheck %s --check-prefix=CS +// +// RUN: %clang_profgen=%t.profraw -o %t.gen.cis -O2 %s +// RUN: %run %t.gen.cis +// RUN: llvm-profdata merge -o %t.cis.profdata %t.profraw +// Check context insenstive profile +// RUN: %clang_profuse=%t.cis.profdata -O2 -emit-llvm -S %s -o - | FileCheck %s --check-prefix=CIS +int g1 = 1; +int volatile g2 = 2; +static void toggle(int t) { + if (t & 1) + g1 *= t; + else + g2 *= t; +} + +int main() { + int i; + // CS: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]] + // CIS: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD:[0-9]+]] + toggle(g1); + // CS: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD2:[0-9]+]] + // CIS: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD:[0-9]+]] + toggle(g2); + return 0; +} + +// CS: ![[PD1]] = !{!"branch_weights", i32 0, i32 1} +// CS: ![[PD2]] = !{!"branch_weights", i32 1, i32 0} +// CIS: ![[PD]] = !{!"branch_weights", i32 2, i32 2} diff --git a/test/profile/Linux/lit.local.cfg b/test/profile/Linux/lit.local.cfg index c8c79fc7d8a77..410ffd8c5b056 100644 --- a/test/profile/Linux/lit.local.cfg +++ b/test/profile/Linux/lit.local.cfg @@ -21,6 +21,7 @@ def is_gold_linker_available(): return False clang_cmd = subprocess.Popen([config.clang, '-fuse-ld=gold', '-xc', '-'], + universal_newlines = True, stdin = subprocess.PIPE, stdout = subprocess.PIPE, stderr = subprocess.PIPE) diff --git a/test/profile/gcc-flag-compatibility.test b/test/profile/gcc-flag-compatibility.test index b1087615ec514..5b05e769cb145 100644 --- a/test/profile/gcc-flag-compatibility.test +++ b/test/profile/gcc-flag-compatibility.test @@ -2,16 +2,16 @@ RUN: rm -rf %t.d RUN: mkdir -p %t.d RUN: %clang_profgen_gcc=%t.d/d1/d2 -o %t.d/code %S/Inputs/gcc-flag-compatibility.c -# Test that the instrumented code writes to %t.d/d1/d2/default.profraw +# Test that the instrumented code writes to %t.d/d1/d2/ RUN: %run %t.d/code -RUN: llvm-profdata merge -o %t.profdata %t.d/d1/d2/default.profraw +RUN: llvm-profdata merge -o %t.profdata %t.d/d1/d2/ # Test that we can override the directory and file name with LLVM_PROFILE_FILE. RUN: env LLVM_PROFILE_FILE=%t.d/x1/prof.raw %run %t.d/code -RUN: llvm-profdata merge -o %t.profdata %t.d/x1/prof.raw +RUN: llvm-profdata merge -o %t.profdata %t.d/x1/ # Test that we can specify a directory with -fprofile-use. -RUN: llvm-profdata merge -o %t.d/default.profdata %t.d/x1/prof.raw +RUN: llvm-profdata merge -o %t.d/default.profdata %t.d/x1/ RUN: %clang_profuse_gcc=%t.d -o %t.d/code %S/Inputs/gcc-flag-compatibility.c # Test that we can specify a file with -fprofile-use. diff --git a/test/profile/instrprof-basic.c b/test/profile/instrprof-basic.c index 02549e1506ba1..dd8f3fca3f9c9 100644 --- a/test/profile/instrprof-basic.c +++ b/test/profile/instrprof-basic.c @@ -1,21 +1,46 @@ -// REQUIRES: shell // RUN: %clang_profgen -o %t -O3 %s // RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t // RUN: llvm-profdata merge -o %t.profdata %t.profraw // RUN: %clang_profuse=%t.profdata -o - -S -emit-llvm %s | FileCheck %s --check-prefix=COMMON --check-prefix=ORIG // -// RUN: rm -f %t.profraw_e_* -// RUN: env LLVM_PROFILE_FILE=%t.profraw_e_%1m %run %t -// RUN: env LLVM_PROFILE_FILE=%t.profraw_e_%1m %run %t -// RUN: llvm-profdata merge -o %t.em.profdata %t.profraw_e_* +// RUN: rm -fr %t.dir1 +// RUN: mkdir -p %t.dir1 +// RUN: env LLVM_PROFILE_FILE=%t.dir1/profraw_e_%1m %run %t +// RUN: env LLVM_PROFILE_FILE=%t.dir1/profraw_e_%1m %run %t +// RUN: llvm-profdata merge -o %t.em.profdata %t.dir1 // RUN: %clang_profuse=%t.em.profdata -o - -S -emit-llvm %s | FileCheck %s --check-prefix=COMMON --check-prefix=MERGE // -// RUN: %clang_profgen=%t.%m.profraw -o %t.merge -O3 %s -// RUN: rm -f %t.*.profraw* +// RUN: rm -fr %t.dir2 +// RUN: mkdir -p %t.dir2 +// RUN: %clang_profgen=%t.dir2/%m.profraw -o %t.merge -O3 %s // RUN: %run %t.merge // RUN: %run %t.merge -// RUN: llvm-profdata merge -o %t.m.profdata %t.*.profraw +// RUN: llvm-profdata merge -o %t.m.profdata %t.dir2/ // RUN: %clang_profuse=%t.m.profdata -o - -S -emit-llvm %s | FileCheck %s --check-prefix=COMMON --check-prefix=MERGE +// +// Test that merging is enabled by default with -fprofile-generate= +// RUN: rm -fr %t.dir3 +// RUN: mkdir -p %t.dir3 +// RUN: %clang_pgogen=%t.dir3/ -o %t.merge3 -O0 %s +// RUN: %run %t.merge3 +// RUN: %run %t.merge3 +// RUN: %run %t.merge3 +// RUN: %run %t.merge3 +// RUN: llvm-profdata merge -o %t.m3.profdata %t.dir3/ +// RUN: %clang_profuse=%t.m3.profdata -O0 -o - -S -emit-llvm %s | FileCheck %s --check-prefix=COMMON --check-prefix=PGOMERGE +// +// Test that merging is enabled by default with -fprofile-generate +// RUN: rm -fr %t.dir4 +// RUN: mkdir -p %t.dir4 +// RUN: %clang_pgogen -o %t.dir4/merge4 -O0 %s +// RUN: cd %t.dir4 +// RUN: %run %t.dir4/merge4 +// RUN: %run %t.dir4/merge4 +// RUN: %run %t.dir4/merge4 +// RUN: %run %t.dir4/merge4 +// RUN: rm -f %t.dir4/merge4 +// RUN: llvm-profdata merge -o %t.m4.profdata ./ +// RUN: %clang_profuse=%t.m4.profdata -O0 -o - -S -emit-llvm %s | FileCheck %s --check-prefix=COMMON --check-prefix=PGOMERGE int begin(int i) { // COMMON: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]] @@ -45,3 +70,5 @@ int main(int argc, const char *argv[]) { // ORIG: ![[PD2]] = !{!"branch_weights", i32 2, i32 1} // MERGE: ![[PD1]] = !{!"branch_weights", i32 1, i32 3} // MERGE: ![[PD2]] = !{!"branch_weights", i32 3, i32 1} +// PGOMERGE: ![[PD1]] = !{!"branch_weights", i32 0, i32 4} +// PGOMERGE: ![[PD2]] = !{!"branch_weights", i32 4, i32 0} diff --git a/test/profile/instrprof-darwin-dead-strip.c b/test/profile/instrprof-darwin-dead-strip.c new file mode 100644 index 0000000000000..64a4895a9ef92 --- /dev/null +++ b/test/profile/instrprof-darwin-dead-strip.c @@ -0,0 +1,60 @@ +// REQUIRES: osx-ld64-live_support +// REQUIRES: lto + +// RUN: %clang_profgen=%t.profraw -fcoverage-mapping -mllvm -enable-name-compression=false -Wl,-dead_strip -o %t %s +// RUN: %run %t +// RUN: llvm-profdata merge -o %t.profdata %t.profraw +// RUN: llvm-profdata show --all-functions %t.profdata | FileCheck %s -check-prefix=PROF +// RUN: llvm-cov show %t -instr-profile %t.profdata | FileCheck %s -check-prefix=COV +// RUN: nm %t | FileCheck %s -check-prefix=NM +// RUN: otool -s __DATA __llvm_prf_names %t | FileCheck %s -check-prefix=PRF_NAMES +// RUN: otool -s __DATA __llvm_prf_cnts %t | FileCheck %s -check-prefix=PRF_CNTS + +// RUN: %clang_lto_profgen=%t.lto.profraw -fcoverage-mapping -mllvm -enable-name-compression=false -Wl,-dead_strip -flto -o %t.lto %s +// RUN: %run %t.lto +// RUN: llvm-profdata merge -o %t.lto.profdata %t.lto.profraw +// RUN: llvm-profdata show --all-functions %t.lto.profdata | FileCheck %s -check-prefix=PROF +// RUN: llvm-cov show %t.lto -instr-profile %t.lto.profdata | FileCheck %s -check-prefix=COV +// RUN: nm %t.lto | FileCheck %s -check-prefix=NM +// RUN: otool -s __DATA __llvm_prf_names %t.lto | FileCheck %s -check-prefix=PRF_NAMES +// RUN: otool -s __DATA __llvm_prf_cnts %t.lto | FileCheck %s -check-prefix=PRF_CNTS + +// Note: We expect foo() and some of the profiling data associated with it to +// be dead-stripped. + +// COV: [[@LINE+1]]{{ *}}|{{ *}}0|void foo() +void foo() {} + +// COV: [[@LINE+1]]{{ *}}|{{ *}}1|int main +int main() { return 0; } + +// NM-NOT: foo + +// PROF: Counters: +// PROF-NEXT: main: +// PROF-NEXT: Hash: +// PROF-NEXT: Counters: 1 +// PROF-NEXT: Function count: 1 +// PROF-NEXT: Functions shown: 1 +// PROF-NEXT: Total functions: 1 +// PROF-NEXT: Maximum function count: 1 +// PROF-NEXT: Maximum internal block count: 0 + +// Note: We don't expect the names of dead-stripped functions to disappear from +// __llvm_prf_names, because collectPGOFuncNameStrings() glues the names +// together. + +// PRF_NAMES: Contents of (__DATA,__llvm_prf_names) section +// PRF_NAMES-NEXT: {{.*}} 08 00 66 6f 6f 01 6d 61 69 6e{{ +$}} +// | | f o o # m a i n +// | |___________| +// | | +// UncompressedLen = 8 | +// | +// CompressedLen = 0 + +// Note: We expect the profile counters for dead-stripped functions to also be +// dead-stripped. + +// PRF_CNTS: Contents of (__DATA,__llvm_prf_cnts) section +// PRF_CNTS-NEXT: {{.*}} 00 00 00 00 00 00 00 00{{ +$}} diff --git a/test/profile/instrprof-dump.c b/test/profile/instrprof-dump.c new file mode 100644 index 0000000000000..93c3c46f69160 --- /dev/null +++ b/test/profile/instrprof-dump.c @@ -0,0 +1,62 @@ +/* +RUN: rm -fr %t.profdir +RUN: %clang_profgen=%t.profdir/default_%m.profraw -o %t -O2 %s +RUN: %run %t 2>&1 | FileCheck %s --check-prefix=NO_EXIT_WRITE +RUN: llvm-profdata merge -o %t.profdata %t.profdir +RUN: %clang_profuse=%t.profdata -o - -S -emit-llvm %s | FileCheck %s --check-prefix=PROF + +NO_EXIT_WRITE: Profile data not written to file: already written +*/ + +int __llvm_profile_dump(void); +void __llvm_profile_reset_counters(void); +int foo(int); +int bar(int); +int skip(int); + +int main(int argc, const char *argv[]) { + int Ret = foo(0); /* region 1 */ + __llvm_profile_dump(); + + /* not profiled -- cleared later. */ + skip(0); /* skipped region */ + + __llvm_profile_reset_counters(); + Ret += bar(0); /* region 2 */ + __llvm_profile_dump(); + + skip(1); + + __llvm_profile_reset_counters(); + /* foo's profile will be merged. */ + foo(1); /* region 3 */ + __llvm_profile_dump(); + + return Ret; +} + +__attribute__((noinline)) int foo(int X) { + /* PROF: define {{.*}} @foo({{.*}}!prof ![[ENT:[0-9]+]] + PROF: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]] + */ + return X <= 0 ? -X : X; +} + +__attribute__((noinline)) int skip(int X) { + /* PROF: define {{.*}} @skip( + PROF: br i1 %{{.*}}, label %{{.*}}, label %{{[^,]+$}} + */ + return X <= 0 ? -X : X; +} + +__attribute__((noinline)) int bar(int X) { + /* PROF-LABEL: define {{.*}} @bar( + PROF: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD2:[0-9]+]] + */ + return X <= 0 ? -X : X; +} + +/* +PROF: ![[ENT]] = !{!"function_entry_count", i64 2} +PROF: ![[PD1]] = !{!"branch_weights", i32 2, i32 2} +*/ diff --git a/test/profile/instrprof-icall-promo.test b/test/profile/instrprof-icall-promo.test index 5332ef0e17c9e..d9b16f67782ec 100644 --- a/test/profile/instrprof-icall-promo.test +++ b/test/profile/instrprof-icall-promo.test @@ -1,16 +1,16 @@ -RUN: %clangxx_profgen -O2 -Xclang -fprofile-instrument=llvm -c -o %t.1.o %S/Inputs/instrprof-icall-promo_1.cc -RUN: %clangxx_profgen -O2 -Xclang -fprofile-instrument=llvm -c -o %t.2.o %S/Inputs/instrprof-icall-promo_2.cc +# IR based instrumentation +RUN: %clangxx_pgogen -O2 -c -o %t.1.o %S/Inputs/instrprof-icall-promo_1.cc +RUN: %clangxx_pgogen -O2 -c -o %t.2.o %S/Inputs/instrprof-icall-promo_2.cc -RUN: %clangxx_profgen -O2 -Xclang -fprofile-instrument=llvm %t.2.o %t.1.o -o %t.gen.1 +RUN: %clangxx_pgogen -O2 %t.2.o %t.1.o -o %t.gen.1 RUN: env LLVM_PROFILE_FILE=%t-icall.profraw %run %t.gen.1 RUN: llvm-profdata merge -o %t-icall.profdata %t-icall.profraw -RUN: %clangxx -O2 -Rpass=pgo-icall-prom -fprofile-instr-use=%t-icall.profdata -c -o %t.2.use.o %S/Inputs/instrprof-icall-promo_2.cc 2>&1 | FileCheck %s +RUN: %clangxx_profuse=%t-icall.profdata -O2 -Rpass=pgo-icall-prom -c -o %t.2.use.o %S/Inputs/instrprof-icall-promo_2.cc 2>&1 | FileCheck %s -RUN: %clangxx_profgen -O2 -Xclang -fprofile-instrument=llvm %t.1.o %t.2.o -o %t.gen.2 +RUN: %clangxx_pgogen -O2 %t.1.o %t.2.o -o %t.gen.2 RUN: env LLVM_PROFILE_FILE=%t-icall2.profraw %run %t.gen.2 RUN: llvm-profdata merge -o %t-icall2.profdata %t-icall2.profraw -# The following test will be re-enabled once a compiler bug is fixed. -RUN: %clangxx -O2 -Rpass=pgo-icall-prom -fprofile-instr-use=%t-icall2.profdata -c -o %t.2.use.o %S/Inputs/instrprof-icall-promo_2.cc 2>&1 | FileCheck %s +RUN: %clangxx_profuse=%t-icall2.profdata -O2 -Rpass=pgo-icall-prom -c -o %t.2.use.o %S/Inputs/instrprof-icall-promo_2.cc 2>&1 | FileCheck %s # CHECK: Promote indirect call to diff --git a/test/profile/instrprof-override-filename-then-reset-default.c b/test/profile/instrprof-override-filename-then-reset-default.c index 137a3b2f22915..3438227213ecd 100644 --- a/test/profile/instrprof-override-filename-then-reset-default.c +++ b/test/profile/instrprof-override-filename-then-reset-default.c @@ -7,13 +7,13 @@ // RUN: %clang_profuse=%t.d/default.profdata -o - -S -emit-llvm %s | FileCheck %s -void __llvm_profile_override_default_filename(const char *); +void __llvm_profile_set_filename(const char *); int main(int argc, const char *argv[]) { // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]] if (argc < 2) return 1; - __llvm_profile_override_default_filename(argv[1]); - __llvm_profile_override_default_filename(0); + __llvm_profile_set_filename(argv[1]); + __llvm_profile_set_filename(0); return 0; } // CHECK: ![[PD1]] = !{!"branch_weights", i32 1, i32 2} diff --git a/test/profile/instrprof-override-filename-with-env.c b/test/profile/instrprof-override-filename-with-env.c index cce83891663a6..3f4e5c8d251c4 100644 --- a/test/profile/instrprof-override-filename-with-env.c +++ b/test/profile/instrprof-override-filename-with-env.c @@ -1,14 +1,14 @@ -// RUN: %clang_profgen -o %t -O3 %s +// RUN: %clang_profgen=%t.bad.profraw -o %t -O3 %s // RUN: env LLVM_PROFILE_FILE=%t.good.profraw %run %t %t.bad.profraw // RUN: llvm-profdata merge -o %t.profdata %t.good.profraw // RUN: %clang_profuse=%t.profdata -o - -S -emit-llvm %s | FileCheck %s -void __llvm_profile_override_default_filename(const char *); +void bar () {} int main(int argc, const char *argv[]) { // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]] if (argc < 2) return 1; - __llvm_profile_override_default_filename(argv[1]); + bar(); return 0; } // CHECK: ![[PD1]] = !{!"branch_weights", i32 1, i32 2} diff --git a/test/profile/instrprof-override-filename.c b/test/profile/instrprof-override-filename.c index 59dea29e3b884..a67c7076afb5c 100644 --- a/test/profile/instrprof-override-filename.c +++ b/test/profile/instrprof-override-filename.c @@ -1,14 +1,14 @@ -// RUN: %clang_profgen -o %t -O3 %s +// RUN: %clang_profgen=%t.profraw -o %t -O3 %s // RUN: %run %t %t.profraw // RUN: llvm-profdata merge -o %t.profdata %t.profraw // RUN: %clang_profuse=%t.profdata -o - -S -emit-llvm %s | FileCheck %s -void __llvm_profile_override_default_filename(const char *); +void bar() {} int main(int argc, const char *argv[]) { // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD1:[0-9]+]] if (argc < 2) return 1; - __llvm_profile_override_default_filename(argv[1]); + bar(); return 0; } // CHECK: ![[PD1]] = !{!"branch_weights", i32 1, i32 2} diff --git a/test/profile/instrprof-path.c b/test/profile/instrprof-path.c new file mode 100644 index 0000000000000..28ee8ad0a4843 --- /dev/null +++ b/test/profile/instrprof-path.c @@ -0,0 +1,39 @@ +// RUN: %clang_pgogen -O2 -o %t.0 %s +// RUN: %clang_pgogen=%t.d1 -O2 -o %t.1 %s +// RUN: %clang_pgogen=%t.d1/%t.d2 -O2 -o %t.2 %s +// +// RUN: %run %t.0 "" +// RUN: env LLVM_PROFILE_FILE=%t.d1/default.profraw %run %t.0 %t.d1/ +// RUN: env LLVM_PROFILE_FILE=%t.d1/%t.d2/default.profraw %run %t.0 %t.d1/%t.d2/ +// RUN: %run %t.1 %t.d1/ +// RUN: %run %t.2 %t.d1/%t.d2/ +// RUN: %run %t.2 %t.d1/%t.d2/ %t.d1/%t.d2/%t.d3/blah.profraw %t.d1/%t.d2/%t.d3/ + +#include <string.h> + +const char *__llvm_profile_get_path_prefix(); +void __llvm_profile_set_filanem(const char*); + +int main(int argc, const char *argv[]) { + int i; + const char *expected; + const char *prefix; + if (argc < 2) + return 1; + + expected = argv[1]; + prefix = __llvm_profile_get_path_prefix(); + + if (strcmp(prefix, expected)) + return 1; + + if (argc == 4) { + __llvm_profile_set_filename(argv[2]); + prefix = __llvm_profile_get_path_prefix(); + expected = argv[3]; + if (strcmp(prefix, expected)) + return 1; + } + + return 0; +} diff --git a/test/profile/Linux/instrprof-set-filename-shared.test b/test/profile/instrprof-set-filename-shared.test index 29e6713289d96..afcb4b4fd2d62 100644 --- a/test/profile/Linux/instrprof-set-filename-shared.test +++ b/test/profile/instrprof-set-filename-shared.test @@ -1,7 +1,7 @@ # Test that __llvm_profile_set_filename is honored by shared libary too. RUN: mkdir -p %t.d -RUN: %clang_profgen=%t.shared.profraw -fPIC -shared -o %t.d/t.shared %S/../Inputs/instrprof-dlopen-func.c -RUN: %clang_profgen -DCALL_SHARED -o %t.m -O3 -rpath %t.d %t.d/t.shared %S/../instrprof-set-filename.c +RUN: %clang_profgen=%t.shared.profraw -fPIC -shared -o %t.d/t.shared %S/Inputs/instrprof-dlopen-func.c +RUN: %clang_profgen -DCALL_SHARED -o %t.m -O3 -rpath %t.d %t.d/t.shared %S/instrprof-set-filename.c RUN: %run %t.m %t.main.profraw RUN: llvm-profdata show %t.main.profraw | FileCheck --check-prefix=SHARED %s diff --git a/test/profile/instrprof-value-prof-evict.test b/test/profile/instrprof-value-prof-evict.test index de82581e451af..8b054fb24371e 100644 --- a/test/profile/instrprof-value-prof-evict.test +++ b/test/profile/instrprof-value-prof-evict.test @@ -4,13 +4,13 @@ // RUN: llvm-profdata show --all-functions -ic-targets %t.profdata | FileCheck %S/Inputs/instrprof-value-prof-evict.c // IR level instrumentation -// RUN: %clang_profgen -O2 -mllvm -disable-vp=false -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=10 -Xclang -fprofile-instrument=llvm -o %t.ir %S/Inputs/instrprof-value-prof-evict.c +// RUN: %clang_pgogen -O2 -mllvm -disable-vp=false -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=10 -o %t.ir %S/Inputs/instrprof-value-prof-evict.c // RUN: env LLVM_PROFILE_FILE=%t.ir.profraw %run %t.ir // RUN: llvm-profdata merge -o %t.ir.profdata %t.ir.profraw // RUN: llvm-profdata show --all-functions -ic-targets %t.ir.profdata | FileCheck %S/Inputs/instrprof-value-prof-evict.c // IR level instrumentation, dynamic allocation -// RUN: %clang_profgen -O2 -mllvm -disable-vp=false -mllvm -vp-static-alloc=false -Xclang -fprofile-instrument=llvm -o %t.ir.dyn %S/Inputs/instrprof-value-prof-evict.c +// RUN: %clang_pgogen -O2 -mllvm -disable-vp=false -mllvm -vp-static-alloc=false -o %t.ir.dyn %S/Inputs/instrprof-value-prof-evict.c // RUN: env LLVM_PROFILE_FILE=%t.ir.dyn.profraw %run %t.ir.dyn // RUN: llvm-profdata merge -o %t.ir.dyn.profdata %t.ir.dyn.profraw // RUN: llvm-profdata show --all-functions -ic-targets %t.ir.dyn.profdata | FileCheck %S/Inputs/instrprof-value-prof-evict.c diff --git a/test/profile/instrprof-value-prof-reset.c b/test/profile/instrprof-value-prof-reset.c new file mode 100644 index 0000000000000..b3744f5735066 --- /dev/null +++ b/test/profile/instrprof-value-prof-reset.c @@ -0,0 +1,47 @@ +// RUN: %clang_profgen -O2 -mllvm -enable-value-profiling=true -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=3 -o %t %s +// RUN: env LLVM_PROFILE_FILE=%t.profraw %run %t +// RUN: llvm-profdata merge -o %t.profdata %t.profraw +// RUN: llvm-profdata show --all-functions -ic-targets %t.profdata | FileCheck %s + +// IR level instrumentation +// RUN: %clang_pgogen -O2 -mllvm -disable-vp=false -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=3 -o %t.ir %s +// RUN: env LLVM_PROFILE_FILE=%t.ir.profraw %run %t.ir +// RUN: llvm-profdata merge -o %t.ir.profdata %t.ir.profraw +// RUN: llvm-profdata show --all-functions -ic-targets %t.ir.profdata | FileCheck %s + +// IR level instrumentation, dynamic allocation +// RUN: %clang_pgogen -O2 -mllvm -disable-vp=false -mllvm -vp-static-alloc=false -o %t.ir.dyn %s +// RUN: env LLVM_PROFILE_FILE=%t.ir.dyn.profraw %run %t.ir.dyn +// RUN: llvm-profdata merge -o %t.ir.dyn.profdata %t.ir.dyn.profraw +// RUN: llvm-profdata show --all-functions -ic-targets %t.ir.dyn.profdata | FileCheck %s +void callee_0() {} +void callee_1() {} +void callee_2() {} + +void *CalleeAddrs[] = {callee_0, callee_1, callee_2, callee_2, callee_2}; +extern void lprofSetMaxValsPerSite(unsigned); +extern void __llvm_profile_reset_counters(); + +typedef void (*FPT)(void); + + +// Testing value profiling eviction algorithm. +FPT getCalleeFunc(int I) { return CalleeAddrs[I]; } + +int main() { + int I; + + // First fill up two value profile entries with two targets + lprofSetMaxValsPerSite(2); + + for (I = 0; I < 5; I++) { + if (I == 2) { + __llvm_profile_reset_counters(); + } + // CHECK: callee_2, 3 + // CHECK-NEXT: callee_1, 0 + // CHECK-NOT: callee_0, + FPT FP = getCalleeFunc(I); + FP(); + } +} diff --git a/test/profile/instrprof-value-prof-shared.test b/test/profile/instrprof-value-prof-shared.test index 5b6d627dbaf93..a45b0d55b2363 100644 --- a/test/profile/instrprof-value-prof-shared.test +++ b/test/profile/instrprof-value-prof-shared.test @@ -7,8 +7,9 @@ // RUN: llvm-profdata show --all-functions -ic-targets %t.profdata | FileCheck %S/Inputs/instrprof-value-prof-real.c --check-prefix=SHARED // IR level instrumentation -// RUN: %clang_profgen -O2 -mllvm -disable-vp=false -Xclang -fprofile-instrument=llvm -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=256 -fPIC -shared -o %t.d/t.ir.shared -DSHARED_LIB %S/Inputs/instrprof-value-prof-real.c -// RUN: %clang_profgen -O2 -mllvm -disable-vp=false -Xclang -fprofile-instrument=llvm -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=256 -rpath %t.d -o %t.ir %t.d/t.ir.shared -DCALL_SHARED %S/Inputs/instrprof-value-prof-real.c +// RUN: %clang_pgogen -O2 -mllvm -disable-vp=false -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=256 -fPIC -shared -o %t.d/t.ir.shared -DSHARED_LIB %S/Inputs/instrprof-value-prof-real.c +// RUN: %clang_pgogen -O2 -mllvm -disable-vp=false -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=256 -rpath %t.d -o %t.ir %t.d/t.ir.shared -DCALL_SHARED %S/Inputs/instrprof-value-prof-real.c +// Profile data from shared library will be concatenated to the same raw file. // RUN: env LLVM_PROFILE_FILE=%t.ir.profraw LLVM_VP_MAX_NUM_VALS_PER_SITE=255 %run %t.ir // RUN: llvm-profdata merge -o %t.ir.profdata %t.ir.profraw // RUN: llvm-profdata show --all-functions -ic-targets %t.ir.profdata | FileCheck %S/Inputs/instrprof-value-prof-real.c @@ -16,9 +17,23 @@ // RUN: llvm-profdata show --all-functions -ic-targets %t.ir.profdata | FileCheck %S/Inputs/instrprof-value-prof-real.c --check-prefix=SHARED // RUN: FileCheck %S/Inputs/instrprof-value-prof-real.c --check-prefix=IR < %t.ir.proftxt +// Same as above but with profile online merging enabled. +// RUN: rm -fr %t.prof/ +// RUN: mkdir -p %t.prof/ +// RUN: %clang_pgogen=%t.prof -O2 -mllvm -disable-vp=false -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=256 -fPIC -shared -o %t.d/t.ir.m.shared -DSHARED_LIB %S/Inputs/instrprof-value-prof-real.c +// RUN: %clang_pgogen=%t.prof -O2 -mllvm -disable-vp=false -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=256 -rpath %t.d -o %t.ir.m %t.d/t.ir.m.shared -DCALL_SHARED %S/Inputs/instrprof-value-prof-real.c +// RUN: env LLVM_VP_MAX_NUM_VALS_PER_SITE=255 %run %t.ir.m +// RUN: llvm-profdata merge -o %t.ir.m.profdata -dump-input-file-list %t.prof/ | count 2 +// RUN: llvm-profdata merge -o %t.ir.m.profdata %t.prof/ +// RUN: llvm-profdata show --all-functions -ic-targets %t.ir.m.profdata | FileCheck %S/Inputs/instrprof-value-prof-real.c +// RUN: llvm-profdata merge -text %t.ir.m.profdata -o %t.ir.m.proftxt +// RUN: llvm-profdata show --all-functions -ic-targets %t.ir.m.profdata | FileCheck %S/Inputs/instrprof-value-prof-real.c --check-prefix=SHARED +// RUN: FileCheck %S/Inputs/instrprof-value-prof-real.c --check-prefix=IR < %t.ir.m.proftxt + + // IR level instrumentation: dynamic memory allocation -// RUN: %clang_profgen -O2 -mllvm -disable-vp=false -Xclang -fprofile-instrument=llvm -mllvm -vp-static-alloc=false -mllvm -vp-counters-per-site=256 -fPIC -shared -o %t.d/t.ir.dyn.shared -DSHARED_LIB %S/Inputs/instrprof-value-prof-real.c -// RUN: %clang_profgen -O2 -mllvm -disable-vp=false -Xclang -fprofile-instrument=llvm -mllvm -vp-static-alloc=false -mllvm -vp-counters-per-site=256 -rpath %t.d -o %t.ir.dyn %t.d/t.ir.dyn.shared -DCALL_SHARED %S/Inputs/instrprof-value-prof-real.c +// RUN: %clang_pgogen -O2 -mllvm -disable-vp=false -mllvm -vp-static-alloc=false -mllvm -vp-counters-per-site=256 -fPIC -shared -o %t.d/t.ir.dyn.shared -DSHARED_LIB %S/Inputs/instrprof-value-prof-real.c +// RUN: %clang_pgogen -O2 -mllvm -disable-vp=false -mllvm -vp-static-alloc=false -mllvm -vp-counters-per-site=256 -rpath %t.d -o %t.ir.dyn %t.d/t.ir.dyn.shared -DCALL_SHARED %S/Inputs/instrprof-value-prof-real.c // RUN: env LLVM_PROFILE_FILE=%t.ir.dyn.profraw %run %t.ir.dyn // RUN: llvm-profdata merge -o %t.ir.dyn.profdata %t.ir.dyn.profraw // RUN: llvm-profdata show --all-functions -ic-targets %t.ir.dyn.profdata | FileCheck %S/Inputs/instrprof-value-prof-real.c @@ -27,8 +42,8 @@ // RUN: FileCheck %S/Inputs/instrprof-value-prof-real.c --check-prefix=IR < %t.ir.dyn.proftxt // IR level instrumentation: main program uses static counter, shared library uses dynamic memory alloc. -// RUN: %clang_profgen -O2 -mllvm -disable-vp=false -Xclang -fprofile-instrument=llvm -mllvm -vp-static-alloc=false -mllvm -vp-counters-per-site=256 -fPIC -shared -o %t.d/t.ir.dyn.shared -DSHARED_LIB %S/Inputs/instrprof-value-prof-real.c -// RUN: %clang_profgen -O2 -mllvm -disable-vp=false -Xclang -fprofile-instrument=llvm -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=256 -rpath %t.d -o %t.ir.mixed %t.d/t.ir.dyn.shared -DCALL_SHARED %S/Inputs/instrprof-value-prof-real.c +// RUN: %clang_pgogen -O2 -mllvm -disable-vp=false -mllvm -vp-static-alloc=false -mllvm -vp-counters-per-site=256 -fPIC -shared -o %t.d/t.ir.dyn.shared -DSHARED_LIB %S/Inputs/instrprof-value-prof-real.c +// RUN: %clang_pgogen -O2 -mllvm -disable-vp=false -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=256 -rpath %t.d -o %t.ir.mixed %t.d/t.ir.dyn.shared -DCALL_SHARED %S/Inputs/instrprof-value-prof-real.c // RUN: env LLVM_PROFILE_FILE=%t.ir.mixed.profraw LLVM_VP_MAX_NUM_VALS_PER_SITE=255 %run %t.ir.mixed // RUN: llvm-profdata merge -o %t.ir.mixed.profdata %t.ir.mixed.profraw // RUN: llvm-profdata show --all-functions -ic-targets %t.ir.mixed.profdata | FileCheck %S/Inputs/instrprof-value-prof-real.c diff --git a/test/profile/instrprof-value-prof.test b/test/profile/instrprof-value-prof.test index 8e7f513d20cbf..02038990bfd91 100644 --- a/test/profile/instrprof-value-prof.test +++ b/test/profile/instrprof-value-prof.test @@ -4,7 +4,7 @@ // RUN: llvm-profdata show --all-functions -ic-targets %t.profdata | FileCheck %S/Inputs/instrprof-value-prof-real.c // IR level instrumentation -// RUN: %clang_profgen -O2 -mllvm -disable-vp=false -Xclang -fprofile-instrument=llvm -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=256 -o %t.ir %S/Inputs/instrprof-value-prof-real.c +// RUN: %clang_pgogen -O2 -mllvm -disable-vp=false -mllvm -vp-static-alloc=true -mllvm -vp-counters-per-site=256 -o %t.ir %S/Inputs/instrprof-value-prof-real.c // RUN: env LLVM_PROFILE_FILE=%t.ir.profraw LLVM_VP_MAX_NUM_VALS_PER_SITE=255 %run %t.ir // RUN: llvm-profdata merge -o %t.ir.profdata %t.ir.profraw // RUN: llvm-profdata show --all-functions -ic-targets %t.ir.profdata | FileCheck %S/Inputs/instrprof-value-prof-real.c @@ -12,7 +12,7 @@ // RUN: FileCheck %S/Inputs/instrprof-value-prof-real.c --check-prefix=IR < %t.ir.proftxt // IR level instrumentation with dynamic memory allocation -// RUN: %clang_profgen -O2 -mllvm -disable-vp=false -Xclang -fprofile-instrument=llvm -mllvm -vp-static-alloc=false -mllvm -vp-counters-per-site=256 -o %t.ir.dyn %S/Inputs/instrprof-value-prof-real.c +// RUN: %clang_pgogen -O2 -mllvm -disable-vp=false -mllvm -vp-static-alloc=false -mllvm -vp-counters-per-site=256 -o %t.ir.dyn %S/Inputs/instrprof-value-prof-real.c // RUN: env LLVM_PROFILE_FILE=%t.ir.dyn.profraw %run %t.ir.dyn // RUN: llvm-profdata merge -o %t.ir.dyn.profdata %t.ir.dyn.profraw // RUN: llvm-profdata show --all-functions -ic-targets %t.ir.dyn.profdata | FileCheck %S/Inputs/instrprof-value-prof-real.c diff --git a/test/profile/instrprof-visibility.cpp b/test/profile/instrprof-visibility.cpp index 08b886536fb47..6fbba9defc565 100644 --- a/test/profile/instrprof-visibility.cpp +++ b/test/profile/instrprof-visibility.cpp @@ -56,34 +56,34 @@ int main() { // --- Check coverage for functions in the anonymous namespace. // COV-DAG: instrprof-visibility.cpp:_ZN12_GLOBAL__N_14callEv -// COV-DAG: 1|{{.*}}|void call() { -// COV-DAG: 1|{{.*}}| f1(); -// COV-DAG: 1|{{.*}}|#ifndef NO_WEAK -// COV-DAG: |{{.*}}| f2(); -// COV-DAG: |{{.*}}|#endif -// COV-DAG: 1|{{.*}}| f3(); -// COV-DAG: 1|{{.*}}|#ifndef NO_EXTERN -// COV-DAG: |{{.*}}| f4(); -// COV-DAG: |{{.*}}|#endif -// COV-DAG: 1|{{.*}}| f5(); -// COV-DAG: 1|{{.*}}| f6(); -// COV-DAG: 1|{{.*}}| f7(); -// COV-DAG: 1|{{.*}}|} +// COV-DAG: [[CALL:[0-9]+]]|{{ *}}1|void call() { +// COV-DAG: {{.*}}|{{ *}}1| f1(); +// COV-DAG: {{.*}}|{{ *}}1|#ifndef NO_WEAK +// COV-DAG: {{.*}}|{{ *}} | f2(); +// COV-DAG: {{.*}}|{{ *}} |#endif +// COV-DAG: {{.*}}|{{ *}}1| f3(); +// COV-DAG: {{.*}}|{{ *}}1|#ifndef NO_EXTERN +// COV-DAG: {{.*}}|{{ *}} | f4(); +// COV-DAG: {{.*}}|{{ *}} |#endif +// COV-DAG: {{.*}}|{{ *}}1| f5(); +// COV-DAG: {{.*}}|{{ *}}1| f6(); +// COV-DAG: {{.*}}|{{ *}}1| f7(); +// COV-DAG: {{.*}}|{{ *}}1|} // --- Check coverage for functions in namespace N1. // COV-DAG: _ZN2N14callEv -// COV-DAG: 1|{{.*}}|void call() { -// COV-DAG: 1|{{.*}}| f1(); -// COV-DAG: 1|{{.*}}|#ifndef NO_WEAK -// COV-DAG: 1|{{.*}}| f2(); -// COV-DAG: 1|{{.*}}|#endif -// COV-DAG: 1|{{.*}}| f3(); -// COV-DAG: 1|{{.*}}|#ifndef NO_EXTERN -// COV-DAG: 1|{{.*}}| f4(); -// COV-DAG: 1|{{.*}}|#endif -// COV-DAG: 1|{{.*}}| f5(); -// COV-DAG: 1|{{.*}}| f6(); -// COV-DAG: 1|{{.*}}| f7(); -// COV-DAG: 1|{{.*}}|} +// COV-DAG: {{ *}}[[CALL]]|{{ *}}1|void call() { +// COV-DAG: {{.*}}|{{ *}}1| f1(); +// COV-DAG: {{.*}}|{{ *}}1|#ifndef NO_WEAK +// COV-DAG: {{.*}}|{{ *}}1| f2(); +// COV-DAG: {{.*}}|{{ *}}1|#endif +// COV-DAG: {{.*}}|{{ *}}1| f3(); +// COV-DAG: {{.*}}|{{ *}}1|#ifndef NO_EXTERN +// COV-DAG: {{.*}}|{{ *}}1| f4(); +// COV-DAG: {{.*}}|{{ *}}1|#endif +// COV-DAG: {{.*}}|{{ *}}1| f5(); +// COV-DAG: {{.*}}|{{ *}}1| f6(); +// COV-DAG: {{.*}}|{{ *}}1| f7(); +// COV-DAG: {{.*}}|{{ *}}1|} // COV-DAG: instrprof-visibility.cpp diff --git a/test/profile/lit.cfg b/test/profile/lit.cfg index 3512e0abcf1a6..a6e6ef81c6228 100644 --- a/test/profile/lit.cfg +++ b/test/profile/lit.cfg @@ -49,20 +49,35 @@ target_cflags=[get_required_attr(config, "target_cflags")] clang_cflags = target_cflags + extra_linkflags clang_cxxflags = config.cxx_mode_flags + clang_cflags -def build_invocation(compile_flags): - return " " + " ".join([config.clang] + compile_flags) + " " +def build_invocation(compile_flags, with_lto = False): + lto_flags = [] + lto_prefix = [] + if with_lto and config.lto_supported: + lto_flags += config.lto_flags + lto_prefix += config.lto_launch + return " " + " ".join(lto_prefix + [config.clang] + lto_flags + compile_flags) + " " # Add clang substitutions. config.substitutions.append( ("%clang ", build_invocation(clang_cflags)) ) config.substitutions.append( ("%clangxx ", build_invocation(clang_cxxflags)) ) config.substitutions.append( ("%clang_profgen ", build_invocation(clang_cflags) + " -fprofile-instr-generate ") ) config.substitutions.append( ("%clang_profgen=", build_invocation(clang_cflags) + " -fprofile-instr-generate=") ) -config.substitutions.append( ("%clang_profuse=", build_invocation(clang_cflags) + " -fprofile-instr-use=") ) +config.substitutions.append( ("%clang_pgogen ", build_invocation(clang_cflags) + " -fprofile-generate ") ) +config.substitutions.append( ("%clang_pgogen=", build_invocation(clang_cflags) + " -fprofile-generate=") ) + config.substitutions.append( ("%clangxx_profgen ", build_invocation(clang_cxxflags) + " -fprofile-instr-generate ") ) -config.substitutions.append( ("%clangxx_profuse=", build_invocation(clang_cxxflags) + " -fprofile-instr-use=") ) +config.substitutions.append( ("%clangxx_profgen=", build_invocation(clang_cxxflags) + " -fprofile-instr-generate=") ) +config.substitutions.append( ("%clangxx_pgogen ", build_invocation(clang_cxxflags) + " -fprofile-generate ") ) +config.substitutions.append( ("%clangxx_pgogen=", build_invocation(clang_cxxflags) + " -fprofile-generate=") ) + config.substitutions.append( ("%clang_profgen_gcc=", build_invocation(clang_cflags) + " -fprofile-generate=") ) config.substitutions.append( ("%clang_profuse_gcc=", build_invocation(clang_cflags) + " -fprofile-use=") ) +config.substitutions.append( ("%clang_profuse=", build_invocation(clang_cflags) + " -fprofile-instr-use=") ) +config.substitutions.append( ("%clangxx_profuse=", build_invocation(clang_cxxflags) + " -fprofile-instr-use=") ) + +config.substitutions.append( ("%clang_lto_profgen=", build_invocation(clang_cflags, True) + " -fprofile-instr-generate=") ) + if config.host_os not in ['Darwin', 'FreeBSD', 'Linux']: config.unsupported = True diff --git a/test/safestack/lit.cfg b/test/safestack/lit.cfg index 535c09742ca93..d4ec73ce703b0 100644 --- a/test/safestack/lit.cfg +++ b/test/safestack/lit.cfg @@ -16,7 +16,6 @@ config.substitutions.append( ("%clang_nosafestack ", config.clang + " -O0 -fno-s config.substitutions.append( ("%clang_safestack ", config.clang + " -O0 -fsanitize=safe-stack ") ) if config.lto_supported: - config.available_features.add('lto') config.substitutions.append((r"%clang_lto_safestack ", ' '.join(config.lto_launch + [config.clang] + config.lto_flags + ['-flto -fsanitize=safe-stack ']))) # SafeStack tests are currently supported on Linux, FreeBSD and Darwin only. diff --git a/test/sanitizer_common/CMakeLists.txt b/test/sanitizer_common/CMakeLists.txt index 9f121654318f9..9b4070b0f6eb5 100644 --- a/test/sanitizer_common/CMakeLists.txt +++ b/test/sanitizer_common/CMakeLists.txt @@ -27,14 +27,7 @@ foreach(tool ${SUPPORTED_TOOLS}) foreach(arch ${TEST_ARCH}) set(SANITIZER_COMMON_LIT_TEST_MODE ${tool}) set(SANITIZER_COMMON_TEST_TARGET_ARCH ${arch}) - if(${arch} MATCHES "arm|aarch64") - # This is only true if we're cross-compiling. - set(SANITIZER_COMMON_TEST_TARGET_CFLAGS - ${COMPILER_RT_TEST_COMPILER_CFLAGS}) - else() - get_target_flags_for_arch(${arch} SANITIZER_COMMON_TEST_TARGET_CFLAGS) - string(REPLACE ";" " " SANITIZER_COMMON_TEST_TARGET_CFLAGS "${SANITIZER_COMMON_TEST_TARGET_CFLAGS}") - endif() + get_test_cc_for_arch(${arch} SANITIZER_COMMON_TEST_TARGET_CC SANITIZER_COMMON_TEST_TARGET_CFLAGS) set(CONFIG_NAME ${tool}-${arch}-${OS_NAME}) configure_lit_site_cfg( ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in @@ -53,9 +46,7 @@ if(COMPILER_RT_INCLUDE_TESTS) list(APPEND SANITIZER_COMMON_TEST_DEPS SanitizerUnitTests) endif() -# FIXME: Re-enable on 64-bit Windows. -if(SANITIZER_COMMON_TESTSUITES AND - (NOT OS_NAME MATCHES "Windows" OR CMAKE_SIZEOF_VOID_P EQUAL 4)) +if(SANITIZER_COMMON_TESTSUITES) add_lit_testsuite(check-sanitizer "Running sanitizer_common tests" ${SANITIZER_COMMON_TESTSUITES} DEPENDS ${SANITIZER_COMMON_TEST_DEPS}) diff --git a/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cc b/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cc index d329122ae7f88..83570a9f13a44 100644 --- a/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cc +++ b/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cc @@ -8,6 +8,7 @@ // This run uses getrusage. We can only test getrusage when allocator_may_return_null=0 // because getrusage gives us max-rss, not current-rss. // RUN: %env_tool_opts=soft_rss_limit_mb=220:quarantine_size=1:allocator_may_return_null=0:can_use_proc_maps_statm=0 not %run %t 2>&1 | FileCheck %s -check-prefix=CHECK_MAY_RETURN_0 +// REQUIRES: stable-runtime // FIXME: make it work for other sanitizers. // XFAIL: lsan diff --git a/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc b/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc index 88d41b6d5fea6..261295790836f 100644 --- a/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc +++ b/test/sanitizer_common/TestCases/Posix/dedup_token_length_test.cc @@ -1,10 +1,10 @@ // Test dedup_token_length // RUN: %clangxx -O0 %s -o %t -// RUN: env %tool_options='abort_on_error=0' not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 -// RUN: env %tool_options='abort_on_error=0, dedup_token_length=0' not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 -// RUN: env %tool_options='abort_on_error=0, dedup_token_length=1' not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 -// RUN: env %tool_options='abort_on_error=0, dedup_token_length=2' not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 -// RUN: env %tool_options='abort_on_error=0, dedup_token_length=3' not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3 +// RUN: env %tool_options='abort_on_error=0' not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 --match-full-lines +// RUN: env %tool_options='abort_on_error=0, dedup_token_length=0' not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK0 --match-full-lines +// RUN: env %tool_options='abort_on_error=0, dedup_token_length=1' not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --match-full-lines +// RUN: env %tool_options='abort_on_error=0, dedup_token_length=2' not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 --match-full-lines +// RUN: env %tool_options='abort_on_error=0, dedup_token_length=3' not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3 --match-full-lines // REQUIRES: stable-runtime // FIXME: implement SEGV handler in other sanitizers, not just asan. @@ -34,7 +34,5 @@ int main(int argc, char **argv) { // CHECK0-NOT: DEDUP_TOKEN: // CHECK1: DEDUP_TOKEN: void Xyz::Abc<int, int>() -// CHECK1-NOT: bar // CHECK2: DEDUP_TOKEN: void Xyz::Abc<int, int>()--bar -// CHECK2-NOT: FOO // CHECK3: DEDUP_TOKEN: void Xyz::Abc<int, int>()--bar--FOO() diff --git a/test/sanitizer_common/TestCases/get_module_and_offset_for_pc.cc b/test/sanitizer_common/TestCases/get_module_and_offset_for_pc.cc new file mode 100644 index 0000000000000..f5a18e6721cf5 --- /dev/null +++ b/test/sanitizer_common/TestCases/get_module_and_offset_for_pc.cc @@ -0,0 +1,63 @@ +// RUN: %clangxx -DSHARED %s -shared -o %T/get_module_and_offset_for_pc.so -fPIC +// RUN: %clangxx -DSO_DIR=\"%T\" -O0 %s -ldl -o %t +// RUN: %run %t 2>&1 | FileCheck %s +// UNSUPPORTED: i386-darwin +// +// Tests __sanitizer_get_module_and_offset_for_pc. + +#include <assert.h> +#include <dlfcn.h> +#include <sanitizer/common_interface_defs.h> +#include <stdio.h> + +#ifdef SHARED +extern "C" { +int foo() { return 1; } +} +#else + +void Test(void *pc, const char *name) { + char module_name[1024]; + void *offset; + int ok = __sanitizer_get_module_and_offset_for_pc( + pc, module_name, sizeof(module_name), &offset); + if (!ok) { + printf("NOT FOUND %s: %p\n", name, pc); + } else { + printf("FOUND %s: %s %p\n", name, module_name, offset); + } +} + +void TestCallerPc() { Test(__builtin_return_address(0), "callerpc"); } + +void TestDlsym() { + void *handle = dlopen(SO_DIR "/get_module_and_offset_for_pc.so", RTLD_LAZY); + assert(handle); + void *foo = dlsym(handle, "foo"); + assert(foo); + Test(foo, "foo"); + dlclose(handle); +} + +// Call __sanitizer_get_module_and_offset_for_pc lots of times +// to make sure it is not too slow. +void TestLoop() { + void *pc = __builtin_return_address(0); + char module_name[1024]; + void *offset; + for (int i = 0; i < 1000000; ++i) { + __sanitizer_get_module_and_offset_for_pc(pc, module_name, + sizeof(module_name), &offset); + } +} + +int main() { + Test(0, "null"); + TestCallerPc(); + TestDlsym(); + TestLoop(); +} +#endif +// CHECK: NOT FOUND null: {{.*}} +// CHECK-NEXT: FOUND callerpc: {{.*}}/get_module_and_offset_for_pc.cc.tmp {{.*}} +// CHECK-NEXT: FOUND foo: {{.*}}/get_module_and_offset_for_pc.so {{.*}} diff --git a/test/sanitizer_common/TestCases/printf-ldbl.c b/test/sanitizer_common/TestCases/printf-ldbl.c new file mode 100644 index 0000000000000..f6629ab81c3b3 --- /dev/null +++ b/test/sanitizer_common/TestCases/printf-ldbl.c @@ -0,0 +1,13 @@ +// RUN: %clang %s -o %t && %run %t 2>&1 + +#include <assert.h> +#include <stdio.h> +#include <string.h> + +int main(int argc, char **argv) { + char buf[20]; + long double ld = 4.0; + snprintf(buf, sizeof buf, "%Lf %d", ld, 123); + assert(!strcmp(buf, "4.000000 123")); + return 0; +} diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc new file mode 100644 index 0000000000000..cf16ec3833123 --- /dev/null +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard-dso.cc @@ -0,0 +1,72 @@ +// Tests trace pc guard coverage collection. +// +// REQUIRES: has_sancovcc,stable-runtime +// XFAIL: tsan,darwin,powerpc64,s390x +// +// RUN: DIR=%t_workdir +// RUN: CLANG_ARGS="-O0 -fsanitize-coverage=trace-pc-guard" +// RUN: rm -rf $DIR +// RUN: mkdir -p $DIR +// RUN: cd $DIR +// RUN: %clangxx -DSHARED1 $CLANG_ARGS -shared %s -o %t_1.so -fPIC +// RUN: %clangxx -DSHARED2 $CLANG_ARGS -shared %s -o %t_2.so -fPIC +// RUN: %clangxx -DMAIN $CLANG_ARGS %s -o %t %t_1.so %t_2.so +// RUN: %env_tool_opts=coverage=1 %t 2>&1 | FileCheck %s +// RUN: %sancovcc -covered-functions -strip_path_prefix=TestCases/ *.sancov \ +// RUN: %t %t_1.so %t_2.so 2>&1 | \ +// RUN: FileCheck --check-prefix=CHECK-SANCOV %s +// RUN: rm -rf $DIR + +#include <stdio.h> + +extern "C" { + int bar(); + int baz(); +} + +#ifdef MAIN + +int foo() { + fprintf(stderr, "foo\n"); + return 1; +} + +int main() { + fprintf(stderr, "main\n"); + foo(); + bar(); + baz(); +} + +#endif // MAIN + +extern "C" { + +#ifdef SHARED1 +int bar() { + fprintf(stderr, "bar\n"); + return 1; +} +#endif + +#ifdef SHARED2 +int baz() { + fprintf(stderr, "baz\n"); + return 1; +} +#endif + +} // extern "C" + +// CHECK: main +// CHECK-NEXT: foo +// CHECK-NEXT: bar +// CHECK-NEXT: baz +// CHECK-DAG: SanitizerCoverage: ./sanitizer_coverage_trace_pc_guard-dso.{{.*}}.sancov 2 PCs written +// CHECK-DAG: SanitizerCoverage: ./sanitizer_coverage_trace_pc_guard-dso.{{.*}}_2.so.{{.*}}.sancov 1 PCs written +// CHECK-DAG: SanitizerCoverage: ./sanitizer_coverage_trace_pc_guard-dso.{{.*}}_1.so.{{.*}}.sancov 1 PCs written +// +// CHECK-SANCOV: Ignoring {{.*}}_1.so and its coverage because __sanitizer_cov* functions were not found. +// CHECK-SANCOV: Ignoring {{.*}}_2.so and its coverage because __sanitizer_cov* functions were not found. +// CHECK-SANCOV-NEXT: sanitizer_coverage_trace_pc_guard-dso.cc:29 foo +// CHECK-SANCOV-NEXT: sanitizer_coverage_trace_pc_guard-dso.cc:34 main diff --git a/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc new file mode 100644 index 0000000000000..1b787f143d467 --- /dev/null +++ b/test/sanitizer_common/TestCases/sanitizer_coverage_trace_pc_guard.cc @@ -0,0 +1,41 @@ +// Tests trace pc guard coverage collection. +// +// REQUIRES: has_sancovcc,stable-runtime +// XFAIL: tsan,darwin,powerpc64,s390x +// +// RUN: DIR=%t_workdir +// RUN: rm -rf $DIR +// RUN: mkdir -p $DIR +// RUN: cd $DIR +// RUN: %clangxx -O0 -fsanitize-coverage=trace-pc-guard %s -ldl -o %t +// RUN: %env_tool_opts=coverage=1 %t 2>&1 | FileCheck %s +// RUN: %sancovcc -covered-functions -strip_path_prefix=TestCases/ *.sancov %t 2>&1 | \ +// RUN: FileCheck --check-prefix=CHECK-SANCOV %s +// RUN: %env_tool_opts=coverage=0 %t 2>&1 | FileCheck --check-prefix=CHECK-NOCOV %s +// RUN: rm -rf $DIR +// Make some room to stabilize line numbers +// +// +// +#include <stdio.h> + +int foo() { + fprintf(stderr, "foo\n"); + return 1; +} + +int main() { + fprintf(stderr, "main\n"); + foo(); + foo(); +} + +// CHECK: main +// CHECK-NEXT: foo +// CHECK-NEXT: foo +// CHECK-NEXT: SanitizerCoverage: ./sanitizer_coverage_trace_pc_guard.{{.*}}.sancov 2 PCs written +// +// CHECK-SANCOV: sanitizer_coverage_trace_pc_guard.cc:22 foo +// CHECK-SANCOV-NEXT: sanitizer_coverage_trace_pc_guard.cc:27 main +// +// CHECK-NOCOV-NOT: SanitizerCoverage diff --git a/test/sanitizer_common/TestCases/scanf-ldbl.c b/test/sanitizer_common/TestCases/scanf-ldbl.c new file mode 100644 index 0000000000000..9ca30f4a65688 --- /dev/null +++ b/test/sanitizer_common/TestCases/scanf-ldbl.c @@ -0,0 +1,13 @@ +// RUN: %clang %s -o %t && %run %t 2>&1 + +#include <assert.h> +#include <stdio.h> +#include <string.h> + +int main(int argc, char **argv) { + long double ld; + memset(&ld, 255, sizeof ld); + sscanf("4.0", "%Lf", &ld); + assert(ld == 4.0); + return 0; +} diff --git a/test/sanitizer_common/TestCases/symbolize_pc.cc b/test/sanitizer_common/TestCases/symbolize_pc.cc new file mode 100644 index 0000000000000..0cc81e1f7dcfb --- /dev/null +++ b/test/sanitizer_common/TestCases/symbolize_pc.cc @@ -0,0 +1,41 @@ +// RUN: %clangxx -O0 %s -o %t +// RUN: %env_tool_opts=strip_path_prefix=/TestCases/ %run %t 2>&1 | FileCheck %s +// UNSUPPORTED: i386-darwin +// +// Tests __sanitizer_symbolize_pc. +#include <stdio.h> +#include <sanitizer/common_interface_defs.h> + +int GLOBAL_VAR_ABC; + +void SymbolizeCaller() { + char data[100]; + __sanitizer_symbolize_pc(__builtin_return_address(0), "%p %F %L", data, + sizeof(data)); + printf("FIRST_FORMAT %s\n", data); + __sanitizer_symbolize_pc(__builtin_return_address(0), + "FUNC:%f LINE:%l FILE:%s", data, sizeof(data)); + printf("SECOND_FORMAT %s\n", data); + __sanitizer_symbolize_pc(__builtin_return_address(0), + "LOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" + "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" + "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" + "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO" + "OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONG" + "FUNC:%f LINE:%l FILE:%s", data, sizeof(data)); + printf("LONG_FORMAT %s\n", data); +} + +void SymbolizeData() { + char data[100]; + __sanitizer_symbolize_global(&GLOBAL_VAR_ABC, "%g %s:%l", data, sizeof(data)); + printf("GLOBAL: %s\n", data); +} + +// CHECK: FIRST_FORMAT 0x{{.*}} in main symbolize_pc.cc:[[@LINE+3]] +// CHECK: SECOND_FORMAT FUNC:main LINE:[[@LINE+2]] FILE:symbolize_pc.cc +int main() { + SymbolizeCaller(); + SymbolizeData(); +} +// CHECK: GLOBAL: GLOBAL_VAR_ABC diff --git a/test/sanitizer_common/print_address.h b/test/sanitizer_common/print_address.h new file mode 100644 index 0000000000000..018db61800d3e --- /dev/null +++ b/test/sanitizer_common/print_address.h @@ -0,0 +1,19 @@ +#include <stdio.h> +#include <stdarg.h> + +void print_address(const char *str, int n, ...) { + fprintf(stderr, "%s", str); + va_list ap; + va_start(ap, n); + while (n--) { + void *p = va_arg(ap, void *); +#if defined(__x86_64__) || defined(__aarch64__) || defined(__powerpc64__) + // On FreeBSD, the %p conversion specifier works as 0x%x and thus does not + // match to the format used in the diagnotic message. + fprintf(stderr, "0x%012lx ", (unsigned long) p); +#elif defined(__mips64) + fprintf(stderr, "0x%010lx ", (unsigned long) p); +#endif + } + fprintf(stderr, "\n"); +} diff --git a/test/scudo/CMakeLists.txt b/test/scudo/CMakeLists.txt index b6cb2fd24f012..a8990999722e1 100644 --- a/test/scudo/CMakeLists.txt +++ b/test/scudo/CMakeLists.txt @@ -1,6 +1,7 @@ set(SCUDO_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(SCUDO_LIT_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}) +set(SCUDO_TESTSUITES) set(SCUDO_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) if(NOT COMPILER_RT_STANDALONE_BUILD) @@ -12,17 +13,21 @@ configure_lit_site_cfg( ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg ) -if(CMAKE_SYSTEM_NAME MATCHES "Linux") - EXEC_PROGRAM(cat ARGS "/proc/cpuinfo" OUTPUT_VARIABLE CPUINFO) - STRING(REGEX REPLACE "^.*(sse4_2).*$" "\\1" SSE_THERE ${CPUINFO}) - STRING(COMPARE EQUAL "sse4_2" "${SSE_THERE}" SSE42_TRUE) -endif(CMAKE_SYSTEM_NAME MATCHES "Linux") +set(SCUDO_TEST_ARCH ${SCUDO_SUPPORTED_ARCH}) +foreach(arch ${SCUDO_TEST_ARCH}) + set(SCUDO_TEST_TARGET_ARCH ${arch}) + string(TOLOWER "-${arch}" SCUDO_TEST_CONFIG_SUFFIX) + get_test_cc_for_arch(${arch} SCUDO_TEST_TARGET_CC SCUDO_TEST_TARGET_CFLAGS) + string(TOUPPER ${arch} ARCH_UPPER_CASE) + set(CONFIG_NAME ${ARCH_UPPER_CASE}${OS_NAME}Config) -if (SSE42_TRUE AND CMAKE_SIZEOF_VOID_P EQUAL 8) - add_lit_testsuite(check-scudo - "Running the Scudo Hardened Allocator tests" - ${CMAKE_CURRENT_BINARY_DIR} - DEPENDS ${SCUDO_TEST_DEPS}) - set_target_properties(check-scudo PROPERTIES FOLDER - "Compiler-RT Misc") -endif(SSE42_TRUE AND CMAKE_SIZEOF_VOID_P EQUAL 8) + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg) + list(APPEND SCUDO_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}) +endforeach() + +add_lit_testsuite(check-scudo "Running the Scudo Hardened Allocator tests" + ${SCUDO_TESTSUITES} + DEPENDS ${SCUDO_TEST_DEPS}) +set_target_properties(check-scudo PROPERTIES FOLDER "Compiler-RT Misc") diff --git a/test/scudo/alignment.cpp b/test/scudo/alignment.cpp index c5e57d1799079..a6eca87a82248 100644 --- a/test/scudo/alignment.cpp +++ b/test/scudo/alignment.cpp @@ -1,11 +1,10 @@ // RUN: %clang_scudo %s -o %t // RUN: not %run %t pointers 2>&1 | FileCheck %s -// Tests that a non-16-byte aligned pointer will trigger the associated error -// on deallocation. +// Tests that a non MinAlignment aligned pointer will trigger the associated +// error on deallocation. #include <assert.h> -#include <malloc.h> #include <stdint.h> #include <stdlib.h> #include <string.h> @@ -17,7 +16,7 @@ int main(int argc, char **argv) void *p = malloc(1U << 16); if (!p) return 1; - free(reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(p) | 8)); + free(reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(p) | 1)); } return 0; } diff --git a/test/scudo/double-free.cpp b/test/scudo/double-free.cpp index 4f5bf0cb8e56a..75919f0c459c5 100644 --- a/test/scudo/double-free.cpp +++ b/test/scudo/double-free.cpp @@ -46,4 +46,4 @@ int main(int argc, char **argv) return 0; } -// CHECK: ERROR: invalid chunk state when deallocating address +// CHECK: ERROR: invalid chunk state diff --git a/test/scudo/interface.cpp b/test/scudo/interface.cpp new file mode 100644 index 0000000000000..f9353066efa37 --- /dev/null +++ b/test/scudo/interface.cpp @@ -0,0 +1,28 @@ +// RUN: %clang_scudo %s -o %t +// RUN: %run %t 2>&1 + +// Tests that the sanitizer interface functions behave appropriately. + +#include <stdlib.h> + +#include <vector> + +#include <sanitizer/allocator_interface.h> + +int main(int argc, char **argv) +{ + void *p; + std::vector<ssize_t> sizes{1, 8, 16, 32, 1024, 32768, + 1 << 16, 1 << 17, 1 << 20, 1 << 24}; + for (size_t size : sizes) { + p = malloc(size); + if (!p) + return 1; + if (!__sanitizer_get_ownership(p)) + return 1; + if (__sanitizer_get_allocated_size(p) < size) + return 1; + free(p); + } + return 0; +} diff --git a/test/scudo/lit.cfg b/test/scudo/lit.cfg index e2a4997dd3c28..4eff2ce2191d0 100644 --- a/test/scudo/lit.cfg +++ b/test/scudo/lit.cfg @@ -3,7 +3,7 @@ import os # Setup config name. -config.name = 'Scudo' +config.name = 'Scudo' + config.name_suffix # Setup source root. config.test_source_root = os.path.dirname(__file__) @@ -14,18 +14,19 @@ base_lib = os.path.join(config.compiler_rt_libdir, whole_archive = "-Wl,-whole-archive %s -Wl,-no-whole-archive " % base_lib # Test suffixes. -config.suffixes = ['.c', '.cc', '.cpp', '.m', '.mm', '.ll', '.test'] +config.suffixes = ['.c', '.cc', '.cpp'] # C flags. -c_flags = ["-std=c++11", +c_flags = ([config.target_cflags] + + ["-std=c++11", "-lstdc++", - "-ldl", "-lrt", - "-pthread", "-latomic", + "-ldl", + "-pthread", "-fPIE", "-pie", - "-O0"] + "-O0"]) def build_invocation(compile_flags): return " " + " ".join([config.clang] + compile_flags) + " " diff --git a/test/scudo/lit.site.cfg.in b/test/scudo/lit.site.cfg.in index 64e2fb39eed8a..4299518755e98 100644 --- a/test/scudo/lit.site.cfg.in +++ b/test/scudo/lit.site.cfg.in @@ -1,5 +1,9 @@ @LIT_SITE_CFG_IN_HEADER@ +config.name_suffix = "@SCUDO_TEST_CONFIG_SUFFIX@" +config.target_arch = "@SCUDO_TEST_TARGET_ARCH@" +config.target_cflags = "@SCUDO_TEST_TARGET_CFLAGS@" + # Load common config for all compiler-rt lit tests. lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") diff --git a/test/scudo/malloc.cpp b/test/scudo/malloc.cpp index 4507a5225ceb7..cafc744a20c24 100644 --- a/test/scudo/malloc.cpp +++ b/test/scudo/malloc.cpp @@ -2,26 +2,37 @@ // RUN: %run %t 2>&1 // Tests that a regular workflow of allocation, memory fill and free works as -// intended. Also tests that a zero-sized allocation succeeds. +// intended. Tests various sizes serviced by the primary and secondary +// allocators. -#include <malloc.h> #include <stdlib.h> #include <string.h> +#include <vector> + int main(int argc, char **argv) { void *p; - size_t size = 1U << 8; + std::vector<ssize_t> sizes{1, 8, 16, 32, 1024, 32768, + 1 << 16, 1 << 17, 1 << 20, 1 << 24}; + std::vector<int> offsets{1, 0, -1, -7, -8, -15, -16, -31, -32}; - p = malloc(size); - if (!p) - return 1; - memset(p, 'A', size); - free(p); p = malloc(0); if (!p) return 1; free(p); + for (ssize_t size : sizes) { + for (int offset: offsets) { + ssize_t actual_size = size + offset; + if (actual_size <= 0) + continue; + p = malloc(actual_size); + if (!p) + return 1; + memset(p, 0xff, actual_size); + free(p); + } + } return 0; } diff --git a/test/scudo/memalign.cpp b/test/scudo/memalign.cpp index 951d1aade6ec9..b407ec5743490 100644 --- a/test/scudo/memalign.cpp +++ b/test/scudo/memalign.cpp @@ -10,22 +10,24 @@ #include <stdlib.h> #include <string.h> +// Reduce the size of the quarantine, or the test can run out of aligned memory +// on 32-bit for the larger alignments. +extern "C" const char *__scudo_default_options() { + return "QuarantineSizeMb=1"; +} + // Sometimes the headers may not have this... extern "C" void *aligned_alloc (size_t alignment, size_t size); int main(int argc, char **argv) { - void *p; + void *p = nullptr; size_t alignment = 1U << 12; - size_t size = alignment; + size_t size = 1U << 12; assert(argc == 2); + if (!strcmp(argv[1], "valid")) { - p = memalign(alignment, size); - if (!p) - return 1; - free(p); - p = nullptr; posix_memalign(&p, alignment, size); if (!p) return 1; @@ -34,6 +36,29 @@ int main(int argc, char **argv) if (!p) return 1; free(p); + // Tests various combinations of alignment and sizes + for (int i = (sizeof(void *) == 4) ? 3 : 4; i < 19; i++) { + alignment = 1U << i; + for (int j = 1; j < 33; j++) { + size = 0x800 * j; + for (int k = 0; k < 3; k++) { + p = memalign(alignment, size - (2 * sizeof(void *) * k)); + if (!p) + return 1; + free(p); + } + } + } + // For larger alignment, reduce the number of allocations to avoid running + // out of potential addresses (on 32-bit). + for (int i = 19; i <= 24; i++) { + for (int k = 0; k < 3; k++) { + p = memalign(alignment, 0x1000 - (2 * sizeof(void *) * k)); + if (!p) + return 1; + free(p); + } + } } if (!strcmp(argv[1], "invalid")) { p = memalign(alignment - 1, size); @@ -42,4 +67,4 @@ int main(int argc, char **argv) return 0; } -// CHECK: ERROR: malloc alignment is not a power of 2 +// CHECK: ERROR: alignment is not a power of 2 diff --git a/test/scudo/mismatch.cpp b/test/scudo/mismatch.cpp index 2d3d198af640a..54cdafc86ee67 100644 --- a/test/scudo/mismatch.cpp +++ b/test/scudo/mismatch.cpp @@ -30,7 +30,7 @@ int main(int argc, char **argv) free((void *)p); } if (!strcmp(argv[1], "memaligndel")) { - int *p = (int *)memalign(0x10, 0x10); + int *p = (int *)memalign(16, 16); if (!p) return 1; delete p; diff --git a/test/scudo/options.cpp b/test/scudo/options.cpp new file mode 100644 index 0000000000000..bccf7c8fbd2b9 --- /dev/null +++ b/test/scudo/options.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_scudo %s -o %t +// RUN: %run %t 2>&1 +// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=0 %run %t 2>&1 +// RUN: SCUDO_OPTIONS=DeallocationTypeMismatch=1 not %run %t 2>&1 | FileCheck %s + +// Tests that the options can be passed using getScudoDefaultOptions, and that +// the environment ones take precedence over them. + +#include <stdlib.h> +#include <malloc.h> + +extern "C" const char* __scudo_default_options() { + return "DeallocationTypeMismatch=0"; // Defaults to true in scudo_flags.inc. +} + +int main(int argc, char **argv) +{ + int *p = (int *)malloc(16); + if (!p) + return 1; + delete p; + return 0; +} + +// CHECK: ERROR: allocation type mismatch on address diff --git a/test/scudo/overflow.cpp b/test/scudo/overflow.cpp index 5b2cb7560133a..c93a544ea0a07 100644 --- a/test/scudo/overflow.cpp +++ b/test/scudo/overflow.cpp @@ -11,12 +11,13 @@ int main(int argc, char **argv) { assert(argc == 2); + ssize_t offset = sizeof(void *) == 8 ? 8 : 0; if (!strcmp(argv[1], "malloc")) { // Simulate a header corruption of an allocated chunk (1-bit) void *p = malloc(1U << 4); if (!p) return 1; - ((char *)p)[-1] ^= 1; + ((char *)p)[-(offset + 1)] ^= 1; free(p); } if (!strcmp(argv[1], "quarantine")) { @@ -25,7 +26,7 @@ int main(int argc, char **argv) return 1; free(p); // Simulate a header corruption of a quarantined chunk - ((char *)p)[-2] ^= 1; + ((char *)p)[-(offset + 2)] ^= 1; // Trigger the quarantine recycle for (int i = 0; i < 0x100; i++) { p = malloc(1U << 16); diff --git a/test/scudo/preinit.cpp b/test/scudo/preinit.cpp index a280ae1d440a9..34f61c9ddfbb4 100644 --- a/test/scudo/preinit.cpp +++ b/test/scudo/preinit.cpp @@ -4,7 +4,6 @@ // Verifies that calling malloc in a preinit_array function succeeds, and that // the resulting pointer can be freed at program termination. -#include <malloc.h> #include <stdlib.h> #include <string.h> diff --git a/test/scudo/random_shuffle.cpp b/test/scudo/random_shuffle.cpp new file mode 100644 index 0000000000000..fce522d9481c6 --- /dev/null +++ b/test/scudo/random_shuffle.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_scudo %s -o %t +// RUN: rm -rf %T/random_shuffle_tmp_dir +// RUN: mkdir %T/random_shuffle_tmp_dir +// RUN: %run %t 100 > %T/random_shuffle_tmp_dir/out1 +// RUN: %run %t 100 > %T/random_shuffle_tmp_dir/out2 +// RUN: %run %t 10000 > %T/random_shuffle_tmp_dir/out1 +// RUN: %run %t 10000 > %T/random_shuffle_tmp_dir/out2 +// RUN: not diff %T/random_shuffle_tmp_dir/out? +// RUN: rm -rf %T/random_shuffle_tmp_dir +// UNSUPPORTED: i386-linux,i686-linux,arm-linux,armhf-linux + +// Tests that the allocator shuffles the chunks before returning to the user. + +#include <stdlib.h> +#include <stdio.h> + +int main(int argc, char **argv) { + int alloc_size = argc == 2 ? atoi(argv[1]) : 100; + char *base = new char[alloc_size]; + for (int i = 0; i < 20; i++) { + char *p = new char[alloc_size]; + printf("%zd\n", base - p); + } +} diff --git a/test/scudo/realloc.cpp b/test/scudo/realloc.cpp index 2a7d5b69f5f20..cc44595001f43 100644 --- a/test/scudo/realloc.cpp +++ b/test/scudo/realloc.cpp @@ -14,54 +14,60 @@ #include <malloc.h> #include <string.h> +#include <vector> + int main(int argc, char **argv) { void *p, *old_p; - size_t size = 32; + // Those sizes will exercise both allocators (Primary & Secondary). + std::vector<size_t> sizes{1, 16, 1024, 32768, 1 << 16, 1 << 17, 1 << 20}; assert(argc == 2); - if (!strcmp(argv[1], "pointers")) { - old_p = p = realloc(nullptr, size); - if (!p) - return 1; - size = malloc_usable_size(p); - // Our realloc implementation will return the same pointer if the size - // requested is lower or equal to the usable size of the associated chunk. - p = realloc(p, size - 1); - if (p != old_p) - return 1; - p = realloc(p, size); - if (p != old_p) - return 1; - // And a new one if the size is greater. - p = realloc(p, size + 1); - if (p == old_p) - return 1; - // A size of 0 will free the chunk and return nullptr. - p = realloc(p, 0); - if (p) - return 1; - old_p = nullptr; - } - if (!strcmp(argv[1], "contents")) { - p = realloc(nullptr, size); - if (!p) - return 1; - for (int i = 0; i < size; i++) - reinterpret_cast<char *>(p)[i] = 'A'; - p = realloc(p, size + 1); - // The contents of the reallocated chunk must match the original one. - for (int i = 0; i < size; i++) - if (reinterpret_cast<char *>(p)[i] != 'A') + for (size_t size : sizes) { + if (!strcmp(argv[1], "pointers")) { + old_p = p = realloc(nullptr, size); + if (!p) return 1; - } - if (!strcmp(argv[1], "memalign")) { - // A chunk coming from memalign cannot be reallocated. - p = memalign(16, size); - if (!p) - return 1; - p = realloc(p, size); - free(p); + size = malloc_usable_size(p); + // Our realloc implementation will return the same pointer if the size + // requested is lower than or equal to the usable size of the associated + // chunk. + p = realloc(p, size - 1); + if (p != old_p) + return 1; + p = realloc(p, size); + if (p != old_p) + return 1; + // And a new one if the size is greater. + p = realloc(p, size + 1); + if (p == old_p) + return 1; + // A size of 0 will free the chunk and return nullptr. + p = realloc(p, 0); + if (p) + return 1; + old_p = nullptr; + } + if (!strcmp(argv[1], "contents")) { + p = realloc(nullptr, size); + if (!p) + return 1; + for (int i = 0; i < size; i++) + reinterpret_cast<char *>(p)[i] = 'A'; + p = realloc(p, size + 1); + // The contents of the reallocated chunk must match the original one. + for (int i = 0; i < size; i++) + if (reinterpret_cast<char *>(p)[i] != 'A') + return 1; + } + if (!strcmp(argv[1], "memalign")) { + // A chunk coming from memalign cannot be reallocated. + p = memalign(16, size); + if (!p) + return 1; + p = realloc(p, size); + free(p); + } } return 0; } diff --git a/test/scudo/secondary.cpp b/test/scudo/secondary.cpp new file mode 100644 index 0000000000000..7a634a81eb03e --- /dev/null +++ b/test/scudo/secondary.cpp @@ -0,0 +1,54 @@ +// RUN: %clang_scudo %s -o %t +// RUN: %run %t after 2>&1 | FileCheck %s +// RUN: %run %t before 2>&1 | FileCheck %s + +// Test that we hit a guard page when writing past the end of a chunk +// allocated by the Secondary allocator, or writing too far in front of it. + +#include <malloc.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <signal.h> +#include <assert.h> + +void handler(int signo, siginfo_t *info, void *uctx) { + if (info->si_code == SEGV_ACCERR) { + fprintf(stderr, "SCUDO SIGSEGV\n"); + exit(0); + } + exit(1); +} + +int main(int argc, char **argv) +{ + // The size must be large enough to be serviced by the secondary allocator. + long page_size = sysconf(_SC_PAGESIZE); + size_t size = (1U << 17) + page_size; + struct sigaction a; + + assert(argc == 2); + memset(&a, 0, sizeof(a)); + a.sa_sigaction = handler; + a.sa_flags = SA_SIGINFO; + + char *p = (char *)malloc(size); + if (!p) + return 1; + memset(p, 'A', size); // This should not trigger anything. + // Set up the SIGSEGV handler now, as the rest should trigger an AV. + sigaction(SIGSEGV, &a, nullptr); + if (!strcmp(argv[1], "after")) { + for (int i = 0; i < page_size; i++) + p[size + i] = 'A'; + } + if (!strcmp(argv[1], "before")) { + for (int i = 1; i < page_size; i++) + p[-i] = 'A'; + } + free(p); + + return 1; // A successful test means we shouldn't reach this. +} + +// CHECK: SCUDO SIGSEGV diff --git a/test/tsan/CMakeLists.txt b/test/tsan/CMakeLists.txt index e05b100f36995..2db6ce0a8c1a4 100644 --- a/test/tsan/CMakeLists.txt +++ b/test/tsan/CMakeLists.txt @@ -24,15 +24,7 @@ endif() foreach(arch ${TSAN_TEST_ARCH}) set(TSAN_TEST_TARGET_ARCH ${arch}) string(TOLOWER "-${arch}" TSAN_TEST_CONFIG_SUFFIX) - if(ANDROID OR ${arch} MATCHES "arm|aarch64") - # This is only true if we are cross-compiling. - # Build all tests with host compiler and use host tools. - set(TSAN_TEST_TARGET_CC ${COMPILER_RT_TEST_COMPILER}) - set(TSAN_TEST_TARGET_CFLAGS ${COMPILER_RT_TEST_COMPILER_CFLAGS}) - else() - get_target_flags_for_arch(${arch} TSAN_TEST_TARGET_CFLAGS) - string(REPLACE ";" " " TSAN_TEST_TARGET_CFLAGS "${TSAN_TEST_TARGET_CFLAGS}") - endif() + get_test_cc_for_arch(${arch} TSAN_TEST_TARGET_CC TSAN_TEST_TARGET_CFLAGS) string(TOUPPER ${arch} ARCH_UPPER_CASE) set(CONFIG_NAME ${ARCH_UPPER_CASE}Config) diff --git a/test/tsan/Darwin/gcd-apply-race.mm b/test/tsan/Darwin/gcd-apply-race.mm index 13b24e0fdb90e..028be1ac5b1cc 100644 --- a/test/tsan/Darwin/gcd-apply-race.mm +++ b/test/tsan/Darwin/gcd-apply-race.mm @@ -10,6 +10,10 @@ long global; int main(int argc, const char *argv[]) { barrier_init(&barrier, 2); fprintf(stderr, "start\n"); + + // Warm up GCD (workaround for macOS Sierra where dispatch_apply might run single-threaded). + dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ }); + dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT); dispatch_apply(2, q, ^(size_t i) { global = i; diff --git a/test/tsan/Darwin/gcd-apply.mm b/test/tsan/Darwin/gcd-apply.mm index e68a4b18205d9..a7dc3740dc7b5 100644 --- a/test/tsan/Darwin/gcd-apply.mm +++ b/test/tsan/Darwin/gcd-apply.mm @@ -17,6 +17,10 @@ void callback(void *context, size_t i) { int main(int argc, const char *argv[]) { barrier_init(&barrier, 2); fprintf(stderr, "start\n"); + + // Warm up GCD (workaround for macOS Sierra where dispatch_apply might run single-threaded). + dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ }); + dispatch_queue_t q = dispatch_queue_create("my.queue", DISPATCH_QUEUE_CONCURRENT); global = 42; diff --git a/test/tsan/Darwin/gcd-suspend.mm b/test/tsan/Darwin/gcd-suspend.mm new file mode 100644 index 0000000000000..3e8818a2d56e7 --- /dev/null +++ b/test/tsan/Darwin/gcd-suspend.mm @@ -0,0 +1,45 @@ +// RUN: %clang_tsan %s -o %t -framework Foundation +// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s + +#import <Foundation/Foundation.h> + +long my_global = 0; + +int main(int argc, const char *argv[]) { + fprintf(stderr, "Hello world.\n"); + + dispatch_queue_t q1 = dispatch_queue_create("queue1", NULL); + dispatch_queue_t q2 = dispatch_queue_create("queue2", NULL); + dispatch_group_t g = dispatch_group_create(); + + dispatch_sync(q1, ^{ + dispatch_suspend(q1); + dispatch_async(q2, ^{ + my_global++; + dispatch_resume(q1); + }); + }); + + dispatch_sync(q1, ^{ + my_global++; + }); + + dispatch_sync(q1, ^{ + dispatch_suspend(q1); + dispatch_group_enter(g); + dispatch_async(q1,^{ my_global++; }); + dispatch_async(q1,^{ my_global++; }); + dispatch_async(q1,^{ my_global++; dispatch_group_leave(g); }); + my_global++; + dispatch_resume(q1); + }); + + dispatch_group_wait(g, DISPATCH_TIME_FOREVER); + + fprintf(stderr, "Done.\n"); + return 0; +} + +// CHECK: Hello world. +// CHECK-NOT: WARNING: ThreadSanitizer +// CHECK: Done. diff --git a/test/tsan/Darwin/gcd-target-queue-norace.mm b/test/tsan/Darwin/gcd-target-queue-norace.mm new file mode 100644 index 0000000000000..36cb1b9298de0 --- /dev/null +++ b/test/tsan/Darwin/gcd-target-queue-norace.mm @@ -0,0 +1,41 @@ +// RUN: %clang_tsan %s -o %t -framework Foundation +// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s + +#import <Foundation/Foundation.h> + +long global; + +int main(int argc, const char *argv[]) { + dispatch_queue_t target_queue = dispatch_queue_create(NULL, DISPATCH_QUEUE_SERIAL); + dispatch_queue_t q1 = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT); + dispatch_queue_t q2 = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT); + dispatch_set_target_queue(q1, target_queue); + dispatch_set_target_queue(q2, target_queue); + + for (int i = 0; i < 100000; i++) { + dispatch_async(q1, ^{ + global++; + + if (global == 200000) { + dispatch_sync(dispatch_get_main_queue(), ^{ + CFRunLoopStop(CFRunLoopGetCurrent()); + }); + } + }); + dispatch_async(q2, ^{ + global++; + + if (global == 200000) { + dispatch_sync(dispatch_get_main_queue(), ^{ + CFRunLoopStop(CFRunLoopGetCurrent()); + }); + } + }); + } + + CFRunLoopRun(); + NSLog(@"Done."); + return 0; +} + +// CHECK-NOT: WARNING: ThreadSanitizer diff --git a/test/tsan/Darwin/libcxx-call-once.mm b/test/tsan/Darwin/libcxx-call-once.mm new file mode 100644 index 0000000000000..5388e495c9c26 --- /dev/null +++ b/test/tsan/Darwin/libcxx-call-once.mm @@ -0,0 +1,34 @@ +// RUN: %clangxx_tsan %s -o %t -framework Foundation -std=c++11 +// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s + +#import <Foundation/Foundation.h> + +#import <iostream> +#import <thread> + +long my_global; +std::once_flag once_token; + +void thread_func() { + std::call_once(once_token, [] { + my_global = 17; + }); + + long val = my_global; + fprintf(stderr, "my_global = %ld\n", val); +} + +int main(int argc, const char *argv[]) { + fprintf(stderr, "Hello world.\n"); + + std::thread t1(thread_func); + std::thread t2(thread_func); + t1.join(); + t2.join(); + + fprintf(stderr, "Done.\n"); +} + +// CHECK: Hello world. +// CHECK-NOT: WARNING: ThreadSanitizer +// CHECK: Done. diff --git a/test/tsan/Darwin/libcxx-future.mm b/test/tsan/Darwin/libcxx-future.mm new file mode 100644 index 0000000000000..902f267ecb89d --- /dev/null +++ b/test/tsan/Darwin/libcxx-future.mm @@ -0,0 +1,30 @@ +// RUN: %clangxx_tsan %s -o %t +// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s + +#include <iostream> +#include <future> +#include <vector> + +int main(int argc, const char *argv[]) { + fprintf(stderr, "Hello world.\n"); + + auto my_task = [] { return 42; }; + + std::vector<std::thread> threads; + + for (int i = 0; i < 100; i++) { + std::packaged_task<int(void)> task(my_task); + std::future<int> future = task.get_future(); + threads.push_back(std::thread(std::move(task))); + } + + for (auto &t : threads) { + t.join(); + } + + fprintf(stderr, "Done.\n"); +} + +// CHECK: Hello world. +// CHECK-NOT: WARNING: ThreadSanitizer +// CHECK: Done. diff --git a/test/tsan/Darwin/norace-objcxx-run-time.mm b/test/tsan/Darwin/norace-objcxx-run-time.mm new file mode 100644 index 0000000000000..0cf729e7f2d87 --- /dev/null +++ b/test/tsan/Darwin/norace-objcxx-run-time.mm @@ -0,0 +1,113 @@ +// RUN: %clang_tsan %s -lc++ -fobjc-arc -lobjc -o %t -framework Foundation +// RUN: %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s + +// Check that we do not report races between: +// - Object retain and initialize +// - Object release and dealloc +// - Object release and .cxx_destruct + +#import <Foundation/Foundation.h> +#include "../test.h" +invisible_barrier_t barrier2; + +class NeedCleanup { + public: + int x; + NeedCleanup() { + x = 1; + } + ~NeedCleanup() { + x = 0; + } +}; + +@interface TestDeallocObject : NSObject { + @public + int v; + } + - (id)init; + - (void)accessMember; + - (void)dealloc; +@end + +@implementation TestDeallocObject + - (id)init { + if ([super self]) { + v = 1; + return self; + } + return nil; + } + - (void)accessMember { + int local = v; + local++; + } + - (void)dealloc { + v = 0; + } +@end + +@interface TestCXXDestructObject : NSObject { + @public + NeedCleanup cxxMemberWithCleanup; + } + - (void)accessMember; +@end + +@implementation TestCXXDestructObject + - (void)accessMember { + int local = cxxMemberWithCleanup.x; + local++; + } +@end + +@interface TestInitializeObject : NSObject +@end + +@implementation TestInitializeObject + static long InitializerAccessedGlobal = 0; + + (void)initialize { + InitializerAccessedGlobal = 42; + } +@end + +int main(int argc, const char *argv[]) { + // Ensure that there is no race when calling initialize on TestInitializeObject; + // otherwise, the locking from ObjC runtime becomes observable. Also ensures that + // blocks are dispatched to 2 different threads. + barrier_init(&barrier, 2); + // Ensure that objects are destructed during block object release. + barrier_init(&barrier2, 3); + + TestDeallocObject *tdo = [[TestDeallocObject alloc] init]; + TestCXXDestructObject *tcxxdo = [[TestCXXDestructObject alloc] init]; + [tdo accessMember]; + [tcxxdo accessMember]; + { + dispatch_queue_t q = dispatch_queue_create(NULL, DISPATCH_QUEUE_CONCURRENT); + dispatch_async(q, ^{ + [TestInitializeObject new]; + barrier_wait(&barrier); + long local = InitializerAccessedGlobal; + local++; + [tdo accessMember]; + [tcxxdo accessMember]; + barrier_wait(&barrier2); + }); + dispatch_async(q, ^{ + barrier_wait(&barrier); + [TestInitializeObject new]; + long local = InitializerAccessedGlobal; + local++; + [tdo accessMember]; + [tcxxdo accessMember]; + barrier_wait(&barrier2); + }); + } + barrier_wait(&barrier2); + NSLog(@"Done."); + return 0; +} + +// CHECK: Done. +// CHECK-NOT: ThreadSanitizer: data race diff --git a/test/tsan/Darwin/objc-double-property.mm b/test/tsan/Darwin/objc-double-property.mm new file mode 100644 index 0000000000000..51b10f21c9cae --- /dev/null +++ b/test/tsan/Darwin/objc-double-property.mm @@ -0,0 +1,21 @@ +// RUN: %clangxx_tsan -O0 %s -o %t -framework Foundation && %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_tsan -O1 %s -o %t -framework Foundation && %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_tsan -O2 %s -o %t -framework Foundation && %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_tsan -O3 %s -o %t -framework Foundation && %env_tsan_opts=ignore_interceptors_accesses=1 %run %t 2>&1 | FileCheck %s + +#import <Foundation/Foundation.h> + +@interface MyClass : NSObject +@property float a; +@property double b; +@property long double c; +@end + +@implementation MyClass +@end + +int main() { + NSLog(@"Hello world"); +} + +// CHECK: Hello world diff --git a/test/tsan/Darwin/osatomics-bitops.mm b/test/tsan/Darwin/osatomics-bitops.mm new file mode 100644 index 0000000000000..68badb792fd66 --- /dev/null +++ b/test/tsan/Darwin/osatomics-bitops.mm @@ -0,0 +1,34 @@ +// RUN: %clangxx_tsan %s -o %t -framework Foundation -std=c++11 +// RUN: %run %t 2>&1 | FileCheck %s + +#import <Foundation/Foundation.h> +#import <libkern/OSAtomic.h> + +int main(int argc, const char *argv[]) { + int value = 1; + bool ret = OSAtomicTestAndClear(7, &value); + fprintf(stderr, "value = %d, ret = %d\n", value, ret); + // CHECK: value = 0, ret = 1 + + ret = OSAtomicTestAndSet(4, &value); + fprintf(stderr, "value = %d, ret = %d\n", value, ret); + // CHECK: value = 8, ret = 0 + + ret = OSAtomicTestAndClear(4, &value); + fprintf(stderr, "value = %d, ret = %d\n", value, ret); + // CHECK: value = 0, ret = 1 + + ret = OSAtomicTestAndSet(12, &value); + fprintf(stderr, "value = %d, ret = %d\n", value, ret); + // CHECK: value = 2048, ret = 0 + + ret = OSAtomicTestAndSet(13, &value); + fprintf(stderr, "value = %d, ret = %d\n", value, ret); + // CHECK: value = 3072, ret = 0 + + ret = OSAtomicTestAndClear(12, &value); + fprintf(stderr, "value = %d, ret = %d\n", value, ret); + // CHECK: value = 1024, ret = 1 + + return 0; +} diff --git a/test/tsan/Darwin/realloc-zero.cc b/test/tsan/Darwin/realloc-zero.cc new file mode 100644 index 0000000000000..98262463cb2d1 --- /dev/null +++ b/test/tsan/Darwin/realloc-zero.cc @@ -0,0 +1,20 @@ +// Test that realloc(nullptr, 0) return a non-NULL pointer. + +// RUN: %clang_tsan %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +#include <malloc/malloc.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/mman.h> + +int main() { + void *p = realloc(NULL, 0); + if (!p) { + abort(); + } + fprintf(stderr, "Okay.\n"); + return 0; +} + +// CHECK: Okay. diff --git a/test/tsan/atomic_free.cc b/test/tsan/atomic_free.cc index a0d8e426b49fc..446949ddb986b 100644 --- a/test/tsan/atomic_free.cc +++ b/test/tsan/atomic_free.cc @@ -1,4 +1,13 @@ -// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s +// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s + +// Also check that atomics instrumentation can be configured by either driver or +// legacy flags: + +// RUN: %clangxx_tsan -O1 %s -o %t -fno-sanitize-thread-atomics && not %deflake %run %t 2>&1 \ +// RUN: | FileCheck --allow-empty --check-prefix=CHECK-NO-ATOMICS %s +// RUN: %clangxx_tsan -O1 %s -o %t -mllvm -tsan-instrument-atomics=0 && not %deflake %run %t 2>&1 \ +// RUN: | FileCheck --allow-empty --check-prefix=CHECK-NO-ATOMICS %s <%t + #include "test.h" void *Thread(void *a) { @@ -18,3 +27,5 @@ int main() { } // CHECK: WARNING: ThreadSanitizer: data race + +// CHECK-NO-ATOMICS-NOT: WARNING: ThreadSanitizer: data race diff --git a/test/tsan/atomic_store.cc b/test/tsan/atomic_store.cc new file mode 100644 index 0000000000000..7ff4879d3cae6 --- /dev/null +++ b/test/tsan/atomic_store.cc @@ -0,0 +1,49 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s +#include "test.h" + +long long Data; +long long Sync; + +void *Thread1(void *x) { + Data++; + __atomic_store_n(&Sync, 1, __ATOMIC_RELEASE); + barrier_wait(&barrier); + barrier_wait(&barrier); + return NULL; +} + +void *Thread2(void *x) { + barrier_wait(&barrier); + if (__atomic_load_n(&Sync, __ATOMIC_RELAXED) != 1) + exit(0); + // This store must terminate release sequence of the store in Thread1, + // thus tsan must detect race between Thread1 and main on Data. + __atomic_store_n(&Sync, 2, __ATOMIC_RELEASE); + barrier_wait(&barrier); + return NULL; +} + +int main() { + barrier_init(&barrier, 3); + pthread_t t[2]; + pthread_create(&t[0], NULL, Thread1, NULL); + pthread_create(&t[1], NULL, Thread2, NULL); + barrier_wait(&barrier); + barrier_wait(&barrier); + if (__atomic_load_n(&Sync, __ATOMIC_ACQUIRE) != 2) + exit(0); + if (Data != 1) + exit(0); + pthread_join(t[0], NULL); + pthread_join(t[1], NULL); + fprintf(stderr, "DONE\n"); + return 0; +} + +// CHECK: WARNING: ThreadSanitizer: data race +// CHECK: Read +// CHECK: #0 main +// CHECK: Previous write +// CHECK: #0 Thread1 +// CHECK: Location is global 'Data' +// CHECK: DONE diff --git a/test/tsan/debug_alloc_stack.cc b/test/tsan/debug_alloc_stack.cc new file mode 100644 index 0000000000000..303c103206f8e --- /dev/null +++ b/test/tsan/debug_alloc_stack.cc @@ -0,0 +1,84 @@ +// RUN: %clangxx_tsan -O0 %s -o %t +// RUN: env %env_tsan_opts=stack_trace_format=DEFAULT %deflake %run %t 2>&1 | FileCheck %s + +// Until I figure out how to make this test work on Linux +// REQUIRES: system-darwin + +#include "test.h" +#include <pthread.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> + +#ifndef __APPLE__ +#include <sys/types.h> +#endif + +extern "C" int __tsan_get_alloc_stack(void *addr, void **trace, size_t size, + int *thread_id, void *os_id); + +char *mem; +void alloc_func() { mem = (char *)malloc(10); } + +void *AllocThread(void *context) { + uint64_t tid; +#ifdef __APPLE__ + pthread_threadid_np(NULL, &tid); +#else + tid = gettid(); +#endif + fprintf(stderr, "alloc stack thread os id = 0x%llx\n", tid); + // CHECK: alloc stack thread os id = [[THREAD_OS_ID:0x[0-9a-f]+]] + alloc_func(); + return NULL; +} + +void *RaceThread(void *context) { + *mem = 'a'; + barrier_wait(&barrier); + return NULL; +} + +int main() { + pthread_t t; + barrier_init(&barrier, 2); + + pthread_create(&t, NULL, AllocThread, NULL); + pthread_join(t, NULL); + + void *trace[100]; + size_t num_frames = 100; + int thread_id; + void *thread_os_id; + num_frames = + __tsan_get_alloc_stack(mem, trace, num_frames, &thread_id, &thread_os_id); + + fprintf(stderr, "alloc stack retval %s\n", + (num_frames > 0 && num_frames < 10) ? "ok" : ""); + // CHECK: alloc stack retval ok + fprintf(stderr, "thread id = %d\n", thread_id); + // CHECK: thread id = 1 + fprintf(stderr, "thread os id = 0x%llx\n", (uint64_t)thread_os_id); + // CHECK: thread os id = [[THREAD_OS_ID]] + fprintf(stderr, "%p\n", trace[0]); + // CHECK: [[ALLOC_FRAME_0:0x[0-9a-f]+]] + fprintf(stderr, "%p\n", trace[1]); + // CHECK: [[ALLOC_FRAME_1:0x[0-9a-f]+]] + fprintf(stderr, "%p\n", trace[2]); + // CHECK: [[ALLOC_FRAME_2:0x[0-9a-f]+]] + + pthread_create(&t, NULL, RaceThread, NULL); + barrier_wait(&barrier); + mem[0] = 'b'; + pthread_join(t, NULL); + + free(mem); + + return 0; +} + +// CHECK: WARNING: ThreadSanitizer: data race +// CHECK: Location is heap block of size 10 at {{.*}} allocated by thread T1 +// CHECK: #0 [[ALLOC_FRAME_0]] +// CHECK: #1 [[ALLOC_FRAME_1]] in alloc_func +// CHECK: #2 [[ALLOC_FRAME_2]] in AllocThread diff --git a/test/tsan/debug_locate.cc b/test/tsan/debug_locate.cc new file mode 100644 index 0000000000000..01b0960d85b72 --- /dev/null +++ b/test/tsan/debug_locate.cc @@ -0,0 +1,43 @@ +// RUN: %clangxx_tsan -O0 %s -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +#include <stdio.h> +#include <stdlib.h> + +extern "C" const char * +__tsan_locate_address(void *addr, char *name, size_t name_size, + void **region_address_ptr, size_t *region_size_ptr); + +long global_var; + +int main() { + long stack_var; + void *heap_var = malloc(10); + + fprintf(stderr, "stack_var = %p\n", &stack_var); + fprintf(stderr, "global_var = %p\n", &global_var); + fprintf(stderr, "heap_var = %p\n", heap_var); + // CHECK: stack_var = [[STACK_VAR:0x[0-9a-f]+]] + // CHECK: global_var = [[GLOBAL_VAR:0x[0-9a-f]+]] + // CHECK: heap_var = [[HEAP_VAR:0x[0-9a-f]+]] + + const char *type; + char name[128]; + void *start; + size_t size; + type = __tsan_locate_address(&stack_var, name, 128, &start, &size); + fprintf(stderr, "type: %s\n", type); + // CHECK: type: stack + + type = __tsan_locate_address(&global_var, name, 128, &start, &size); + fprintf(stderr, "type: %s, name = %s, start = %p, size = %zu\n", type, name, + start, size); + // CHECK: type: global, name = global_var, start = [[GLOBAL_VAR]], size = {{8|0}} + + type = __tsan_locate_address(heap_var, name, 128, &start, &size); + fprintf(stderr, "type: %s, start = %p, size = %zu\n", type, start, size); + // CHECK: type: heap, start = [[HEAP_VAR]], size = 10 + + free(heap_var); + return 0; +} diff --git a/test/tsan/exceptions.cc b/test/tsan/exceptions.cc new file mode 100644 index 0000000000000..193e115f78020 --- /dev/null +++ b/test/tsan/exceptions.cc @@ -0,0 +1,185 @@ +// RUN: %clangxx_tsan -O0 %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s + +#include "test.h" +#include <setjmp.h> + +__attribute__((noinline)) void throws_int() { + throw 42; +} + +__attribute__((noinline)) void callee_throws() { + try { + throws_int(); + } catch (int) { // NOLINT + fprintf(stderr, "callee_throws caught exception\n"); + } +} + +__attribute__((noinline)) void throws_catches_rethrows() { + try { + throws_int(); + } catch (int) { // NOLINT + fprintf(stderr, "throws_catches_rethrows caught exception\n"); + throw; + } +} + +__attribute__((noinline)) void callee_rethrows() { + try { + throws_catches_rethrows(); + } catch (int) { // NOLINT + fprintf(stderr, "callee_rethrows caught exception\n"); + } +} + +__attribute__((noinline)) void throws_and_catches() { + try { + throws_int(); + } catch (int) { // NOLINT + fprintf(stderr, "throws_and_catches caught exception\n"); + } +} + +__attribute__((noinline)) void nested_try() { + try { + try { + throws_int(); + } catch (double) { // NOLINT + fprintf(stderr, "nested_try inner block caught exception\n"); + } + } catch (int) { // NOLINT + fprintf(stderr, "nested_try outer block caught exception\n"); + } +} + +__attribute__((noinline)) void nested_try2() { + try { + try { + throws_int(); + } catch (int) { // NOLINT + fprintf(stderr, "nested_try inner block caught exception\n"); + } + } catch (double) { // NOLINT + fprintf(stderr, "nested_try outer block caught exception\n"); + } +} + +class ClassWithDestructor { + public: + ClassWithDestructor() { + fprintf(stderr, "ClassWithDestructor\n"); + } + ~ClassWithDestructor() { + fprintf(stderr, "~ClassWithDestructor\n"); + } +}; + +__attribute__((noinline)) void local_object_then_throw() { + ClassWithDestructor obj; + throws_int(); +} + +__attribute__((noinline)) void cpp_object_with_destructor() { + try { + local_object_then_throw(); + } catch (int) { // NOLINT + fprintf(stderr, "cpp_object_with_destructor caught exception\n"); + } +} + +__attribute__((noinline)) void recursive_call(long n) { + if (n > 0) { + recursive_call(n - 1); + } else { + throws_int(); + } +} + +__attribute__((noinline)) void multiframe_unwind() { + try { + recursive_call(5); + } catch (int) { // NOLINT + fprintf(stderr, "multiframe_unwind caught exception\n"); + } +} + +__attribute__((noinline)) void longjmp_unwind() { + jmp_buf env; + int i = setjmp(env); + if (i != 0) { + fprintf(stderr, "longjmp_unwind jumped\n"); + return; + } + + try { + longjmp(env, 42); + } catch (int) { // NOLINT + fprintf(stderr, "longjmp_unwind caught exception\n"); + } +} + +__attribute__((noinline)) void recursive_call_longjmp(jmp_buf env, long n) { + if (n > 0) { + recursive_call_longjmp(env, n - 1); + } else { + longjmp(env, 42); + } +} + +__attribute__((noinline)) void longjmp_unwind_multiple_frames() { + jmp_buf env; + int i = setjmp(env); + if (i != 0) { + fprintf(stderr, "longjmp_unwind_multiple_frames jumped\n"); + return; + } + + try { + recursive_call_longjmp(env, 5); + } catch (int) { // NOLINT + fprintf(stderr, "longjmp_unwind_multiple_frames caught exception\n"); + } +} + +#define CHECK_SHADOW_STACK(val) \ + fprintf(stderr, (val == __tsan_testonly_shadow_stack_current_size() \ + ? "OK.\n" \ + : "Shadow stack leak!\n")); + +int main(int argc, const char * argv[]) { + fprintf(stderr, "Hello, World!\n"); + unsigned long shadow_stack_size = __tsan_testonly_shadow_stack_current_size(); + + throws_and_catches(); + CHECK_SHADOW_STACK(shadow_stack_size); + + callee_throws(); + CHECK_SHADOW_STACK(shadow_stack_size); + + callee_rethrows(); + CHECK_SHADOW_STACK(shadow_stack_size); + + nested_try(); + CHECK_SHADOW_STACK(shadow_stack_size); + + nested_try2(); + CHECK_SHADOW_STACK(shadow_stack_size); + + cpp_object_with_destructor(); + CHECK_SHADOW_STACK(shadow_stack_size); + + multiframe_unwind(); + CHECK_SHADOW_STACK(shadow_stack_size); + + longjmp_unwind(); + CHECK_SHADOW_STACK(shadow_stack_size); + + longjmp_unwind_multiple_frames(); + CHECK_SHADOW_STACK(shadow_stack_size); + + return 0; +} + +// CHECK: Hello, World! +// CHECK-NOT: Shadow stack leak diff --git a/test/tsan/fork_atexit.cc b/test/tsan/fork_atexit.cc index 15cf0a2485ca4..6e3a2f5c4ba78 100644 --- a/test/tsan/fork_atexit.cc +++ b/test/tsan/fork_atexit.cc @@ -7,7 +7,7 @@ #include <sys/wait.h> void foo() { - printf("CHILD ATEXIT\n"); + fprintf(stderr, "CHILD ATEXIT\n"); } void *worker(void *unused) { diff --git a/test/tsan/global_race.cc b/test/tsan/global_race.cc index a35299619e9d9..ec26b06f5c1ca 100644 --- a/test/tsan/global_race.cc +++ b/test/tsan/global_race.cc @@ -1,4 +1,14 @@ -// RUN: %clangxx_tsan -O1 %s -o %T/global_race.cc.exe && %deflake %run %T/global_race.cc.exe | FileCheck %s +// RUN: %clangxx_tsan -O1 %s -o %T/global_race.cc.exe && %deflake %run %T/global_race.cc.exe 2>&1 \ +// RUN: | FileCheck %s + +// Also check that memory access instrumentation can be configured by either +// driver or legacy flags: + +// RUN: %clangxx_tsan -O1 %s -o %T/global_race.cc.exe -fno-sanitize-thread-memory-access && not %deflake %run %T/global_race.cc.exe 2>&1 \ +// RUN: | FileCheck --allow-empty --check-prefix=CHECK-MEMORY-ACCESS-OFF %s +// RUN: %clangxx_tsan -O1 %s -o %T/global_race.cc.exe -mllvm -tsan-instrument-memory-accesses=0 && not %deflake %run %T/global_race.cc.exe 2>&1 \ +// RUN: | FileCheck --allow-empty --check-prefix=CHECK-MEMORY-ACCESS-OFF %s + #include "test.h" int GlobalData[10]; @@ -23,3 +33,4 @@ int main() { // CHECK: WARNING: ThreadSanitizer: data race // CHECK: Location is global 'GlobalData' {{(of size 40 )?}}at [[ADDR]] (global_race.cc.exe+0x{{[0-9,a-f]+}}) +// CHECK-MEMORY-ACCESS-OFF-NOT: WARNING: ThreadSanitizer: data race diff --git a/test/tsan/ignore_lib4.cc b/test/tsan/ignore_lib4.cc index 193df11d2b2a7..84d8b2768a94d 100644 --- a/test/tsan/ignore_lib4.cc +++ b/test/tsan/ignore_lib4.cc @@ -3,8 +3,6 @@ // RUN: echo "called_from_lib:libignore_lib4.so" > %t.supp // RUN: %env_tsan_opts=suppressions='%t.supp' %run %t 2>&1 | FileCheck %s -// Longjmp assembly has not been implemented for mips64 yet -// XFAIL: mips64 // powerpc64 big endian bots failed with "FileCheck error: '-' is empty" due // to a segmentation fault. // UNSUPPORTED: powerpc64-unknown-linux-gnu diff --git a/test/tsan/ignore_lib5.cc b/test/tsan/ignore_lib5.cc new file mode 100644 index 0000000000000..d7cd28500be91 --- /dev/null +++ b/test/tsan/ignore_lib5.cc @@ -0,0 +1,75 @@ +// RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib1.so +// RUN: %clangxx_tsan -O1 %s -o %t +// RUN: echo running w/o suppressions: +// RUN: %deflake %run %t | FileCheck %s --check-prefix=CHECK-NOSUPP +// RUN: echo running with suppressions: +// RUN: %env_tsan_opts=suppressions='%s.supp' %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-WITHSUPP + +// REQUIRES: stable-runtime + +// Previously the test episodically failed with: +// ThreadSanitizer: called_from_lib suppression '/libignore_lib1.so$' is +// matched against 2 libraries: '/libignore_lib1.so' and '/libignore_lib1.so' +// This was caused by non-atomicity of reading of /proc/self/maps. + +#ifndef LIB + +#include <dlfcn.h> +#include <sys/mman.h> +#include <stdlib.h> +#include <stdio.h> +#include <errno.h> +#include <libgen.h> +#include <string> +#include "test.h" + +#ifndef MAP_32BIT +# define MAP_32BIT 0 +#endif + +#ifdef __APPLE__ +# define TSAN_MAP_ANON MAP_ANON +#else +# define TSAN_MAP_ANON MAP_ANONYMOUS +#endif + +void *thr(void *arg) { + // This thread creates lots of separate mappings in /proc/self/maps before + // the ignored library. + for (int i = 0; i < 10000; i++) { + if (i == 5000) + barrier_wait(&barrier); + mmap(0, 4096, PROT_READ, TSAN_MAP_ANON | MAP_PRIVATE | MAP_32BIT, -1 , 0); + mmap(0, 4096, PROT_WRITE, TSAN_MAP_ANON | MAP_PRIVATE | MAP_32BIT, -1 , 0); + } + return 0; +} + +int main(int argc, char **argv) { + barrier_init(&barrier, 2); + pthread_t th; + pthread_create(&th, 0, thr, 0); + barrier_wait(&barrier); + std::string lib = std::string(dirname(argv[0])) + "/libignore_lib1.so"; + void *h = dlopen(lib.c_str(), RTLD_GLOBAL | RTLD_NOW); + if (h == 0) + exit(printf("failed to load the library (%d)\n", errno)); + void (*f)() = (void(*)())dlsym(h, "libfunc"); + if (f == 0) + exit(printf("failed to find the func (%d)\n", errno)); + pthread_join(th, 0); + f(); +} + +#else // #ifdef LIB + +#include "ignore_lib_lib.h" + +#endif // #ifdef LIB + +// CHECK-NOSUPP: WARNING: ThreadSanitizer: data race +// CHECK-NOSUPP: OK + +// CHECK-WITHSUPP-NOT: WARNING: ThreadSanitizer: data race +// CHECK-WITHSUPP: OK + diff --git a/test/tsan/ignore_lib5.cc.supp b/test/tsan/ignore_lib5.cc.supp new file mode 100644 index 0000000000000..9f4119ec0bc47 --- /dev/null +++ b/test/tsan/ignore_lib5.cc.supp @@ -0,0 +1,2 @@ +called_from_lib:/libignore_lib1.so$ + diff --git a/test/tsan/java.h b/test/tsan/java.h index 565a7a7fdabff..e9aa4ee2440b1 100644 --- a/test/tsan/java.h +++ b/test/tsan/java.h @@ -7,6 +7,7 @@ void __tsan_java_init(jptr heap_begin, jptr heap_size); int __tsan_java_fini(); void __tsan_java_alloc(jptr ptr, jptr size); void __tsan_java_free(jptr ptr, jptr size); +jptr __tsan_java_find(jptr *from_ptr, jptr to); void __tsan_java_move(jptr src, jptr dst, jptr size); void __tsan_java_finalize(); void __tsan_java_mutex_lock(jptr addr); diff --git a/test/tsan/libcxx/lit.local.cfg b/test/tsan/libcxx/lit.local.cfg index 202b44ee116d9..3ee705736e6fe 100644 --- a/test/tsan/libcxx/lit.local.cfg +++ b/test/tsan/libcxx/lit.local.cfg @@ -5,6 +5,8 @@ def getRoot(config): root = getRoot(config) -if not root.has_libcxx: +# Only run if we have an instrumented libcxx. On Darwin, run always (we have +# interceptors to support the system-provided libcxx). +if not root.has_libcxx and root.host_os != 'Darwin': config.unsupported = True diff --git a/test/tsan/lit.cfg b/test/tsan/lit.cfg index 1fc1eccd15ead..5d82cc9d4921c 100644 --- a/test/tsan/lit.cfg +++ b/test/tsan/lit.cfg @@ -38,13 +38,15 @@ if config.compiler_id == 'GNU': else: extra_cflags = [] +tsan_incdir = config.test_source_root + "/../" # Setup default compiler flags used with -fsanitize=thread option. clang_tsan_cflags = (["-fsanitize=thread", "-Wall"] + [config.target_cflags] + config.debug_info_flags + - extra_cflags) -clang_tsan_cxxflags = config.cxx_mode_flags + clang_tsan_cflags + extra_cflags + + ["-I%s" % tsan_incdir]) +clang_tsan_cxxflags = config.cxx_mode_flags + clang_tsan_cflags + ["-std=c++11"] + ["-I%s" % tsan_incdir] # Add additional flags if we're using instrumented libc++. # Instrumented libcxx currently not supported on Darwin. if config.has_libcxx and config.host_os != 'Darwin': @@ -54,8 +56,7 @@ if config.has_libcxx and config.host_os != 'Darwin': libcxx_incdir = os.path.join(libcxx_path, "include", "c++", "v1") libcxx_libdir = os.path.join(libcxx_path, "lib") libcxx_so = os.path.join(libcxx_libdir, "libc++.so") - clang_tsan_cxxflags += ["-std=c++11", - "-nostdinc++", + clang_tsan_cxxflags += ["-nostdinc++", "-I%s" % libcxx_incdir, libcxx_so, "-Wl,-rpath=%s" % libcxx_libdir] @@ -69,7 +70,7 @@ config.substitutions.append( ("%clangxx_tsan ", build_invocation(clang_tsan_cxxf # Define CHECK-%os to check for OS-dependent output. config.substitutions.append( ('CHECK-%os', ("CHECK-" + config.host_os))) -config.substitutions.append( ("%deflake ", os.path.join(os.path.dirname(__file__), "deflake.bash")) ) +config.substitutions.append( ("%deflake ", os.path.join(os.path.dirname(__file__), "deflake.bash") + " ")) # Default test suffixes. config.suffixes = ['.c', '.cc', '.cpp', '.m', '.mm'] diff --git a/test/tsan/longjmp.cc b/test/tsan/longjmp.cc index 61d285c11bf2c..a8abca6017586 100644 --- a/test/tsan/longjmp.cc +++ b/test/tsan/longjmp.cc @@ -1,8 +1,5 @@ // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -// Longjmp assembly has not been implemented for mips64 yet -// XFAIL: mips64 - #include <stdio.h> #include <stdlib.h> #include <setjmp.h> diff --git a/test/tsan/longjmp2.cc b/test/tsan/longjmp2.cc index 2b2775a8ca1e7..d396f3fec66e7 100644 --- a/test/tsan/longjmp2.cc +++ b/test/tsan/longjmp2.cc @@ -1,8 +1,5 @@ // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -// Longjmp assembly has not been implemented for mips64 yet -// XFAIL: mips64 - #include <stdio.h> #include <stdlib.h> #include <setjmp.h> diff --git a/test/tsan/longjmp3.cc b/test/tsan/longjmp3.cc index 197b91e1cdc35..842cf264c977c 100644 --- a/test/tsan/longjmp3.cc +++ b/test/tsan/longjmp3.cc @@ -1,8 +1,5 @@ // RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s -// Longjmp assembly has not been implemented for mips64 yet -// XFAIL: mips64 - #include <pthread.h> #include <stdio.h> #include <stdlib.h> diff --git a/test/tsan/longjmp4.cc b/test/tsan/longjmp4.cc index 3785a0f072614..4c2fbf0c4028f 100644 --- a/test/tsan/longjmp4.cc +++ b/test/tsan/longjmp4.cc @@ -1,8 +1,5 @@ // RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s -// Longjmp assembly has not been implemented for mips64 yet -// XFAIL: mips64 - #include <pthread.h> #include <stdio.h> #include <stdlib.h> diff --git a/test/tsan/map32bit.cc b/test/tsan/map32bit.cc index 0411f29a9504e..3b4f8990016e8 100644 --- a/test/tsan/map32bit.cc +++ b/test/tsan/map32bit.cc @@ -8,7 +8,7 @@ // https://github.com/google/sanitizers/issues/412 // MAP_32BIT flag for mmap is supported only for x86_64. -// XFAIL: mips64 +// XFAIL: mips // XFAIL: aarch64 // XFAIL: powerpc64 diff --git a/test/tsan/pie_test.cc b/test/tsan/pie_test.cc index 8635f9cd403fa..93d31daf5fd61 100644 --- a/test/tsan/pie_test.cc +++ b/test/tsan/pie_test.cc @@ -1,12 +1,6 @@ // Check if tsan work with PIE binaries. // RUN: %clang_tsan %s -pie -fpic -o %t && %run %t -// Some kernels might map PIE segments outside the current segment -// mapping defined for x86 [1]. -// [1] https://git.kernel.org/linus/d1fd836dcf00d2028c700c7e44d2c23404062c90 - -// UNSUPPORTED: x86 - int main(void) { return 0; } diff --git a/test/tsan/signal_block.cc b/test/tsan/signal_block.cc new file mode 100644 index 0000000000000..dfd4259c43c9b --- /dev/null +++ b/test/tsan/signal_block.cc @@ -0,0 +1,60 @@ +// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s + +// Test that a signal is not delivered when it is blocked. + +#include "test.h" +#include <semaphore.h> +#include <signal.h> +#include <errno.h> + +int stop; +sig_atomic_t signal_blocked; + +void handler(int signum) { + if (signal_blocked) { + fprintf(stderr, "signal arrived when blocked\n"); + exit(1); + } +} + +void *thread(void *arg) { + sigset_t myset; + sigemptyset(&myset); + sigaddset(&myset, SIGUSR1); + while (!__atomic_load_n(&stop, __ATOMIC_RELAXED)) { + usleep(1); + if (pthread_sigmask(SIG_BLOCK, &myset, 0)) { + fprintf(stderr, "pthread_sigmask failed %d\n", errno); + exit(1); + } + signal_blocked = 1; + usleep(1); + signal_blocked = 0; + if (pthread_sigmask(SIG_UNBLOCK, &myset, 0)) { + fprintf(stderr, "pthread_sigmask failed %d\n", errno); + exit(1); + } + } + return 0; +} + +int main(int argc, char** argv) { + struct sigaction act = {}; + act.sa_handler = &handler; + if (sigaction(SIGUSR1, &act, 0)) { + fprintf(stderr, "sigaction failed %d\n", errno); + return 1; + } + pthread_t th; + pthread_create(&th, 0, thread, 0); + for (int i = 0; i < 100000; i++) + pthread_kill(th, SIGUSR1); + __atomic_store_n(&stop, 1, __ATOMIC_RELAXED); + pthread_join(th, 0); + fprintf(stderr, "DONE\n"); + return 0; +} + +// CHECK-NOT: ThreadSanitizer CHECK +// CHECK-NOT: WARNING: ThreadSanitizer: +// CHECK: DONE diff --git a/test/tsan/signal_cond.cc b/test/tsan/signal_cond.cc index beb2e0266e508..6c20dd8f2e394 100644 --- a/test/tsan/signal_cond.cc +++ b/test/tsan/signal_cond.cc @@ -14,7 +14,7 @@ pthread_cond_t cond; void sig_handler(int sig) { (void)sig; - write(1, "SIGNAL\n", sizeof("SIGNAL\n") - 1); + write(2, "SIGNAL\n", sizeof("SIGNAL\n") - 1); barrier_wait(&barrier); } diff --git a/test/tsan/signal_longjmp.cc b/test/tsan/signal_longjmp.cc index 45e24626cbfab..f9fa4f54f507d 100644 --- a/test/tsan/signal_longjmp.cc +++ b/test/tsan/signal_longjmp.cc @@ -3,8 +3,6 @@ // Test case for longjumping out of signal handler: // https://github.com/google/sanitizers/issues/482 -// Longjmp assembly has not been implemented for mips64 yet -// XFAIL: mips64 // This test fails on powerpc64 BE (VMA=44), a segmentation fault // error happens at the second assignment // "((volatile int *volatile)mem)[1] = 1". diff --git a/test/tsan/simple_stack.c b/test/tsan/simple_stack.c index 6ef92fb46c683..71a3911b39bee 100644 --- a/test/tsan/simple_stack.c +++ b/test/tsan/simple_stack.c @@ -1,4 +1,3 @@ -// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s #include "test.h" int Global; @@ -47,20 +46,40 @@ int main() { return 0; } +// RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s + +// Also check that functions instrumentation can be configured by either driver +// or legacy flags: + +// RUN: %clangxx_tsan -O1 %s -o %t -fno-sanitize-thread-func-entry-exit && %deflake %run %t 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-FUNC-ENTRY-EXIT-OFF %s +// RUN: %clangxx_tsan -O1 %s -o %t -mllvm -tsan-instrument-func-entry-exit=0 && %deflake %run %t 2>&1 \ +// RUN: | FileCheck --check-prefix=CHECK-FUNC-ENTRY-EXIT-OFF %s + // CHECK: WARNING: ThreadSanitizer: data race // CHECK-NEXT: Write of size 4 at {{.*}} by thread T1: -// CHECK-NEXT: #0 foo1{{.*}} {{.*}}simple_stack.c:7{{(:10)?}} ({{.*}}) -// CHECK-NEXT: #1 bar1{{.*}} {{.*}}simple_stack.c:12{{(:3)?}} ({{.*}}) -// CHECK-NEXT: #2 Thread1{{.*}} {{.*}}simple_stack.c:26{{(:3)?}} ({{.*}}) +// CHECK-NEXT: #0 foo1{{.*}} {{.*}}simple_stack.c:6{{(:10)?}} ({{.*}}) +// CHECK-NEXT: #1 bar1{{.*}} {{.*}}simple_stack.c:11{{(:3)?}} ({{.*}}) +// CHECK-NEXT: #2 Thread1{{.*}} {{.*}}simple_stack.c:25{{(:3)?}} ({{.*}}) // CHECK: Previous read of size 4 at {{.*}} by thread T2: -// CHECK-NEXT: #0 foo2{{.*}} {{.*}}simple_stack.c:16{{(:20)?}} ({{.*}}) -// CHECK-NEXT: #1 bar2{{.*}} {{.*}}simple_stack.c:21{{(:3)?}} ({{.*}}) -// CHECK-NEXT: #2 Thread2{{.*}} {{.*}}simple_stack.c:31{{(:3)?}} ({{.*}}) +// CHECK-NEXT: #0 foo2{{.*}} {{.*}}simple_stack.c:15{{(:20)?}} ({{.*}}) +// CHECK-NEXT: #1 bar2{{.*}} {{.*}}simple_stack.c:20{{(:3)?}} ({{.*}}) +// CHECK-NEXT: #2 Thread2{{.*}} {{.*}}simple_stack.c:30{{(:3)?}} ({{.*}}) // CHECK: Thread T1 (tid={{.*}}, running) created by main thread at: // CHECK-NEXT: #0 pthread_create {{.*}} ({{.*}}) -// CHECK-NEXT: #1 StartThread{{.*}} {{.*}}simple_stack.c:37{{(:3)?}} ({{.*}}) -// CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack.c:43{{(:3)?}} ({{.*}}) +// CHECK-NEXT: #1 StartThread{{.*}} {{.*}}simple_stack.c:36{{(:3)?}} ({{.*}}) +// CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack.c:42{{(:3)?}} ({{.*}}) // CHECK: Thread T2 ({{.*}}) created by main thread at: // CHECK-NEXT: #0 pthread_create {{.*}} ({{.*}}) -// CHECK-NEXT: #1 StartThread{{.*}} {{.*}}simple_stack.c:37{{(:3)?}} ({{.*}}) -// CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack.c:44{{(:3)?}} ({{.*}}) +// CHECK-NEXT: #1 StartThread{{.*}} {{.*}}simple_stack.c:36{{(:3)?}} ({{.*}}) +// CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack.c:43{{(:3)?}} ({{.*}}) + +// CHECK-FUNC-ENTRY-EXIT-OFF: WARNING: ThreadSanitizer: data race +// CHECK-FUNC-ENTRY-EXIT-OFF-NEXT: Write of size 4 at {{.*}} by thread T1: +// CHECK-FUNC-ENTRY-EXIT-OFF-NEXT: #0 foo1{{.*}} {{.*}}simple_stack.c:6{{(:10)?}} ({{.*}}) +// CHECK-FUNC-ENTRY-EXIT-OFF: Previous read of size 4 at {{.*}} by thread T2: +// CHECK-FUNC-ENTRY-EXIT-OFF-NEXT: #0 foo2{{.*}} {{.*}}simple_stack.c:15{{(:20)?}} ({{.*}}) +// CHECK-FUNC-ENTRY-EXIT-OFF: Thread T1 (tid={{.*}}, running) created by main thread at: +// CHECK-FUNC-ENTRY-EXIT-OFF-NEXT: #0 pthread_create {{.*}} ({{.*}}) +// CHECK-FUNC-ENTRY-EXIT-OFF: Thread T2 ({{.*}}) created by main thread at: +// CHECK-FUNC-ENTRY-EXIT-OFF-NEXT: #0 pthread_create {{.*}} ({{.*}}) diff --git a/test/tsan/test.h b/test/tsan/test.h index e3affdc0837d0..6b981c09f53df 100644 --- a/test/tsan/test.h +++ b/test/tsan/test.h @@ -6,6 +6,7 @@ #include <stddef.h> #include <sched.h> #include <stdarg.h> +#include "sanitizer_common/print_address.h" #ifdef __APPLE__ #include <mach/mach_time.h> @@ -22,6 +23,7 @@ extern "C" { void __tsan_testonly_barrier_init(invisible_barrier_t *barrier, unsigned count); void __tsan_testonly_barrier_wait(invisible_barrier_t *barrier); +unsigned long __tsan_testonly_shadow_stack_current_size(); #ifdef __cplusplus } #endif @@ -37,23 +39,6 @@ static inline void barrier_wait(invisible_barrier_t *barrier) { // Default instance of the barrier, but a test can declare more manually. invisible_barrier_t barrier; -void print_address(const char *str, int n, ...) { - fprintf(stderr, "%s", str); - va_list ap; - va_start(ap, n); - while (n--) { - void *p = va_arg(ap, void *); -#if defined(__x86_64__) || defined(__aarch64__) || defined(__powerpc64__) - // On FreeBSD, the %p conversion specifier works as 0x%x and thus does not - // match to the format used in the diagnotic message. - fprintf(stderr, "0x%012lx ", (unsigned long) p); -#elif defined(__mips64) - fprintf(stderr, "0x%010lx ", (unsigned long) p); -#endif - } - fprintf(stderr, "\n"); -} - #ifdef __APPLE__ unsigned long long monotonic_clock_ns() { static mach_timebase_info_data_t timebase_info; diff --git a/test/ubsan/CMakeLists.txt b/test/ubsan/CMakeLists.txt index 7b14a70b76fa2..f4b73e87f56bb 100644 --- a/test/ubsan/CMakeLists.txt +++ b/test/ubsan/CMakeLists.txt @@ -22,13 +22,7 @@ endif() foreach(arch ${UBSAN_TEST_ARCH}) set(UBSAN_TEST_TARGET_ARCH ${arch}) - if(${arch} MATCHES "arm|aarch64") - # This is only true if we're cross-compiling. - set(UBSAN_TEST_TARGET_CFLAGS ${COMPILER_RT_TEST_COMPILER_CFLAGS}) - else() - get_target_flags_for_arch(${arch} UBSAN_TEST_TARGET_CFLAGS) - string(REPLACE ";" " " UBSAN_TEST_TARGET_CFLAGS "${UBSAN_TEST_TARGET_CFLAGS}") - endif() + get_test_cc_for_arch(${arch} UBSAN_TEST_TARGET_CC UBSAN_TEST_TARGET_CFLAGS) add_ubsan_testsuite("Standalone" ubsan ${arch}) if(COMPILER_RT_HAS_ASAN AND ";${ASAN_SUPPORTED_ARCH};" MATCHES ";${arch};") diff --git a/test/ubsan/TestCases/TypeCheck/null.cpp b/test/ubsan/TestCases/TypeCheck/null.cpp index b1cba83d17db2..636fab82fd935 100644 --- a/test/ubsan/TestCases/TypeCheck/null.cpp +++ b/test/ubsan/TestCases/TypeCheck/null.cpp @@ -1,20 +1,34 @@ -// RUN: %clangxx -fsanitize=null %s -O3 -o %t -// RUN: %run %t l 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD -// RUN: %expect_crash %run %t s 2>&1 | FileCheck %s --check-prefix=CHECK-STORE -// RUN: %run %t r 2>&1 | FileCheck %s --check-prefix=CHECK-REFERENCE -// RUN: %run %t m 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER -// RUN: %run %t f 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN +// RUN: %clangxx -fsanitize=null -fno-sanitize-recover=null %s -O3 -o %t +// RUN: not %run %t l 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD +// RUN: not %run %t s 2>&1 | FileCheck %s --check-prefix=CHECK-STORE +// RUN: not %run %t r 2>&1 | FileCheck %s --check-prefix=CHECK-REFERENCE +// RUN: not %run %t m 2>&1 | FileCheck %s --check-prefix=CHECK-MEMBER +// RUN: not %run %t f 2>&1 | FileCheck %s --check-prefix=CHECK-MEMFUN +// RUN: not %run %t t 2>&1 | FileCheck %s --check-prefix=CHECK-VCALL +// RUN: not %run %t u 2>&1 | FileCheck %s --check-prefix=CHECK-VCALL2 struct S { int f() { return 0; } int k; }; +struct T { + virtual int v() { return 1; } +}; + +struct U : T { + virtual int v() { return 2; } +}; + int main(int, char **argv) { int *p = 0; S *s = 0; + T *t = 0; + U *u = 0; (void)*p; // ok! + (void)*t; // ok! + (void)*u; // ok! switch (argv[1][0]) { case 'l': @@ -34,5 +48,11 @@ int main(int, char **argv) { case 'f': // CHECK-MEMFUN: null.cpp:[[@LINE+1]]:15: runtime error: member call on null pointer of type 'S' return s->f(); + case 't': + // CHECK-VCALL: null.cpp:[[@LINE+1]]:15: runtime error: member call on null pointer of type 'T' + return t->v(); + case 'u': + // CHECK-VCALL2: null.cpp:[[@LINE+1]]:15: runtime error: member call on null pointer of type 'U' + return u->v(); } } diff --git a/test/ubsan/TestCases/TypeCheck/vptr.cpp b/test/ubsan/TestCases/TypeCheck/vptr.cpp index 86b646da7561c..53a79c9fc7ee3 100644 --- a/test/ubsan/TestCases/TypeCheck/vptr.cpp +++ b/test/ubsan/TestCases/TypeCheck/vptr.cpp @@ -1,4 +1,4 @@ -// RUN: %clangxx -frtti -fsanitize=vptr -fno-sanitize-recover=vptr -g %s -O3 -o %t +// RUN: %clangxx -frtti -fsanitize=vptr -fno-sanitize-recover=vptr -g %s -O3 -o %t -mllvm -enable-tail-merge=false // RUN: %run %t rT && %run %t mT && %run %t fT && %run %t cT // RUN: %run %t rU && %run %t mU && %run %t fU && %run %t cU // RUN: %run %t rS && %run %t rV && %run %t oV @@ -50,6 +50,8 @@ struct V : S {}; // Make p global so that lsan does not complain. T *p = 0; +volatile void *sink1, *sink2; + int access_p(T *p, char type); int main(int argc, char **argv) { @@ -74,6 +76,11 @@ int main(int argc, char **argv) { char Buffer[sizeof(U)] = {}; char TStorage[sizeof(T)]; + // Allocate two dummy objects so that the real object + // is not on the boundary of mapped memory. Otherwise ubsan + // will not be able to describe the vptr in detail. + sink1 = new T; + sink2 = new U; switch (argv[1][1]) { case '0': p = reinterpret_cast<T*>(Buffer); diff --git a/test/xray/CMakeLists.txt b/test/xray/CMakeLists.txt new file mode 100644 index 0000000000000..50f6926bbe1e5 --- /dev/null +++ b/test/xray/CMakeLists.txt @@ -0,0 +1,48 @@ +set(XRAY_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + +set(XRAY_TESTSUITES) +set(XRAY_FDR_TESTSUITES) + +set(XRAY_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) +set(XRAY_FDR_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) + +if(NOT COMPILER_RT_STANDALONE_BUILD AND COMPILER_RT_BUILD_XRAY AND + COMPILER_RT_HAS_XRAY) + list(APPEND XRAY_TEST_DEPS xray) + list(APPEND XRAY_FDR_TEST_DEPS xray-fdr) +endif() + +set(XRAY_TEST_ARCH ${XRAY_SUPPORTED_ARCH}) +if (COMPILER_RT_BUILD_XRAY AND COMPILER_RT_HAS_XRAY) + foreach(arch ${XRAY_TEST_ARCH}) + set(XRAY_TEST_TARGET_ARCH ${arch}) + string(TOLOWER "-${arch}-${OS_NAME}" XRAY_TEST_CONFIG_SUFFIX) + get_test_cc_for_arch(${arch} XRAY_TEST_TARGET_CC XRAY_TEST_TARGET_CFLAGS) + string(TOUPPER ${arch} ARCH_UPPER_CASE) + set(CONFIG_NAME ${ARCH_UPPER_CASE}${OS_NAME}Config) + + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg) + list(APPEND XRAY_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}) + endforeach() + + # Add unit tests. + if(COMPILER_RT_INCLUDE_TESTS) + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg) + list(APPEND XRAY_TEST_DEPS XRayUnitTests) + list(APPEND XRAY_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit) + endif() +endif() + +add_lit_testsuite(check-xray "Running the XRay tests" + ${XRAY_TESTSUITES} + DEPENDS ${XRAY_TEST_DEPS}) +set_target_properties(check-xray PROPERTIES FOLDER "Compiler-RT Misc") + +add_lit_testsuite(check-xray-fdr "Running the XRay flight data recorder tests" + ${XRAY_FDR_TESTSUITES} + DEPENDS ${XRAY_FDR_TEST_DEPS}) +set_target_properties(check-xray-fdr PROPERTIES FOLDER "Compiler-RT Misc") diff --git a/test/xray/TestCases/Linux/fixedsize-logging.cc b/test/xray/TestCases/Linux/fixedsize-logging.cc new file mode 100644 index 0000000000000..90e766876c546 --- /dev/null +++ b/test/xray/TestCases/Linux/fixedsize-logging.cc @@ -0,0 +1,20 @@ +// Check to make sure that we have a log file with a fixed-size. + +// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS="verbosity=1 xray_logfile_base=fixedsize-logging-" %run %t 2>&1 | FileCheck %s +// +// After all that, clean up the output xray log. +// +// RUN: rm fixedsize-logging-* + +#include <cstdio> + +[[clang::xray_always_instrument]] void foo() { + printf("foo() is always instrumented!"); +} + +int main() { + // CHECK: XRay: Log file in 'fixedsize-logging-{{.*}}' + foo(); + // CHECK: foo() is always instrumented! +} diff --git a/test/xray/TestCases/Linux/optional-inmemory-log.cc b/test/xray/TestCases/Linux/optional-inmemory-log.cc new file mode 100644 index 0000000000000..ef2c43f3be776 --- /dev/null +++ b/test/xray/TestCases/Linux/optional-inmemory-log.cc @@ -0,0 +1,21 @@ +// Make sure that we don't get the inmemory logging implementation enabled when +// we turn it off via options. + +// RUN: %clangxx_xray -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS="verbosity=1 xray_naive_log=false xray_logfile_base=optional-inmemory-log.xray-" %run %t 2>&1 | FileCheck %s +// +// Make sure we clean out the logs in case there was a bug. +// +// RUN: rm -f optional-inmemory-log.xray-* + +#include <cstdio> + +[[clang::xray_always_instrument]] void foo() { + printf("foo() is always instrumented!"); +} + +int main() { + // CHECK-NOT: XRay: Log file in 'optional-inmemory-log.xray-{{.*}}' + foo(); + // CHECK: foo() is always instrumented! +} diff --git a/test/xray/TestCases/Linux/patching-unpatching.cc b/test/xray/TestCases/Linux/patching-unpatching.cc new file mode 100644 index 0000000000000..e684e427f068f --- /dev/null +++ b/test/xray/TestCases/Linux/patching-unpatching.cc @@ -0,0 +1,48 @@ +// Check that we can patch and un-patch on demand, and that logging gets invoked +// appropriately. +// +// RUN: %clangxx_xray -fxray-instrument -std=c++11 %s -o %t +// RUN: XRAY_OPTIONS="patch_premain=false" %run %t 2>&1 | FileCheck %s +// REQUIRES: stable-runtime + +#include "xray/xray_interface.h" + +#include <cstdio> + +bool called = false; + +void test_handler(int32_t fid, XRayEntryType type) { + printf("called: %d, type=%d\n", fid, static_cast<int32_t>(type)); + called = true; +} + +[[clang::xray_always_instrument]] void always_instrument() { + printf("always instrumented called\n"); +} + +int main() { + __xray_set_handler(test_handler); + always_instrument(); + // CHECK: always instrumented called + auto status = __xray_patch(); + printf("patching status: %d\n", static_cast<int32_t>(status)); + // CHECK-NEXT: patching status: 1 + always_instrument(); + // CHECK-NEXT: called: {{.*}}, type=0 + // CHECK-NEXT: always instrumented called + // CHECK-NEXT: called: {{.*}}, type=1 + status = __xray_unpatch(); + printf("patching status: %d\n", static_cast<int32_t>(status)); + // CHECK-NEXT: patching status: 1 + always_instrument(); + // CHECK-NEXT: always instrumented called + status = __xray_patch(); + printf("patching status: %d\n", static_cast<int32_t>(status)); + // CHECK-NEXT: patching status: 1 + __xray_remove_handler(); + always_instrument(); + // CHECK-NEXT: always instrumented called + status = __xray_unpatch(); + printf("patching status: %d\n", static_cast<int32_t>(status)); + // CHECK-NEXT: patching status: 1 +} diff --git a/test/xray/Unit/lit.site.cfg.in b/test/xray/Unit/lit.site.cfg.in new file mode 100644 index 0000000000000..1ebc7b9ec5f3f --- /dev/null +++ b/test/xray/Unit/lit.site.cfg.in @@ -0,0 +1,12 @@ +@LIT_SITE_CFG_IN_HEADER@ + +import os + +# Load common config for all compiler-rt unit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/unittests/lit.common.unit.configured") + +# Setup config name. +config.name = 'XRay-Unit' + +config.test_exec_root = "@COMPILER_RT_BINARY_DIR@/lib/xray/tests" +config.test_source_root = config.test_exec_root diff --git a/test/xray/lit.cfg b/test/xray/lit.cfg new file mode 100644 index 0000000000000..5d030e101452f --- /dev/null +++ b/test/xray/lit.cfg @@ -0,0 +1,39 @@ +# -*- Python -*- + +import os + +# Setup config name. +config.name = 'XRay' + config.name_suffix + +# Setup source root. +config.test_source_root = os.path.dirname(__file__) + +# Setup default compiler flags use with -fxray-instrument option. +clang_xray_cflags = (['-fxray-instrument', config.target_cflags]) +clang_xray_cxxflags = config.cxx_mode_flags + clang_xray_cflags + + +def build_invocation(compile_flags): + return ' ' + ' '.join([config.clang] + compile_flags) + ' ' + +# Setup substitutions. +config.substitutions.append( + ('%clang ', build_invocation([config.target_cflags]))) +config.substitutions.append( + ('%clangxx ', + build_invocation(config.cxx_mode_flags + [config.target_cflags]))) +config.substitutions.append( + ('%clang_xray ', build_invocation(clang_xray_cflags))) +config.substitutions.append( + ('%clangxx_xray', build_invocation(clang_xray_cxxflags))) + +# Default test suffixes. +config.suffixes = ['.c', '.cc', '.cpp'] + +if config.host_os not in ['Linux'] or config.host_arch.find('64') == -1: + config.unsupported = True + +# Allow tests to use REQUIRES=stable-runtime. For use when you cannot use XFAIL +# e.g. because the test sometimes passes, sometimes fails. +if config.target_arch != 'aarch64': + config.available_features.add('stable-runtime') diff --git a/test/xray/lit.site.cfg.in b/test/xray/lit.site.cfg.in new file mode 100644 index 0000000000000..ee0ffcad4d9c8 --- /dev/null +++ b/test/xray/lit.site.cfg.in @@ -0,0 +1,13 @@ +@LIT_SITE_CFG_IN_HEADER@ + +# Tool-specific config options. +config.name_suffix = "@XRAY_TEST_CONFIG_SUFFIX@" +config.xray_lit_source_dir = "@XRAY_LIT_SOURCE_DIR@" +config.target_cflags = "@XRAY_TEST_TARGET_CFLAGS@" +config.target_arch = "@XRAY_TEST_TARGET_ARCH@" + +# Load common config for all compiler-rt lit tests +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/test/lit.common.configured") + +# Load tool-specific config that would do the real work. +lit_config.load_config(config, "@XRAY_LIT_SOURCE_DIR@/lit.cfg") |