diff options
Diffstat (limited to 'test')
200 files changed, 2371 insertions, 719 deletions
diff --git a/test/asan/CMakeLists.txt b/test/asan/CMakeLists.txt index 14f7f506da51..0c46ef7e6e31 100644 --- a/test/asan/CMakeLists.txt +++ b/test/asan/CMakeLists.txt @@ -1,140 +1,58 @@ set(ASAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set(ASAN_TESTSUITES) +set(ASAN_DYNAMIC_TESTSUITES) macro(get_bits_for_arch arch bits) - if (${arch} STREQUAL "arm" OR - ${arch} STREQUAL "i386" OR - ${arch} STREQUAL "i686" OR - ${arch} STREQUAL "mips") + if (${arch} MATCHES "i386|i686|arm|mips|mipsel") set(bits 32) - elseif (${arch} STREQUAL "aarch64" OR - ${arch} STREQUAL "x86_64" OR - ${arch} STREQUAL "mips64") + elseif (${arch} MATCHES "x86_64|powerpc64|powerpc64le|aarch64|mips64|mips64el") set(bits 64) else() message(FATAL_ERROR "Unknown target architecture: ${arch}") endif() endmacro() -# TODO: merge with non-ANDROID case -if(ANDROID) - foreach(arch ${ASAN_SUPPORTED_ARCH}) - set(ASAN_TEST_TARGET_CC ${CMAKE_CXX_COMPILER}) - set(ASAN_TEST_TARGET_CFLAGS ${COMPILER_RT_TEST_COMPILER_CFLAGS}) - set(ASAN_TEST_CONFIG_SUFFIX "-${arch}-android") - get_bits_for_arch(${arch} ASAN_TEST_BITS) - set(ASAN_TEST_DYNAMIC True) - set(ASAN_TEST_TARGET_ARCH "${arch}-android") - string(TOUPPER ${arch} ARCH_UPPER_CASE) - set(CONFIG ${ARCH_UPPER_CASE}AndroidConfig) - configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in - ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG}/lit.site.cfg - ) - list(APPEND ASAN_TESTSUITES - ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG}) - endforeach() - -else() # Not Android - - if(CAN_TARGET_arm) - # 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}) - set(ASAN_TEST_CONFIG_SUFFIX "-arm-linux") - set(ASAN_TEST_BITS "32") - set(ASAN_TEST_DYNAMIC False) - configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in - ${CMAKE_CURRENT_BINARY_DIR}/ARMLinuxConfig/lit.site.cfg - ) - list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/ARMLinuxConfig) +foreach(arch ${ASAN_SUPPORTED_ARCH}) + if(ANDROID) + set(ASAN_TEST_TARGET_ARCH ${arch}-android) + else() + set(ASAN_TEST_TARGET_ARCH ${arch}) endif() - - if(CAN_TARGET_aarch64) + 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}) - set(ASAN_TEST_CONFIG_SUFFIX "-aarch64-linux") - set(ASAN_TEST_BITS "64") - set(ASAN_TEST_DYNAMIC False) - configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in - ${CMAKE_CURRENT_BINARY_DIR}/AArch64LinuxConfig/lit.site.cfg - ) - list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/AArch64LinuxConfig) + else() + get_target_flags_for_arch(${arch} ASAN_TEST_TARGET_CFLAGS) endif() - - if(CAN_TARGET_x86_64 OR CAN_TARGET_powerpc64 OR CAN_TARGET_mips64 OR CAN_TARGET_mips64el) - set(ASAN_TEST_CONFIG_SUFFIX "64") - set(ASAN_TEST_BITS "64") - set(ASAN_TEST_TARGET_CFLAGS ${TARGET_64_BIT_CFLAGS}) + if(ANDROID) + set(ASAN_TEST_DYNAMIC True) + else() set(ASAN_TEST_DYNAMIC False) - configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in - ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig/lit.site.cfg - ) - list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig) - if(COMPILER_RT_BUILD_SHARED_ASAN) - set(ASAN_TEST_CONFIG_SUFFIX "64-Dynamic") - set(ASAN_TEST_DYNAMIC True) - configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in - ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig-dynamic/lit.site.cfg) - list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/64bitConfig-dynamic) - endif() - endif() - - if(CAN_TARGET_i386) - set(ASAN_TEST_CONFIG_SUFFIX "32") - set(ASAN_TEST_BITS "32") - set(ASAN_TEST_TARGET_CFLAGS ${TARGET_32_BIT_CFLAGS}) - set(ASAN_TEST_DYNAMIC False) - set(ASAN_TEST_TARGET_ARCH "i386") - configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in - ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig/lit.site.cfg - ) - list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig) - if(COMPILER_RT_BUILD_SHARED_ASAN) - set(ASAN_TEST_CONFIG_SUFFIX "32-Dynamic") - set(ASAN_TEST_DYNAMIC True) - configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in - ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig-dynamic/lit.site.cfg) - list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig-dynamic) - endif() endif() + 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 ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}) - if(CAN_TARGET_mips OR CAN_TARGET_mipsel) - set(ASAN_TEST_CONFIG_SUFFIX "32") - set(ASAN_TEST_BITS "32") - set(ASAN_TEST_TARGET_CFLAGS ${TARGET_32_BIT_CFLAGS}) - set(ASAN_TEST_DYNAMIC False) + if(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME) + string(TOLOWER "-${arch}-${OS_NAME}-dynamic" ASAN_TEST_CONFIG_SUFFIX) + set(ASAN_TEST_DYNAMIC True) + set(CONFIG_NAME ${ARCH_UPPER_CASE}${OS_NAME}DynamicConfig) configure_lit_site_cfg( ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in - ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig/lit.site.cfg - ) - list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig) - if(COMPILER_RT_BUILD_SHARED_ASAN) - set(ASAN_TEST_CONFIG_SUFFIX "32-Dynamic") - set(ASAN_TEST_DYNAMIC True) - configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in - ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig-dynamic/lit.site.cfg) - list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/32bitConfig-dynamic) - endif() + ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}/lit.site.cfg) + list(APPEND ASAN_DYNAMIC_TESTSUITES + ${CMAKE_CURRENT_BINARY_DIR}/${CONFIG_NAME}) endif() -endif() # Not Android - -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) -endif() +endforeach() set(ASAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) if(COMPILER_RT_STANDALONE_BUILD) @@ -144,13 +62,49 @@ if(COMPILER_RT_STANDALONE_BUILD) else() list(APPEND ASAN_TEST_DEPS asan) endif() +set(ASAN_DYNAMIC_TEST_DEPS ${ASAN_TEST_DEPS}) -# FIXME: support unit test in the android test runner -if(COMPILER_RT_INCLUDE_TESTS AND NOT ANDROID) - list(APPEND ASAN_TEST_DEPS AsanUnitTests) - list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit) +# Add unit tests. +if(COMPILER_RT_INCLUDE_TESTS) + set(ASAN_TEST_DYNAMIC False) + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg) + if(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME) + set(ASAN_TEST_DYNAMIC True) + configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/Unit/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/Unit/dynamic/lit.site.cfg) + endif() + # FIXME: support unit test in the android test runner + if (NOT ANDROID) + list(APPEND ASAN_TEST_DEPS AsanUnitTests) + list(APPEND ASAN_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit) + if(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME) + list(APPEND ASAN_DYNAMIC_TEST_DEPS AsanDynamicUnitTests) + list(APPEND ASAN_DYNAMIC_TESTSUITES ${CMAKE_CURRENT_BINARY_DIR}/Unit/dynamic) + endif() + endif() endif() + add_lit_testsuite(check-asan "Running the AddressSanitizer tests" ${ASAN_TESTSUITES} DEPENDS ${ASAN_TEST_DEPS}) set_target_properties(check-asan PROPERTIES FOLDER "ASan tests") + +if(COMPILER_RT_ASAN_HAS_STATIC_RUNTIME) + # Add check-dynamic-asan target. It is a part of check-all only on Windows, + # where we want to always test both dynamic and static runtime. + if(NOT OS_NAME MATCHES "Windows") + set(EXCLUDE_FROM_ALL TRUE) + endif() + add_lit_testsuite(check-asan-dynamic + "Running the AddressSanitizer tests with dynamic runtime" + ${ASAN_DYNAMIC_TESTSUITES} + DEPENDS ${ASAN_DYNAMIC_TEST_DEPS}) + set_target_properties(check-asan-dynamic + PROPERTIES FOLDER "ASan dynamic tests") + if(NOT OS_NAME MATCHES "Windows") + set(EXCLUDE_FROM_ALL FALSE) + endif() +endif() diff --git a/test/asan/TestCases/Android/coverage-android.cc b/test/asan/TestCases/Android/coverage-android.cc index 071a2e3e1faa..e243059fbbec 100644 --- a/test/asan/TestCases/Android/coverage-android.cc +++ b/test/asan/TestCases/Android/coverage-android.cc @@ -1,8 +1,8 @@ // Test for direct coverage writing with dlopen. -// Test normal exit. -// RUN: %clangxx_asan -mllvm -asan-coverage=1 -DSHARED %s -shared -o %T/libcoverage_android_test_1.so -fPIC -// RUN: %clangxx_asan -mllvm -asan-coverage=1 -DSO_DIR=\"%device\" %s -o %t +// Test normal exit, coverage level 1. +// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %T/libcoverage_android_test_1.so -fPIC +// RUN: %clangxx_asan -fsanitize-coverage=1 -DSO_DIR=\"%device\" %s -o %t // RUN: adb shell rm -rf %device/coverage-android // RUN: rm -rf %T/coverage-android @@ -14,12 +14,12 @@ // RUN: ls; pwd // RUN: cd %T/coverage-android/direct // RUN: %sancov rawunpack *.sancov.raw -// RUN: %sancov print *.sancov |& FileCheck %s +// RUN: %sancov print *.sancov |& FileCheck --check-prefix=CHECK1 %s -// Test sudden death. -// RUN: %clangxx_asan -mllvm -asan-coverage=1 -DSHARED -DKILL %s -shared -o %T/libcoverage_android_test_1.so -fPIC -// RUN: %clangxx_asan -mllvm -asan-coverage=1 -DSO_DIR=\"%device\" %s -o %t +// Test sudden death, coverage level 1. +// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED -DKILL %s -shared -o %T/libcoverage_android_test_1.so -fPIC +// RUN: %clangxx_asan -fsanitize-coverage=1 -DSO_DIR=\"%device\" %s -o %t // RUN: adb shell rm -rf %device/coverage-android-kill // RUN: rm -rf %T/coverage-android-kill @@ -31,7 +31,75 @@ // RUN: ls; pwd // RUN: cd %T/coverage-android-kill/direct // RUN: %sancov rawunpack *.sancov.raw -// RUN: %sancov print *.sancov |& FileCheck %s +// RUN: %sancov print *.sancov |& FileCheck --check-prefix=CHECK1 %s + + +// Test normal exit, coverage level 2. +// RUN: %clangxx_asan -fsanitize-coverage=2 -DSHARED %s -shared -o %T/libcoverage_android_test_1.so -fPIC +// RUN: %clangxx_asan -fsanitize-coverage=2 -DSO_DIR=\"%device\" %s -o %t + +// RUN: adb shell rm -rf %device/coverage-android +// RUN: rm -rf %T/coverage-android + +// RUN: adb shell mkdir -p %device/coverage-android/direct +// RUN: mkdir -p %T/coverage-android/direct +// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=1:coverage_dir=%device/coverage-android/direct:verbosity=1 %run %t +// RUN: adb pull %device/coverage-android/direct %T/coverage-android/direct +// RUN: ls; pwd +// RUN: cd %T/coverage-android/direct +// RUN: %sancov rawunpack *.sancov.raw +// RUN: %sancov print *.sancov |& FileCheck --check-prefix=CHECK2 %s + + +// Test sudden death, coverage level 2. +// RUN: %clangxx_asan -fsanitize-coverage=2 -DSHARED -DKILL %s -shared -o %T/libcoverage_android_test_1.so -fPIC +// RUN: %clangxx_asan -fsanitize-coverage=2 -DSO_DIR=\"%device\" %s -o %t + +// RUN: adb shell rm -rf %device/coverage-android-kill +// RUN: rm -rf %T/coverage-android-kill + +// RUN: adb shell mkdir -p %device/coverage-android-kill/direct +// RUN: mkdir -p %T/coverage-android-kill/direct +// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=1:coverage_dir=%device/coverage-android-kill/direct:verbosity=1 not %run %t +// RUN: adb pull %device/coverage-android-kill/direct %T/coverage-android-kill/direct +// RUN: ls; pwd +// RUN: cd %T/coverage-android-kill/direct +// RUN: %sancov rawunpack *.sancov.raw +// RUN: %sancov print *.sancov |& FileCheck --check-prefix=CHECK2 %s + + +// Test normal exit, coverage level 3. +// RUN: %clangxx_asan -fsanitize-coverage=3 -DSHARED %s -shared -o %T/libcoverage_android_test_1.so -fPIC +// RUN: %clangxx_asan -fsanitize-coverage=3 -DSO_DIR=\"%device\" %s -o %t + +// RUN: adb shell rm -rf %device/coverage-android +// RUN: rm -rf %T/coverage-android + +// RUN: adb shell mkdir -p %device/coverage-android/direct +// RUN: mkdir -p %T/coverage-android/direct +// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=1:coverage_dir=%device/coverage-android/direct:verbosity=1 %run %t +// RUN: adb pull %device/coverage-android/direct %T/coverage-android/direct +// RUN: ls; pwd +// RUN: cd %T/coverage-android/direct +// RUN: %sancov rawunpack *.sancov.raw +// RUN: %sancov print *.sancov |& FileCheck --check-prefix=CHECK3 %s + + +// Test sudden death, coverage level 3. +// RUN: %clangxx_asan -fsanitize-coverage=3 -DSHARED -DKILL %s -shared -o %T/libcoverage_android_test_1.so -fPIC +// RUN: %clangxx_asan -fsanitize-coverage=3 -DSO_DIR=\"%device\" %s -o %t + +// RUN: adb shell rm -rf %device/coverage-android-kill +// RUN: rm -rf %T/coverage-android-kill + +// RUN: adb shell mkdir -p %device/coverage-android-kill/direct +// RUN: mkdir -p %T/coverage-android-kill/direct +// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=1:coverage_dir=%device/coverage-android-kill/direct:verbosity=1 not %run %t +// RUN: adb pull %device/coverage-android-kill/direct %T/coverage-android-kill/direct +// RUN: ls; pwd +// RUN: cd %T/coverage-android-kill/direct +// RUN: %sancov rawunpack *.sancov.raw +// RUN: %sancov print *.sancov |& FileCheck --check-prefix=CHECK3 %s #include <assert.h> #include <dlfcn.h> @@ -51,11 +119,17 @@ void bar() { } #else +volatile int sink; + int main(int argc, char **argv) { fprintf(stderr, "PID: %d\n", getpid()); void *handle1 = dlopen(SO_DIR "/libcoverage_android_test_1.so", RTLD_LAZY); assert(handle1); + + if (argc == 0) + sink = 0; + void (*bar1)() = (void (*)())dlsym(handle1, "bar"); assert(bar1); bar1(); @@ -64,4 +138,6 @@ int main(int argc, char **argv) { } #endif -// CHECK: 2 PCs total +// CHECK1: 2 PCs total +// CHECK2: 7 PCs total +// CHECK3: 8 PCs total diff --git a/test/asan/TestCases/Android/lit.local.cfg b/test/asan/TestCases/Android/lit.local.cfg index 42513dd3aa61..63a6e52826a3 100644 --- a/test/asan/TestCases/Android/lit.local.cfg +++ b/test/asan/TestCases/Android/lit.local.cfg @@ -5,7 +5,7 @@ def getRoot(config): root = getRoot(config) -if root.android != "TRUE": +if root.android != "1": config.unsupported = True config.substitutions.append( ("%device", "/data/local/tmp/Output") ) diff --git a/test/asan/TestCases/Darwin/address-range-limit.mm b/test/asan/TestCases/Darwin/address-range-limit.mm new file mode 100644 index 000000000000..a6906766d7ee --- /dev/null +++ b/test/asan/TestCases/Darwin/address-range-limit.mm @@ -0,0 +1,38 @@ +// Regression test for https://code.google.com/p/address-sanitizer/issues/detail?id=368. + +// RUN: %clang_asan %s -Wno-deprecated-declarations -flat_namespace -bundle -undefined suppress -o %t.bundle +// RUN: %clang_asan %s -Wno-deprecated-declarations -o %t -framework Foundation && not %run %t 2>&1 | FileCheck %s + +#import <Foundation/Foundation.h> +#import <mach-o/dyld.h> + +#include <string> + +int main(int argc, char *argv[]) { + for (int i = 0; i < 10; i++) { + NSObjectFileImage im; + + std::string path = std::string(argv[0]) + ".bundle"; + NSObjectFileImageReturnCode rc = + NSCreateObjectFileImageFromFile(path.c_str(), &im); + if (rc != NSObjectFileImageSuccess) { + fprintf(stderr, "Could not load bundle.\n"); + exit(-1); + } + + NSModule handle = NSLinkModule(im, "a.bundle", 0); + if (handle == 0) { + fprintf(stderr, "Could not load bundle.\n"); + exit(-1); + } + printf("h: %p\n", handle); + } + + char *ptr = (char *)malloc(10); + ptr[10] = 'x'; // BOOM +} + +// CHECK: AddressSanitizer: heap-buffer-overflow +// CHECK: WRITE of size 1 +// CHECK: {{#0 .* in main}} +// CHECK: is located 0 bytes to the right of 10-byte region diff --git a/test/asan/TestCases/Darwin/crashlog-stacktraces.c b/test/asan/TestCases/Darwin/crashlog-stacktraces.c new file mode 100644 index 000000000000..e9af5396e1c3 --- /dev/null +++ b/test/asan/TestCases/Darwin/crashlog-stacktraces.c @@ -0,0 +1,43 @@ +// RUN: %clang_asan -O0 %s -o %t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <execinfo.h> +#include <sanitizer/common_interface_defs.h> +#include <stdio.h> +#include <stdlib.h> + +void death_function() { + fprintf(stderr, "DEATH CALLBACK\n"); + + void* callstack[128]; + int i, frames = backtrace(callstack, 128); + char** strs = backtrace_symbols(callstack, frames); + for (i = 0; i < frames; ++i) { + fprintf(stderr, "%s\n", strs[i]); + } + free(strs); + + fprintf(stderr, "END OF BACKTRACE\n"); +} + +int fault_function() { + char *x = (char*)malloc(10 * sizeof(char)); + free(x); + return x[5]; // BOOM +} + +int main() { + __sanitizer_set_death_callback(death_function); + fault_function(); + return 0; +} + +// CHECK: {{.*ERROR: AddressSanitizer: heap-use-after-free on address}} +// CHECK: {{READ of size 1 at 0x.* thread T0}} +// CHECK: {{ #0 0x.* in fault_function}} + +// CHECK: DEATH CALLBACK +// CHECK: death_function +// CHECK: fault_function +// CHECK: main +// CHECK: END OF BACKTRACE diff --git a/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cc b/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cc index b1bb4567f900..0bd4170a353c 100644 --- a/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cc +++ b/test/asan/TestCases/Darwin/dyld_insert_libraries_reexec.cc @@ -20,13 +20,11 @@ int main() { return 0; } -// CHECK-NOINSERT: Parsed ASAN_OPTIONS: verbosity=1 // CHECK-NOINSERT: exec()-ing the program with // CHECK-NOINSERT: DYLD_INSERT_LIBRARIES // CHECK-NOINSERT: to enable ASan wrappers. // CHECK-NOINSERT: Passed -// CHECK: Parsed ASAN_OPTIONS: verbosity=1 // CHECK-NOT: exec()-ing the program with // CHECK-NOT: DYLD_INSERT_LIBRARIES // CHECK-NOT: to enable ASan wrappers. diff --git a/test/asan/TestCases/Darwin/dyld_insert_libraries_remove.cc b/test/asan/TestCases/Darwin/dyld_insert_libraries_remove.cc new file mode 100644 index 000000000000..a3af8c156ef2 --- /dev/null +++ b/test/asan/TestCases/Darwin/dyld_insert_libraries_remove.cc @@ -0,0 +1,39 @@ +// Check that when launching with DYLD_INSERT_LIBRARIES, we properly remove +// the ASan dylib from the environment variable (both when using an absolute +// or relative path) and also that the other dylibs are left untouched. + +// RUN: mkdir -p %T/dyld_insert_libraries_remove +// RUN: cp `%clang_asan %s -fsanitize=address -### 2>&1 \ +// RUN: | grep "libclang_rt.asan_osx_dynamic.dylib" \ +// RUN: | sed -e 's/.*"\(.*libclang_rt.asan_osx_dynamic.dylib\)".*/\1/'` \ +// RUN: %T/dyld_insert_libraries_remove/libclang_rt.asan_osx_dynamic.dylib + +// RUN: %clangxx_asan %s -o %T/dyld_insert_libraries_remove/a.out +// RUN: %clangxx -DSHARED_LIB %s \ +// RUN: -dynamiclib -o %T/dyld_insert_libraries_remove/dummy-so.dylib + +// RUN: ( cd %T/dyld_insert_libraries_remove && \ +// RUN: DYLD_INSERT_LIBRARIES=@executable_path/libclang_rt.asan_osx_dynamic.dylib:dummy-so.dylib \ +// RUN: %run ./a.out 2>&1 ) | FileCheck %s || exit 1 + +// RUN: ( cd %T/dyld_insert_libraries_remove && \ +// RUN: DYLD_INSERT_LIBRARIES=libclang_rt.asan_osx_dynamic.dylib:dummy-so.dylib \ +// RUN: %run ./a.out 2>&1 ) | FileCheck %s || exit 1 + +// RUN: ( cd %T/dyld_insert_libraries_remove && \ +// RUN: DYLD_INSERT_LIBRARIES=%T/dyld_insert_libraries_remove/libclang_rt.asan_osx_dynamic.dylib:dummy-so.dylib \ +// RUN: %run ./a.out 2>&1 ) | FileCheck %s || exit 1 + +#if !defined(SHARED_LIB) +#include <stdio.h> +#include <stdlib.h> + +int main() { + const char kEnvName[] = "DYLD_INSERT_LIBRARIES"; + printf("%s=%s\n", kEnvName, getenv(kEnvName)); + // CHECK: {{DYLD_INSERT_LIBRARIES=dummy-so.dylib}} + return 0; +} +#else // SHARED_LIB +void foo() {} +#endif // SHARED_LIB diff --git a/test/asan/TestCases/Darwin/interception-in-shared-lib-test.cc b/test/asan/TestCases/Darwin/interception-in-shared-lib-test.cc index e472a9dc6972..028683d2fc41 100644 --- a/test/asan/TestCases/Darwin/interception-in-shared-lib-test.cc +++ b/test/asan/TestCases/Darwin/interception-in-shared-lib-test.cc @@ -3,11 +3,11 @@ // ../Linux/interception-in-shared-lib-test.cc. // RUN: %clangxx_asan -O0 %s -DSHARED_LIB \ -// RUN: -shared -o %T/libinterception-in-shared-lib-test.so \ -// RUN: -fPIC +// RUN: -shared -o %t-so.so \ +// RUN: -fPIC -install_name @rpath/interception-in-shared-lib-test.cc.tmp-so.so // TODO(glider): figure out how to set rpath in a more portable way and unite // this test with ../Linux/interception-in-shared-lib-test.cc. -// RUN: %clangxx_asan -O0 %s -o %t -Wl,-rpath,@executable-path -L%T -linterception-in-shared-lib-test && \ +// RUN: %clangxx_asan -O0 %s -o %t -Wl,-rpath,@executable_path %t-so.so && \ // RUN: not %run %t 2>&1 | FileCheck %s #include <stdio.h> diff --git a/test/asan/TestCases/Darwin/interface_symbols_darwin.c b/test/asan/TestCases/Darwin/interface_symbols_darwin.c index 8680d678cf91..a75044d491fb 100644 --- a/test/asan/TestCases/Darwin/interface_symbols_darwin.c +++ b/test/asan/TestCases/Darwin/interface_symbols_darwin.c @@ -31,6 +31,15 @@ // RUN: echo __asan_report_store_n >> %t.interface // RUN: echo __asan_get_current_fake_stack >> %t.interface // RUN: echo __asan_addr_is_in_fake_stack >> %t.interface +// RUN: echo __asan_mz_calloc >> %t.interface +// RUN: echo __asan_mz_destroy >> %t.interface +// RUN: echo __asan_mz_free >> %t.interface +// RUN: echo __asan_mz_malloc >> %t.interface +// RUN: echo __asan_mz_memalign >> %t.interface +// RUN: echo __asan_mz_realloc >> %t.interface +// RUN: echo __asan_mz_size >> %t.interface +// RUN: echo __asan_mz_valloc >> %t.interface + // RUN: for i in `jot - 0 10`; do echo __asan_stack_malloc_$i >> %t.interface; done // RUN: for i in `jot - 0 10`; do echo __asan_stack_free_$i >> %t.interface; done diff --git a/test/asan/TestCases/Darwin/linked-only.cc b/test/asan/TestCases/Darwin/linked-only.cc new file mode 100644 index 000000000000..bb19ea8535e2 --- /dev/null +++ b/test/asan/TestCases/Darwin/linked-only.cc @@ -0,0 +1,33 @@ +// Main executable is uninstrumented, but linked to ASan runtime. +// Regression test for https://code.google.com/p/address-sanitizer/issues/detail?id=357. + +// RUN: %clangxx -g -O0 %s -c -o %t.o +// RUN: %clangxx_asan -g -O0 %t.o -o %t +// RUN: %run %t 2>&1 | FileCheck %s + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "sanitizer/asan_interface.h" + +void test_shadow(char *p, size_t size) { + fprintf(stderr, "p = %p\n", p); + char *q = (char *)__asan_region_is_poisoned(p, size); + fprintf(stderr, "=%zd=\n", q ? q - p : -1); +} + +int main(int argc, char *argv[]) { + char *p = (char *)malloc(10000); + test_shadow(p, 100); + free(p); + // CHECK: =-1= + + test_shadow((char *)&main, 1); + // CHECK: =-1= + + test_shadow((char *)&p, 1); + // CHECK: =-1= + + return 0; +} diff --git a/test/asan/TestCases/Darwin/mixing-global-constructors.cc b/test/asan/TestCases/Darwin/mixing-global-constructors.cc new file mode 100644 index 000000000000..0b0f15cc78d5 --- /dev/null +++ b/test/asan/TestCases/Darwin/mixing-global-constructors.cc @@ -0,0 +1,42 @@ +// A global constructor from a non-instrumented part calls a function +// in an instrumented part. +// Regression test for https://code.google.com/p/address-sanitizer/issues/detail?id=363. + +// RUN: %clangxx -DINSTRUMENTED_PART=0 -c %s -o %t-uninst.o +// RUN: %clangxx_asan -DINSTRUMENTED_PART=1 -c %s -o %t-inst.o +// RUN: %clangxx_asan %t-uninst.o %t-inst.o -o %t + +// RUN: %run %t 2>&1 | FileCheck %s + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +void func(char *ptr); + +#if INSTRUMENTED_PART == 1 + +void func(char *ptr) { + *ptr = 'X'; +} + +#else // INSTRUMENTED_PART == 1 + +struct C1 { + C1() { + printf("Hello "); + char buffer[10] = "world"; + func(buffer); + printf("%s\n", buffer); + } +}; + +C1 *obj = new C1(); + +int main(int argc, const char *argv[]) { + return 0; +} + +#endif // INSTRUMENTED_PART == 1 + +// CHECK: Hello Xorld diff --git a/test/asan/TestCases/Darwin/suppressions-darwin.cc b/test/asan/TestCases/Darwin/suppressions-darwin.cc index 9a8f56d5dc50..fb37296d404f 100644 --- a/test/asan/TestCases/Darwin/suppressions-darwin.cc +++ b/test/asan/TestCases/Darwin/suppressions-darwin.cc @@ -4,17 +4,17 @@ // Check that suppressing the interceptor by name works. // RUN: echo "interceptor_name:memmove" > %t.supp -// RUN: ASAN_OPTIONS=suppressions=%t.supp %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s +// RUN: ASAN_OPTIONS="suppressions='%t.supp'" %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s // Check that suppressing by interceptor name works even without the symbolizer -// RUN: ASAN_OPTIONS=suppressions=%t.supp:symbolize=false %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s +// RUN: ASAN_OPTIONS="suppressions='%t.supp':symbolize=false" %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s // Check that suppressing all reports from a library works. // RUN: echo "interceptor_via_lib:CoreFoundation" > %t.supp -// RUN: ASAN_OPTIONS=suppressions=%t.supp %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s +// RUN: ASAN_OPTIONS="suppressions='%t.supp'" %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s // Check that suppressing library works even without the symbolizer. -// RUN: ASAN_OPTIONS=suppressions=%t.supp:symbolize=false %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s +// RUN: ASAN_OPTIONS="suppressions='%t.supp':symbolize=false" %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s #include <CoreFoundation/CoreFoundation.h> diff --git a/test/asan/TestCases/Linux/asan_preload_test-2.cc b/test/asan/TestCases/Linux/asan_preload_test-2.cc index 00b32e15d17d..0f22264cf1fb 100644 --- a/test/asan/TestCases/Linux/asan_preload_test-2.cc +++ b/test/asan/TestCases/Linux/asan_preload_test-2.cc @@ -10,11 +10,11 @@ #include <stdlib.h> -extern "C" void *memset(void *p, int val, size_t n); +extern "C" ssize_t write(int fd, const void *buf, size_t count); void do_access(void *p) { // CHECK: AddressSanitizer: heap-buffer-overflow - memset(p, 0, 2); + write(1, p, 2); } int main(int argc, char **argv) { diff --git a/test/asan/TestCases/Linux/coverage-caller-callee-total-count.cc b/test/asan/TestCases/Linux/coverage-caller-callee-total-count.cc index 0201425106f9..7598f6bc7bc5 100644 --- a/test/asan/TestCases/Linux/coverage-caller-callee-total-count.cc +++ b/test/asan/TestCases/Linux/coverage-caller-callee-total-count.cc @@ -6,7 +6,7 @@ // // REQUIRES: asan-64-bits -#include <sanitizer/common_interface_defs.h> +#include <sanitizer/coverage_interface.h> #include <stdio.h> #include <assert.h> int P = 0; diff --git a/test/asan/TestCases/Linux/coverage-direct-activation.cc b/test/asan/TestCases/Linux/coverage-direct-activation.cc new file mode 100644 index 000000000000..9b2a0d8897c8 --- /dev/null +++ b/test/asan/TestCases/Linux/coverage-direct-activation.cc @@ -0,0 +1,59 @@ +// Test for direct coverage writing enabled at activation time. + +// RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %T/libcoverage_direct_activation_test_1.so -fPIC +// RUN: %clangxx -c -DSO_DIR=\"%T\" %s -o %t.o +// RUN: %clangxx_asan -fsanitize-coverage=1 %t.o %libdl -o %t + +// RUN: rm -rf %T/coverage-direct-activation + +// RUN: mkdir -p %T/coverage-direct-activation/normal +// RUN: ASAN_OPTIONS=coverage=1,coverage_direct=0,coverage_dir=%T/coverage-direct-activation/normal:verbosity=1 %run %t +// RUN: %sancov print %T/coverage-direct-activation/normal/*.sancov >%T/coverage-direct-activation/normal/out.txt + +// RUN: mkdir -p %T/coverage-direct-activation/direct +// RUN: ASAN_OPTIONS=start_deactivated=1,coverage_direct=1,verbosity=1 \ +// RUN: ASAN_ACTIVATION_OPTIONS=coverage=1,coverage_dir=%T/coverage-direct-activation/direct %run %t +// RUN: cd %T/coverage-direct-activation/direct +// RUN: %sancov rawunpack *.sancov.raw +// RUN: %sancov print *.sancov >out.txt +// RUN: cd ../.. + +// Test start_deactivated=1,coverage=1 in ASAN_OPTIONS. + +// RUN: diff -u coverage-direct-activation/normal/out.txt coverage-direct-activation/direct/out.txt + +// RUN: mkdir -p %T/coverage-direct-activation/direct2 +// RUN: ASAN_OPTIONS=start_deactivated=1,coverage=1,coverage_direct=1,verbosity=1 \ +// RUN: ASAN_ACTIVATION_OPTIONS=coverage_dir=%T/coverage-direct-activation/direct2 %run %t +// RUN: cd %T/coverage-direct-activation/direct2 +// RUN: %sancov rawunpack *.sancov.raw +// RUN: %sancov print *.sancov >out.txt +// RUN: cd ../.. + +// RUN: diff -u coverage-direct-activation/normal/out.txt coverage-direct-activation/direct2/out.txt + +// XFAIL: android + +#include <assert.h> +#include <dlfcn.h> +#include <stdio.h> +#include <unistd.h> + +#ifdef SHARED +extern "C" { +void bar() { printf("bar\n"); } +} +#else + +int main(int argc, char **argv) { + fprintf(stderr, "PID: %d\n", getpid()); + void *handle1 = + dlopen(SO_DIR "/libcoverage_direct_activation_test_1.so", RTLD_LAZY); + assert(handle1); + void (*bar1)() = (void (*)())dlsym(handle1, "bar"); + assert(bar1); + bar1(); + + return 0; +} +#endif diff --git a/test/asan/TestCases/Linux/coverage-direct-large.cc b/test/asan/TestCases/Linux/coverage-direct-large.cc index 78aa68621ad1..25c950e0bb30 100644 --- a/test/asan/TestCases/Linux/coverage-direct-large.cc +++ b/test/asan/TestCases/Linux/coverage-direct-large.cc @@ -1,7 +1,9 @@ // Test for direct coverage writing with lots of data. // Current implementation maps output file in chunks of 64K. This test overflows // 1 chunk. -// RUN: %clangxx_asan -fsanitize-coverage=1 -O0 %s -o %t + +// RUN: %clangxx_asan -fsanitize-coverage=1 -O0 -DSHARED %s -shared -o %T/libcoverage_direct_large_test_1.so -fPIC +// RUN: %clangxx_asan -fsanitize-coverage=1 -O0 -DSO_DIR=\"%T\" %s %libdl -o %t // RUN: rm -rf %T/coverage-direct-large @@ -34,12 +36,30 @@ F3(Q, x##0) F3(Q, x##1) F3(Q, x##2) F3(Q, x##3) F3(Q, x##4) F3(Q, x##5) \ F3(Q, x##6) F3(Q, x##7) F3(Q, x##8) F3(Q, x##9) -#define DECL(x) __attribute__((noinline)) void x() {} +#define DECL(x) __attribute__((noinline)) static void x() {} #define CALL(x) x(); F4(DECL, f) +#ifdef SHARED +extern "C" void so_entry() { + F4(CALL, f) +} +#else + +#include <assert.h> +#include <dlfcn.h> int main(void) { F4(CALL, f) + + void *handle1 = + dlopen(SO_DIR "/libcoverage_direct_large_test_1.so", RTLD_LAZY); + assert(handle1); + void (*so_entry)() = (void (*)())dlsym(handle1, "so_entry"); + assert(so_entry); + so_entry(); + return 0; } + +#endif // SHARED diff --git a/test/asan/TestCases/Linux/coverage-direct.cc b/test/asan/TestCases/Linux/coverage-direct.cc index 2cc1aed0a0fa..45222fa1a03e 100644 --- a/test/asan/TestCases/Linux/coverage-direct.cc +++ b/test/asan/TestCases/Linux/coverage-direct.cc @@ -1,6 +1,26 @@ -// Test for direct coverage writing with dlopen. +// Test for direct coverage writing with dlopen at coverage level 1 to 3. + // RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %T/libcoverage_direct_test_1.so -fPIC -// RUN: %clangxx_asan -fsanitize-coverage=1 -DSO_DIR=\"%T\" %s -o %t +// RUN: %clangxx_asan -fsanitize-coverage=1 -DSO_DIR=\"%T\" %s %libdl -o %t + +// RUN: rm -rf %T/coverage-direct + +// RUN: mkdir -p %T/coverage-direct/normal +// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=0:coverage_dir=%T/coverage-direct/normal:verbosity=1 %run %t +// RUN: %sancov print %T/coverage-direct/normal/*.sancov >%T/coverage-direct/normal/out.txt + +// RUN: mkdir -p %T/coverage-direct/direct +// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=1:coverage_dir=%T/coverage-direct/direct:verbosity=1 %run %t +// RUN: cd %T/coverage-direct/direct +// RUN: %sancov rawunpack *.sancov.raw +// RUN: %sancov print *.sancov >out.txt +// RUN: cd ../.. + +// RUN: diff -u coverage-direct/normal/out.txt coverage-direct/direct/out.txt + + +// RUN: %clangxx_asan -fsanitize-coverage=2 -DSHARED %s -shared -o %T/libcoverage_direct_test_1.so -fPIC +// RUN: %clangxx_asan -fsanitize-coverage=2 -DSO_DIR=\"%T\" %s %libdl -o %t // RUN: rm -rf %T/coverage-direct @@ -16,7 +36,26 @@ // RUN: cd ../.. // RUN: diff -u coverage-direct/normal/out.txt coverage-direct/direct/out.txt -// + + +// RUN: %clangxx_asan -fsanitize-coverage=3 -DSHARED %s -shared -o %T/libcoverage_direct_test_1.so -fPIC +// RUN: %clangxx_asan -fsanitize-coverage=3 -DSO_DIR=\"%T\" %s %libdl -o %t + +// RUN: rm -rf %T/coverage-direct + +// RUN: mkdir -p %T/coverage-direct/normal +// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=0:coverage_dir=%T/coverage-direct/normal:verbosity=1 %run %t +// RUN: %sancov print %T/coverage-direct/normal/*.sancov >%T/coverage-direct/normal/out.txt + +// RUN: mkdir -p %T/coverage-direct/direct +// RUN: ASAN_OPTIONS=coverage=1:coverage_direct=1:coverage_dir=%T/coverage-direct/direct:verbosity=1 %run %t +// RUN: cd %T/coverage-direct/direct +// RUN: %sancov rawunpack *.sancov.raw +// RUN: %sancov print *.sancov >out.txt +// RUN: cd ../.. + +// RUN: diff -u coverage-direct/normal/out.txt coverage-direct/direct/out.txt + // XFAIL: android #include <assert.h> diff --git a/test/asan/TestCases/Linux/coverage-disabled.cc b/test/asan/TestCases/Linux/coverage-disabled.cc index a75b26dc02e9..cb33542a5701 100644 --- a/test/asan/TestCases/Linux/coverage-disabled.cc +++ b/test/asan/TestCases/Linux/coverage-disabled.cc @@ -12,6 +12,8 @@ // RUN: ASAN_OPTIONS=coverage_direct=1:coverage_dir=%T/coverage-disabled/direct:verbosity=1 %run %t // RUN: cd %T/coverage-disabled/direct // RUN: not %sancov rawunpack *.sancov +// +// XFAIL: android int main(int argc, char **argv) { return 0; diff --git a/test/asan/TestCases/Linux/coverage-levels.cc b/test/asan/TestCases/Linux/coverage-levels.cc index 748ef1f08db5..cc196c5a9e18 100644 --- a/test/asan/TestCases/Linux/coverage-levels.cc +++ b/test/asan/TestCases/Linux/coverage-levels.cc @@ -1,11 +1,15 @@ // Test various levels of coverage // // RUN: %clangxx_asan -O1 -fsanitize-coverage=1 %s -o %t -// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 +// RUN: ASAN_OPTIONS=coverage=1:coverage_bitset=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 // RUN: %clangxx_asan -O1 -fsanitize-coverage=2 %s -o %t -// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 +// RUN: ASAN_OPTIONS=coverage=1:coverage_bitset=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 // RUN: %clangxx_asan -O1 -fsanitize-coverage=3 %s -o %t -// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3 +// RUN: ASAN_OPTIONS=coverage=1:coverage_bitset=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3 + +// RUN: ASAN_OPTIONS=coverage=1:coverage_bitset=0:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3_NOBITSET +// RUN: ASAN_OPTIONS=coverage=1:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3_NOBITSET +// RUN: ASAN_OPTIONS=coverage=1:coverage_pcs=0:verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3_NOPCS // // REQUIRES: asan-64-bits @@ -15,6 +19,11 @@ int main(int argc, char **argv) { sink = 0; } +// CHECK1: CovDump: bitset of 1 bits written, 1 bits are set // CHECK1: 1 PCs written +// CHECK2: CovDump: bitset of 3 bits written, 2 bits are set // CHECK2: 2 PCs written +// CHECK3: CovDump: bitset of 4 bits written, 3 bits are set // CHECK3: 3 PCs written +// CHECK3_NOBITSET-NOT: bitset of +// CHECK3_NOPCS-NOT: PCs written diff --git a/test/asan/TestCases/Linux/coverage-maybe-open-file.cc b/test/asan/TestCases/Linux/coverage-maybe-open-file.cc index 4664cef7f5af..4580de411799 100644 --- a/test/asan/TestCases/Linux/coverage-maybe-open-file.cc +++ b/test/asan/TestCases/Linux/coverage-maybe-open-file.cc @@ -13,7 +13,7 @@ #include <string.h> #include <unistd.h> -#include <sanitizer/common_interface_defs.h> +#include <sanitizer/coverage_interface.h> int main(int argc, char **argv) { int fd = __sanitizer_maybe_open_cov_file("test"); diff --git a/test/asan/TestCases/Linux/coverage-module-unloaded.cc b/test/asan/TestCases/Linux/coverage-module-unloaded.cc index 449841e78189..f8d9c57f81be 100644 --- a/test/asan/TestCases/Linux/coverage-module-unloaded.cc +++ b/test/asan/TestCases/Linux/coverage-module-unloaded.cc @@ -2,7 +2,7 @@ // modules. // RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %T/libcoverage_module_unloaded_test_1.so -fPIC // RUN: %clangxx_asan -fsanitize-coverage=1 -DSHARED %s -shared -o %T/libcoverage_module_unloaded_test_2.so -fPIC -// RUN: %clangxx_asan -fsanitize-coverage=1 -DSO_DIR=\"%T\" %s -o %t +// RUN: %clangxx_asan -fsanitize-coverage=1 -DSO_DIR=\"%T\" %s %libdl -o %t // RUN: export ASAN_OPTIONS=coverage=1:verbosity=1 // RUN: mkdir -p %T/coverage-module-unloaded && cd %T/coverage-module-unloaded // RUN: %run %t 2>&1 | FileCheck %s diff --git a/test/asan/TestCases/Linux/coverage-reset.cc b/test/asan/TestCases/Linux/coverage-reset.cc new file mode 100644 index 000000000000..d3d35e21b5a7 --- /dev/null +++ b/test/asan/TestCases/Linux/coverage-reset.cc @@ -0,0 +1,52 @@ +// Test __sanitizer_reset_coverage(). + +// RUN: %clangxx_asan -fsanitize-coverage=1 %s -o %t +// RUN: ASAN_OPTIONS=coverage=1 %run %t + +#include <sanitizer/coverage_interface.h> +#include <stdio.h> +#include <assert.h> +static volatile int sink; +__attribute__((noinline)) void bar() { sink = 2; } +__attribute__((noinline)) void foo() { sink = 1; } + +#define GET_AND_PRINT_COVERAGE() \ + bitset = 0; \ + for (size_t i = 0; i < n_guards; i++) \ + if (guards[i]) bitset |= 1U << i; \ + printf("line %d: bitset %zd total: %zd\n", __LINE__, bitset, \ + __sanitizer_get_total_unique_coverage()); + +#define IS_POWER_OF_TWO(a) ((a & ((a) - 1)) == 0) + +int main() { + size_t *guards = 0; + size_t bitset; + size_t n_guards = __sanitizer_get_coverage_guards(&guards); + + GET_AND_PRINT_COVERAGE(); + size_t main_bit = bitset; + assert(IS_POWER_OF_TWO(main_bit)); + + foo(); + GET_AND_PRINT_COVERAGE(); + size_t foo_bit = bitset & ~main_bit; + assert(IS_POWER_OF_TWO(foo_bit)); + + bar(); + GET_AND_PRINT_COVERAGE(); + size_t bar_bit = bitset & ~(main_bit | foo_bit); + assert(IS_POWER_OF_TWO(bar_bit)); + + __sanitizer_reset_coverage(); + GET_AND_PRINT_COVERAGE(); + assert(bitset == 0); + + foo(); + GET_AND_PRINT_COVERAGE(); + assert(bitset == foo_bit); + + bar(); + GET_AND_PRINT_COVERAGE(); + assert(bitset == (foo_bit | bar_bit)); +} diff --git a/test/asan/TestCases/Linux/coverage-sandboxing.cc b/test/asan/TestCases/Linux/coverage-sandboxing.cc index 56f9c40f4cc0..1a72c6bb9a6e 100644 --- a/test/asan/TestCases/Linux/coverage-sandboxing.cc +++ b/test/asan/TestCases/Linux/coverage-sandboxing.cc @@ -27,7 +27,7 @@ #include <string.h> #include <unistd.h> -#include <sanitizer/common_interface_defs.h> +#include <sanitizer/coverage_interface.h> #define bb0(n) \ case n: \ diff --git a/test/asan/TestCases/Linux/coverage-tracing.cc b/test/asan/TestCases/Linux/coverage-tracing.cc index 89ab0d283add..49dbb5e9528b 100644 --- a/test/asan/TestCases/Linux/coverage-tracing.cc +++ b/test/asan/TestCases/Linux/coverage-tracing.cc @@ -2,21 +2,49 @@ // // RUN: %clangxx_asan -O1 -fsanitize-coverage=1 -mllvm -sanitizer-coverage-experimental-tracing %s -o %t // RUN: rm -rf %T/coverage-tracing -// RUN: mkdir -p %T/coverage-tracing -// RUN: ASAN_OPTIONS=coverage=1:coverage_dir=%T/coverage-tracing:verbosity=1 %run %t 1 2 3 4 2>&1 | FileCheck %s +// RUN: mkdir %T/coverage-tracing +// RUN: cd %T/coverage-tracing +// RUN: A=x; ASAN_OPTIONS=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK1; mv trace-points.*.sancov $A.points +// RUN: A=f; ASAN_OPTIONS=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK2; mv trace-points.*.sancov $A.points +// RUN: A=b; ASAN_OPTIONS=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK2; mv trace-points.*.sancov $A.points +// RUN: A=bf; ASAN_OPTIONS=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK3; mv trace-points.*.sancov $A.points +// RUN: A=fb; ASAN_OPTIONS=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK3; mv trace-points.*.sancov $A.points +// RUN: A=ffb; ASAN_OPTIONS=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK4; mv trace-points.*.sancov $A.points +// RUN: A=fff; ASAN_OPTIONS=coverage=1:verbosity=1 %run %t $A 1 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK4; mv trace-points.*.sancov $A.points +// RUN: A=bbf; ASAN_OPTIONS=coverage=1:verbosity=1 %run %t $A 100 2>&1 | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK301; mv trace-points.*.sancov $A.points +// RUN: diff f.points fff.points +// RUN: diff bf.points fb.points +// RUN: diff bf.points ffb.points +// RUN: diff bf.points bbf.points +// RUN: not diff x.points f.points +// RUN: not diff x.points b.points +// RUN: not diff x.points bf.points +// RUN: not diff f.points b.points +// RUN: not diff f.points bf.points +// RUN: not diff b.points bf.points // RUN: rm -rf %T/coverage-tracing // // REQUIRES: asan-64-bits +#include <stdlib.h> volatile int sink; +__attribute__((noinline)) void foo() { sink++; } +__attribute__((noinline)) void bar() { sink++; } + int main(int argc, char **argv) { - volatile int i = 0; - do { - sink = 0; - i++; - } while (i < argc); - return 0; + if (argc != 3) return 0; + int n = strtol(argv[2], 0, 10); + while (n-- > 0) { + for (int i = 0; argv[1][i]; i++) { + if (argv[1][i] == 'f') foo(); + else if (argv[1][i] == 'b') bar(); + } + } } -// CHECK: CovDump: Trace: {{[3-9]}} PCs written -// CHECK: CovDump: Trace: {{[6-9]}} Events written +// CHECK: CovDump: Trace: 3 PCs written +// CHECK1: CovDump: Trace: 1 Events written +// CHECK2: CovDump: Trace: 2 Events written +// CHECK3: CovDump: Trace: 3 Events written +// CHECK4: CovDump: Trace: 4 Events written +// CHECK301: CovDump: Trace: 301 Events written diff --git a/test/asan/TestCases/Linux/coverage.cc b/test/asan/TestCases/Linux/coverage.cc index f6eb0ae9285b..06fe1a295eaf 100644 --- a/test/asan/TestCases/Linux/coverage.cc +++ b/test/asan/TestCases/Linux/coverage.cc @@ -13,7 +13,7 @@ // https://code.google.com/p/address-sanitizer/issues/detail?id=263 // XFAIL: android -#include "sanitizer/common_interface_defs.h" +#include <sanitizer/coverage_interface.h> #include <assert.h> #include <stdio.h> #include <string.h> diff --git a/test/asan/TestCases/Linux/malloc-in-qsort.cc b/test/asan/TestCases/Linux/malloc-in-qsort.cc index 545bc7e42a17..80af409d66a9 100644 --- a/test/asan/TestCases/Linux/malloc-in-qsort.cc +++ b/test/asan/TestCases/Linux/malloc-in-qsort.cc @@ -39,15 +39,12 @@ int main() { return GlobalPtr[10]; } -// Fast unwind: can not unwind through qsort. -// FIXME: this test does not properly work with slow unwind yet. - +// Fast unwind may not unwind through qsort. // CHECK-FAST: ERROR: AddressSanitizer: heap-buffer-overflow // CHECK-FAST: is located 0 bytes to the right // CHECK-FAST: #0{{.*}}operator new // CHECK-FAST-NEXT: #1{{.*}}QsortCallback -// CHECK-FAST-NOT: MyQsort -// + // CHECK-SLOW: ERROR: AddressSanitizer: heap-buffer-overflow // CHECK-SLOW: is located 0 bytes to the right // CHECK-SLOW: #0{{.*}}operator new diff --git a/test/asan/TestCases/Linux/nohugepage_test.cc b/test/asan/TestCases/Linux/nohugepage_test.cc new file mode 100644 index 000000000000..b549f3bc2119 --- /dev/null +++ b/test/asan/TestCases/Linux/nohugepage_test.cc @@ -0,0 +1,91 @@ +// Regression test for +// https://code.google.com/p/chromium/issues/detail?id=446692 +// where asan consumed too much RAM due to transparent hugetables. +// +// RUN: %clangxx_asan -g %s -o %t +// RUN: ASAN_OPTIONS=no_huge_pages_for_shadow=1 %run %t 2>&1 | FileCheck %s +// RUN: %run %t 2>&1 | FileCheck %s +// +// Would be great to run the test with no_huge_pages_for_shadow=0, but +// the result will depend on the OS version and settings... +// +// REQUIRES: x86_64-supported-target, asan-64-bits +// +// WARNING: this test is very subtle and may nto work on some systems. +// If this is the case we'll need to futher improve it or disable it. +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <sanitizer/asan_interface.h> + +char FileContents[1 << 14]; + +void FileToString(const char *path) { + FileContents[0] = 0; + int fd = open(path, 0); + if (fd < 0) return; + ssize_t res = read(fd, FileContents, sizeof(FileContents) - 1); + if (res >= 0) + FileContents[res] = 0; +} + +long ReadShadowRss() { + const char *path = "/proc/self/smaps"; + FileToString(path); + char *s = strstr(FileContents, "2008fff7000-10007fff8000"); + if (!s) return 0; + + s = strstr(s, "Rss:"); + if (!s) return 0; + s = s + 4; + return atol(s); +} + +const int kAllocSize = 1 << 28; // 256Mb +const int kTwoMb = 1 << 21; +const int kAsanShadowGranularity = 8; + +char *x; + +__attribute__((no_sanitize_address)) void TouchNoAsan(size_t i) { x[i] = 0; } + +int main() { + long rss[5]; + rss[0] = ReadShadowRss(); + // use mmap directly to avoid asan touching the shadow. + x = (char *)mmap(0, kAllocSize, PROT_READ | PROT_WRITE, + MAP_PRIVATE | MAP_ANON, 0, 0); + fprintf(stderr, "X: %p-%p\n", x, x + kAllocSize); + rss[1] = ReadShadowRss(); + + // Touch the allocated region, but not the shadow. + for (size_t i = 0; i < kAllocSize; i += kTwoMb * kAsanShadowGranularity) + TouchNoAsan(i); + rss[2] = ReadShadowRss(); + + // Touch the shadow just a bit, in 2Mb*Granularity steps. + for (size_t i = 0; i < kAllocSize; i += kTwoMb * kAsanShadowGranularity) + __asan_poison_memory_region(x + i, kAsanShadowGranularity); + rss[3] = ReadShadowRss(); + + // Touch all the shadow. + __asan_poison_memory_region(x, kAllocSize); + rss[4] = ReadShadowRss(); + + // Print the differences. + for (int i = 0; i < 4; i++) { + assert(rss[i] > 0); + assert(rss[i+1] >= rss[i]); + long diff = rss[i+1] / rss[i]; + fprintf(stderr, "RSS CHANGE IS %d => %d: %s (%ld vs %ld)\n", i, i + 1, + diff < 10 ? "SMALL" : "LARGE", rss[i], rss[i + 1]); + } +} +// CHECK: RSS CHANGE IS 2 => 3: SMALL +// CHECK: RSS CHANGE IS 3 => 4: LARGE diff --git a/test/asan/TestCases/Linux/overflow-in-qsort.cc b/test/asan/TestCases/Linux/overflow-in-qsort.cc index 79b654e117cd..21bdff60cd30 100644 --- a/test/asan/TestCases/Linux/overflow-in-qsort.cc +++ b/test/asan/TestCases/Linux/overflow-in-qsort.cc @@ -37,11 +37,9 @@ int main() { MyQsort(a, 2); } -// Fast unwind: can not unwind through qsort. - +// Fast unwind may not unwind through qsort. // CHECK-FAST: ERROR: AddressSanitizer: global-buffer-overflow // CHECK-FAST: #0{{.*}} in QsortCallback -// CHECK-FAST-NOT: MyQsort // CHECK-FAST: is located 0 bytes to the right of global variable 'global_array // CHECK-SLOW: ERROR: AddressSanitizer: global-buffer-overflow diff --git a/test/asan/TestCases/Linux/quarantine_size_mb.cc b/test/asan/TestCases/Linux/quarantine_size_mb.cc new file mode 100644 index 000000000000..4499992444f9 --- /dev/null +++ b/test/asan/TestCases/Linux/quarantine_size_mb.cc @@ -0,0 +1,24 @@ +// Test quarantine_size_mb (and the deprecated quarantine_size) +// RUN: %clangxx_asan %s -o %t +// RUN: ASAN_OPTIONS=quarantine_size=10485760:verbosity=1:hard_rss_limit_mb=50 %run %t 2>&1 | FileCheck %s --check-prefix=Q10 +// RUN: ASAN_OPTIONS=quarantine_size_mb=10:verbosity=1:hard_rss_limit_mb=50 %run %t 2>&1 | FileCheck %s --check-prefix=Q10 +// RUN: ASAN_OPTIONS=quarantine_size_mb=10:quarantine_size=20:verbosity=1 not %run %t 2>&1 | FileCheck %s --check-prefix=BOTH +// RUN: ASAN_OPTIONS=quarantine_size_mb=1000:hard_rss_limit_mb=50 not %run %t 2>&1 | FileCheck %s --check-prefix=RSS_LIMIT +// RUN: ASAN_OPTIONS=hard_rss_limit_mb=50 not %run %t 2>&1 | FileCheck %s --check-prefix=RSS_LIMIT +#include <string.h> +char *g; + +static const int kNumAllocs = 1 << 11; +static const int kAllocSize = 1 << 20; + +int main() { + for (int i = 0; i < kNumAllocs; i++) { + g = new char[kAllocSize]; + memset(g, -1, kAllocSize); + delete [] (g); + } +} + +// Q10: quarantine_size_mb=10M +// BOTH: please use either 'quarantine_size' (deprecated) or quarantine_size_mb, but not both +// RSS_LIMIT: AddressSanitizer: hard rss limit exhausted diff --git a/test/asan/TestCases/Linux/sized_delete_test.cc b/test/asan/TestCases/Linux/sized_delete_test.cc index 823e3c0bf88e..343cb0a86fed 100644 --- a/test/asan/TestCases/Linux/sized_delete_test.cc +++ b/test/asan/TestCases/Linux/sized_delete_test.cc @@ -8,7 +8,7 @@ // Sized-delete is implemented with a weak delete() definition. // Weak symbols are kind of broken on Android. -// XFAIL: android +// XFAIL: android, asan-dynamic-runtime #include <new> #include <stdio.h> diff --git a/test/asan/TestCases/Linux/stack-overflow-sigbus.cc b/test/asan/TestCases/Linux/stack-overflow-sigbus.cc new file mode 100644 index 000000000000..5f597e9c51f0 --- /dev/null +++ b/test/asan/TestCases/Linux/stack-overflow-sigbus.cc @@ -0,0 +1,64 @@ +// Test ASan detection of stack-overflow condition when Linux sends SIGBUS. + +// RUN: %clangxx_asan -O0 %s -o %t && env ASAN_OPTIONS=use_sigaltstack=1 not %run %t 2>&1 | FileCheck %s + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <sys/mman.h> +#include <sys/resource.h> + +const int BS = 1024; +volatile char x; +volatile int y = 1; + +void recursive_func(char *p) { + char buf[BS]; + buf[rand() % BS] = 1; + buf[rand() % BS] = 2; + x = buf[rand() % BS]; + if (y) + recursive_func(buf); + x = 1; // prevent tail call optimization + // CHECK: {{stack-overflow on address 0x.* \(pc 0x.* bp 0x.* sp 0x.* T.*\)}} +} + +void LimitStackAndReexec(int argc, char **argv) { + struct rlimit rlim; + int res = getrlimit(RLIMIT_STACK, &rlim); + assert(res == 0); + if (rlim.rlim_cur == RLIM_INFINITY) { + rlim.rlim_cur = 256 * 1024; + res = setrlimit(RLIMIT_STACK, &rlim); + assert(res == 0); + + execv(argv[0], argv); + assert(0 && "unreachable"); + } +} + +int main(int argc, char **argv) { + LimitStackAndReexec(argc, argv); + + // Map some memory just before the start of the current stack vma. + // When the stack grows down and crashes into it, Linux can send + // SIGBUS instead of SIGSEGV. See: + // http://lkml.iu.edu/hypermail/linux/kernel/1008.1/02299.html + const long pagesize = sysconf(_SC_PAGESIZE); + FILE *f = fopen("/proc/self/maps", "r"); + char a[1000]; + void *p = 0; + while (fgets(a, sizeof a, f)) { + if (strstr(a, "[stack]")) { + unsigned long addr; + if (sscanf(a, "%lx", &addr) == 1) + p = mmap((void *)(addr - 4 * pagesize), pagesize, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); + } + } + assert(p); + + recursive_func(0); + return 0; +} diff --git a/test/asan/TestCases/Linux/stack-trace-dlclose.cc b/test/asan/TestCases/Linux/stack-trace-dlclose.cc index e494e5661d1d..b3bd9f7780f5 100644 --- a/test/asan/TestCases/Linux/stack-trace-dlclose.cc +++ b/test/asan/TestCases/Linux/stack-trace-dlclose.cc @@ -2,7 +2,7 @@ // XFAIL: android // // RUN: %clangxx_asan -DSHARED %s -shared -o %T/stack_trace_dlclose.so -fPIC -// RUN: %clangxx_asan -DSO_DIR=\"%T\" %s -o %t +// RUN: %clangxx_asan -DSO_DIR=\"%T\" %s %libdl -o %t // RUN: ASAN_OPTIONS=exitcode=0 %run %t 2>&1 | FileCheck %s // XFAIL: arm-linux-gnueabi // XFAIL: armv7l-unknown-linux-gnueabihf diff --git a/test/asan/TestCases/Posix/asan-symbolize-sanity-test.cc b/test/asan/TestCases/Posix/asan-symbolize-sanity-test.cc index 6ed02f4d5374..3ce6446eca22 100644 --- a/test/asan/TestCases/Posix/asan-symbolize-sanity-test.cc +++ b/test/asan/TestCases/Posix/asan-symbolize-sanity-test.cc @@ -5,7 +5,7 @@ // shared object files. // RUN: %clangxx_asan -O0 -DSHARED_LIB %s -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -O0 %s -o %t +// RUN: %clangxx_asan -O0 %s %libdl -o %t // RUN: env ASAN_OPTIONS=symbolize=0 not %run %t 2>&1 | %asan_symbolize | FileCheck %s // XFAIL: arm-linux-gnueabi // XFAIL: armv7l-unknown-linux-gnueabihf diff --git a/test/asan/TestCases/Posix/init-order-dlopen.cc b/test/asan/TestCases/Posix/init-order-dlopen.cc index 6f204775eb4e..3c6f093b03d1 100644 --- a/test/asan/TestCases/Posix/init-order-dlopen.cc +++ b/test/asan/TestCases/Posix/init-order-dlopen.cc @@ -10,8 +10,8 @@ // If the linker doesn't support --export-dynamic (which is ELF-specific), // try to link without that option. // FIXME: find a better solution. -// RUN: %clangxx_asan -O0 %s -pthread -o %t -Wl,--export-dynamic || \ -// RUN: %clangxx_asan -O0 %s -pthread -o %t +// RUN: %clangxx_asan -O0 %s -pthread %libdl -o %t -Wl,--export-dynamic || \ +// RUN: %clangxx_asan -O0 %s -pthread %libdl -o %t // RUN: ASAN_OPTIONS=strict_init_order=true %run %t 2>&1 | FileCheck %s #if !defined(SHARED_LIB) #include <dlfcn.h> diff --git a/test/asan/TestCases/Posix/large_allocator_unpoisons_on_free.cc b/test/asan/TestCases/Posix/large_allocator_unpoisons_on_free.cc index 0a4998049cb0..f852a62ea9a3 100644 --- a/test/asan/TestCases/Posix/large_allocator_unpoisons_on_free.cc +++ b/test/asan/TestCases/Posix/large_allocator_unpoisons_on_free.cc @@ -2,7 +2,7 @@ // RUN: %clangxx_asan %s -o %t // The memory is released only when the deallocated chunk leaves the quarantine, // otherwise the mmap(p, ...) call overwrites the malloc header. -// RUN: ASAN_OPTIONS=quarantine_size=1 %run %t +// RUN: ASAN_OPTIONS=quarantine_size_mb=0 %run %t #include <assert.h> #include <string.h> diff --git a/test/asan/TestCases/Posix/shared-lib-test.cc b/test/asan/TestCases/Posix/shared-lib-test.cc index a0827b5fefbf..305942a0792d 100644 --- a/test/asan/TestCases/Posix/shared-lib-test.cc +++ b/test/asan/TestCases/Posix/shared-lib-test.cc @@ -1,11 +1,11 @@ // RUN: %clangxx_asan -O0 -DSHARED_LIB %s -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -O0 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O0 %s %libdl -o %t && not %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -O1 -DSHARED_LIB %s -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s %libdl -o %t && not %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -O2 -DSHARED_LIB %s -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s %libdl -o %t && not %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -O3 -DSHARED_LIB %s -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -O3 %s -o %t && not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s %libdl -o %t && not %run %t 2>&1 | FileCheck %s // XFAIL: arm-linux-gnueabi #if !defined(SHARED_LIB) diff --git a/test/asan/TestCases/Posix/start-deactivated.cc b/test/asan/TestCases/Posix/start-deactivated.cc index d60677a8a5bb..d7e0dfc98e6d 100644 --- a/test/asan/TestCases/Posix/start-deactivated.cc +++ b/test/asan/TestCases/Posix/start-deactivated.cc @@ -4,12 +4,25 @@ // 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 %t.o -o %t -// RUN: ASAN_OPTIONS=start_deactivated=1 not %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O0 %t.o %libdl -o %t +// RUN: ASAN_OPTIONS=start_deactivated=1,allocator_may_return_null=0 \ +// RUN: ASAN_ACTIVATION_OPTIONS=allocator_may_return_null=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK +// RUN: ASAN_OPTIONS=start_deactivated=1 \ +// RUN: ASAN_ACTIVATION_OPTIONS=help=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-HELP +// RUN: ASAN_OPTIONS=start_deactivated=1,verbosity=1 \ +// RUN: ASAN_ACTIVATION_OPTIONS=help=1,handle_segv=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-UNSUPPORTED +// RUN: ASAN_OPTIONS=start_deactivated=1 \ +// RUN: ASAN_ACTIVATION_OPTIONS=help=1,handle_segv=0 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-UNSUPPORTED-V0 + +// Check that verbosity=1 in activation flags affects reporting of unrecognized activation flags. +// RUN: ASAN_OPTIONS=start_deactivated=1 \ +// RUN: ASAN_ACTIVATION_OPTIONS=help=1,handle_segv=0,verbosity=1 not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-UNSUPPORTED + // XFAIL: arm-linux-gnueabi // XFAIL: armv7l-unknown-linux-gnueabihf #if !defined(SHARED_LIB) +#include <assert.h> #include <dlfcn.h> #include <stdio.h> #include <stdlib.h> @@ -43,12 +56,18 @@ int main(int argc, char *argv[]) { 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) { fprintf(stderr, "dlsym failed: %s\n", dlerror()); return 1; } + // Test that ASAN_ACTIVATION_OPTIONS=allocator_may_return_null=1 has effect. + void *p = malloc((unsigned long)-2); + assert(!p); + // CHECK: WARNING: AddressSanitizer failed to allocate 0xfff{{.*}} bytes + ((Fn)fn)(); // CHECK: AddressSanitizer: heap-buffer-overflow // CHECK: READ of size 1 @@ -67,3 +86,16 @@ extern "C" void do_another_bad_thing() { printf("%hhx\n", p[105]); } #endif // SHARED_LIB + +// help=1 in activation flags lists only flags are are supported at activation +// CHECK-HELP: Available flags for {{.*}}Sanitizer: +// CHECK-HELP-NOT: handle_segv +// CHECK-HELP: max_redzone +// CHECK-HELP-NOT: handle_segv + +// unsupported activation flags produce a warning ... +// CHECK-UNSUPPORTED: WARNING: found 1 unrecognized +// CHECK-UNSUPPORTED: handle_segv + +// ... but not at verbosity=0 +// CHECK-UNSUPPORTED-V0-NOT: WARNING: found {{.*}} unrecognized diff --git a/test/asan/TestCases/Posix/tsd_dtor_leak.cc b/test/asan/TestCases/Posix/tsd_dtor_leak.cc index 32253afc8b25..6952245227b4 100644 --- a/test/asan/TestCases/Posix/tsd_dtor_leak.cc +++ b/test/asan/TestCases/Posix/tsd_dtor_leak.cc @@ -1,7 +1,7 @@ // Regression test for a leak in tsd: // https://code.google.com/p/address-sanitizer/issues/detail?id=233 // RUN: %clangxx_asan -O1 %s -pthread -o %t -// RUN: ASAN_OPTIONS=quarantine_size=1 %run %t +// RUN: ASAN_OPTIONS=quarantine_size_mb=0 %run %t #include <pthread.h> #include <stdio.h> #include <stdlib.h> @@ -25,15 +25,17 @@ void Dtor(void *tsd) { int main() { assert(0 == pthread_key_create(&tsd_key, Dtor)); - size_t old_heap_size = 0; + pthread_t t; + for (int i = 0; i < 3; i++) { + pthread_create(&t, 0, Thread, 0); + pthread_join(t, 0); + } + size_t old_heap_size = __sanitizer_get_heap_size(); for (int i = 0; i < 10; i++) { - pthread_t t; pthread_create(&t, 0, Thread, 0); pthread_join(t, 0); size_t new_heap_size = __sanitizer_get_heap_size(); fprintf(stderr, "heap size: new: %zd old: %zd\n", new_heap_size, old_heap_size); - if (old_heap_size) - assert(old_heap_size == new_heap_size); - old_heap_size = new_heap_size; + assert(old_heap_size == new_heap_size); } } diff --git a/test/asan/TestCases/Windows/iostream_sbo.cc b/test/asan/TestCases/Windows/iostream_sbo.cc new file mode 100644 index 000000000000..ffcd53013ec6 --- /dev/null +++ b/test/asan/TestCases/Windows/iostream_sbo.cc @@ -0,0 +1,18 @@ +// First, check this works with the default blacklist: +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: echo "42" | %run %t 2>&1 | FileCheck %s +// +// Then, make sure it still works when a user uses his own blacklist file: +// RUN: %clang_cl_asan -O0 %s -fsanitize-blacklist=%p/../Helpers/initialization-blacklist.txt -Fe%t2 +// RUN: echo "42" | %run %t2 2>&1 | FileCheck %s + +#include <iostream> + +int main() { + int i; + std::cout << "Type i: "; + std::cin >> i; + return 0; +// CHECK: Type i: +// CHECK-NOT: AddressSanitizer: stack-buffer-overflow on address [[ADDR:0x[0-9a-f]+]] +} diff --git a/test/asan/TestCases/Windows/shadow_mapping_failure.cc b/test/asan/TestCases/Windows/shadow_mapping_failure.cc new file mode 100644 index 000000000000..97cd3d60cdfa --- /dev/null +++ b/test/asan/TestCases/Windows/shadow_mapping_failure.cc @@ -0,0 +1,18 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: not %run %t 2>&1 | FileCheck %s + +#include <stdio.h> + +char bigchunk[1 << 30]; + +int main() { + printf("Hello, world!\n"); + scanf("%s", bigchunk); +// CHECK-NOT: Hello, world! +// CHECK: Shadow memory range interleaves with an existing memory mapping. +// CHECK: ASan shadow was supposed to be located in the [0x2fff0000-0x{{.*}}ffff] range. +// CHECK: Dumping process modules: +// CHECK-DAG: 0x{{[0-9a-f]*}}-0x{{[0-9a-f]*}} {{.*}}shadow_mapping_failure +// CHECK-DAG: 0x{{[0-9a-f]*}}-0x{{[0-9a-f]*}} {{.*}}kernel32.dll +// CHECK-DAG: 0x{{[0-9a-f]*}}-0x{{[0-9a-f]*}} {{.*}}ntdll.dll +} diff --git a/test/asan/TestCases/Windows/thread_suspended.cc b/test/asan/TestCases/Windows/thread_suspended.cc new file mode 100644 index 000000000000..47e4f9d5d19b --- /dev/null +++ b/test/asan/TestCases/Windows/thread_suspended.cc @@ -0,0 +1,27 @@ +// RUN: %clang_cl_asan -O0 %s -Fe%t +// RUN: %run %t + +#include <windows.h> + +DWORD WINAPI thread_proc(void *) { + volatile char stack_buffer[42]; + for (int i = 0; i < sizeof(stack_buffer); ++i) + stack_buffer[i] = 42; + return 0x42; +} + +int main() { + DWORD exitcode; + HANDLE thr = CreateThread(NULL, 0, thread_proc, NULL, CREATE_SUSPENDED, NULL); + ResumeThread(thr); + if (thr == 0) + return 1; + if (WAIT_OBJECT_0 != WaitForSingleObject(thr, INFINITE)) + return 2; + + GetExitCodeThread(thr, &exitcode); + if (exitcode != 0x42) + return 3; + CloseHandle(thr); +} + diff --git a/test/asan/TestCases/allocator_returns_null.cc b/test/asan/TestCases/allocator_returns_null.cc index 59a053c3dcad..da6fbd43099e 100644 --- a/test/asan/TestCases/allocator_returns_null.cc +++ b/test/asan/TestCases/allocator_returns_null.cc @@ -24,14 +24,14 @@ int main(int argc, char **argv) { volatile size_t size = std::numeric_limits<size_t>::max() - 10000; assert(argc == 2); - char *x = 0; + void *x = 0; if (!strcmp(argv[1], "malloc")) { fprintf(stderr, "malloc:\n"); - x = (char*)malloc(size); + x = malloc(size); } if (!strcmp(argv[1], "calloc")) { fprintf(stderr, "calloc:\n"); - x = (char*)calloc(size / 4, 4); + x = calloc(size / 4, 4); } if (!strcmp(argv[1], "calloc-overflow")) { @@ -39,18 +39,18 @@ int main(int argc, char **argv) { volatile size_t kMaxSizeT = std::numeric_limits<size_t>::max(); size_t kArraySize = 4096; volatile size_t kArraySize2 = kMaxSizeT / kArraySize + 10; - x = (char*)calloc(kArraySize, kArraySize2); + x = calloc(kArraySize, kArraySize2); } if (!strcmp(argv[1], "realloc")) { fprintf(stderr, "realloc:\n"); - x = (char*)realloc(0, size); + x = realloc(0, size); } if (!strcmp(argv[1], "realloc-after-malloc")) { fprintf(stderr, "realloc-after-malloc:\n"); char *t = (char*)malloc(100); *t = 42; - x = (char*)realloc(t, size); + x = realloc(t, size); assert(*t == 42); free(t); } diff --git a/test/asan/TestCases/asan_options-help.cc b/test/asan/TestCases/asan_options-help.cc new file mode 100644 index 000000000000..f10830f16085 --- /dev/null +++ b/test/asan/TestCases/asan_options-help.cc @@ -0,0 +1,9 @@ +// RUN: %clangxx_asan -O0 %s -o %t +// RUN: ASAN_OPTIONS=help=1 %run %t 2>&1 | FileCheck %s + +int main() { +} + +// CHECK: Available flags for AddressSanitizer: +// CHECK-DAG: handle_segv +// CHECK-DAG: check_initialization_order diff --git a/test/asan/TestCases/deep_call_stack.cc b/test/asan/TestCases/deep_call_stack.cc index 789f23454d19..a5b846e3eb75 100644 --- a/test/asan/TestCases/deep_call_stack.cc +++ b/test/asan/TestCases/deep_call_stack.cc @@ -1,7 +1,8 @@ // Check that UAR mode can handle very deep recusrion. -// export ASAN_OPTIONS=detect_stack_use_after_return=1 +// RUN: export ASAN_OPTIONS=detect_stack_use_after_return=1 // RUN: %clangxx_asan -O2 %s -o %t && \ // RUN: (ulimit -s 4096; %run %t) 2>&1 | FileCheck %s + // Also check that use_sigaltstack+verbosity doesn't crash. // RUN: env ASAN_OPTIONS=verbosity=1:use_sigaltstack=1 %run %t | FileCheck %s #include <stdio.h> diff --git a/test/asan/TestCases/default_options.cc b/test/asan/TestCases/default_options.cc index 6453f66a9523..1614fbe71b4b 100644 --- a/test/asan/TestCases/default_options.cc +++ b/test/asan/TestCases/default_options.cc @@ -4,12 +4,12 @@ // __asan_default_options() are not supported on Windows. // XFAIL: win32 -const char *kAsanDefaultOptions="verbosity=1 foo=bar"; +const char *kAsanDefaultOptions="verbosity=1 help=1"; extern "C" __attribute__((no_sanitize_address)) const char *__asan_default_options() { - // CHECK: Using the defaults from __asan_default_options: {{.*}} foo=bar + // CHECK: Available flags for AddressSanitizer: return kAsanDefaultOptions; } diff --git a/test/asan/TestCases/dlclose-test.cc b/test/asan/TestCases/dlclose-test.cc index 094453f3de2a..2d31aee5a32f 100644 --- a/test/asan/TestCases/dlclose-test.cc +++ b/test/asan/TestCases/dlclose-test.cc @@ -15,13 +15,13 @@ // REQUIRES: x86_64-supported-target,i386-supported-target // RUN: %clangxx_asan -O0 -DSHARED_LIB %s -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -O0 %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O0 %s %libdl -o %t && %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -O1 -DSHARED_LIB %s -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O1 %s %libdl -o %t && %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -O2 -DSHARED_LIB %s -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -O2 %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O2 %s %libdl -o %t && %run %t 2>&1 | FileCheck %s // RUN: %clangxx_asan -O3 -DSHARED_LIB %s -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -O3 %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_asan -O3 %s %libdl -o %t && %run %t 2>&1 | FileCheck %s #if !defined(SHARED_LIB) #include <assert.h> diff --git a/test/asan/TestCases/interception_failure_test.cc b/test/asan/TestCases/interception_failure_test.cc index a23fe6938ca9..53c50090bfa6 100644 --- a/test/asan/TestCases/interception_failure_test.cc +++ b/test/asan/TestCases/interception_failure_test.cc @@ -5,6 +5,7 @@ // 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 +// XFAIL: freebsd #include <stdlib.h> #include <stdio.h> diff --git a/test/asan/TestCases/log-path_test.cc b/test/asan/TestCases/log-path_test.cc index 5a1d0729119a..7dd1fadda86d 100644 --- a/test/asan/TestCases/log-path_test.cc +++ b/test/asan/TestCases/log-path_test.cc @@ -13,7 +13,7 @@ // RUN: FileCheck %s --check-prefix=CHECK-ERROR < %t.log.* // Invalid log_path. -// RUN: env ASAN_OPTIONS=log_path=/INVALID not %run %t 2> %t.out +// RUN: env ASAN_OPTIONS=log_path=/dev/null/INVALID not %run %t 2> %t.out // RUN: FileCheck %s --check-prefix=CHECK-INVALID < %t.out // Too long log_path. @@ -40,5 +40,5 @@ int main(int argc, char **argv) { return res; } // CHECK-ERROR: ERROR: AddressSanitizer -// CHECK-INVALID: ERROR: Can't open file: /INVALID +// CHECK-INVALID: ERROR: Can't open file: /dev/null/INVALID // CHECK-LONG: ERROR: Path is too long: 01234 diff --git a/test/asan/TestCases/stack-overflow.cc b/test/asan/TestCases/stack-overflow.cc index 7542d56b6db8..d4bb74730f12 100644 --- a/test/asan/TestCases/stack-overflow.cc +++ b/test/asan/TestCases/stack-overflow.cc @@ -92,7 +92,7 @@ void LimitStackAndReexec(int argc, char **argv) { int res = getrlimit(RLIMIT_STACK, &rlim); assert(res == 0); if (rlim.rlim_cur == RLIM_INFINITY) { - rlim.rlim_cur = 128 * 1024; + rlim.rlim_cur = 256 * 1024; res = setrlimit(RLIMIT_STACK, &rlim); assert(res == 0); diff --git a/test/asan/TestCases/suppressions-function.cc b/test/asan/TestCases/suppressions-function.cc index c52b3c303518..0a6c9995827e 100644 --- a/test/asan/TestCases/suppressions-function.cc +++ b/test/asan/TestCases/suppressions-function.cc @@ -3,8 +3,8 @@ // RUN: not %run %t 2>&1 | FileCheck --check-prefix=CHECK-CRASH %s // RUN: echo "interceptor_via_fun:crash_function" > %t.supp -// RUN: %clangxx_asan -O0 %s -o %t && ASAN_OPTIONS=suppressions=%t.supp %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s -// RUN: %clangxx_asan -O3 %s -o %t && ASAN_OPTIONS=suppressions=%t.supp %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s +// RUN: %clangxx_asan -O0 %s -o %t && ASAN_OPTIONS="suppressions='%t.supp'" %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s +// RUN: %clangxx_asan -O3 %s -o %t && ASAN_OPTIONS="suppressions='%t.supp'" %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s // XFAIL: android diff --git a/test/asan/TestCases/suppressions-interceptor.cc b/test/asan/TestCases/suppressions-interceptor.cc index 10d24fdc30a3..45a14d1a422a 100644 --- a/test/asan/TestCases/suppressions-interceptor.cc +++ b/test/asan/TestCases/suppressions-interceptor.cc @@ -3,7 +3,7 @@ // RUN: not %run %t 2>&1 | FileCheck --check-prefix=CHECK-CRASH %s // RUN: echo "interceptor_name:strlen" > %t.supp -// RUN: ASAN_OPTIONS=suppressions=%t.supp %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s +// RUN: ASAN_OPTIONS="suppressions='%t.supp'" %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s // XFAIL: android diff --git a/test/asan/TestCases/suppressions-library.cc b/test/asan/TestCases/suppressions-library.cc index dfb0d4a5e030..28f19f54efc1 100644 --- a/test/asan/TestCases/suppressions-library.cc +++ b/test/asan/TestCases/suppressions-library.cc @@ -1,11 +1,11 @@ -// RUN: %clangxx_asan -O0 -DSHARED_LIB %s -fPIC -shared -o %t-so.so -// RUN: %clangxx_asan -O0 %s %t-so.so -o %t +// RUN: %clangxx_asan -O0 -DSHARED_LIB %s -fPIC -shared -o %t-so.so -install_name @rpath/suppressions-library.cc.tmp-so.so +// RUN: %clangxx_asan -O0 %s %t-so.so -o %t -rpath @executable_path // Check that without suppressions, we catch the issue. // RUN: not %run %t 2>&1 | FileCheck --check-prefix=CHECK-CRASH %s -// RUN: echo "interceptor_via_lib:%t-so.so" > %t.supp -// RUN: ASAN_OPTIONS=suppressions=%t.supp %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s +// RUN: echo "interceptor_via_lib:suppressions-library.cc.tmp-so.so" > %t.supp +// RUN: ASAN_OPTIONS="suppressions='%t.supp'" %run %t 2>&1 | FileCheck --check-prefix=CHECK-IGNORE %s // XFAIL: android diff --git a/test/asan/TestCases/zero_page_pc.cc b/test/asan/TestCases/zero_page_pc.cc index 5810a9fb9dde..925cbc63a305 100644 --- a/test/asan/TestCases/zero_page_pc.cc +++ b/test/asan/TestCases/zero_page_pc.cc @@ -6,7 +6,11 @@ int main() { void_f *func = (void_f *)0x4; func(); // x86 reports the SEGV with both address=4 and pc=4. - // PowerPC64 reports it with address=4 but pc still in main(). - // CHECK: {{AddressSanitizer: SEGV.*(address|pc) 0x0*4}} + // On PowerPC64 ELFv1, the pointer is taken to be a function-descriptor + // pointer out of which three 64-bit quantities are read. This will SEGV, but + // the compiler is free to choose the order. As a result, the address is + // either 0x4, 0xc or 0x14. The pc is still in main() because it has not + // actually made the call when the faulting access occurs. + // CHECK: {{AddressSanitizer: SEGV.*(address|pc) 0x0*[4c]}} return 0; } diff --git a/test/asan/Unit/lit.site.cfg.in b/test/asan/Unit/lit.site.cfg.in index 1791b6b05b1c..b5991023ee8a 100644 --- a/test/asan/Unit/lit.site.cfg.in +++ b/test/asan/Unit/lit.site.cfg.in @@ -8,7 +8,7 @@ lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/unittests/lit.common.un def push_ld_library_path(config, new_path): new_ld_library_path = os.path.pathsep.join( - (new_path, config.environment['LD_LIBRARY_PATH'])) + (new_path, config.environment.get('LD_LIBRARY_PATH', ''))) config.environment['LD_LIBRARY_PATH'] = new_ld_library_path # Setup config name. @@ -17,7 +17,13 @@ config.name = 'AddressSanitizer-Unit' # Setup test source and exec root. For unit tests, we define # it as build directory with ASan unit tests. # FIXME: De-hardcode this path. -config.test_exec_root = "@COMPILER_RT_BINARY_DIR@/lib/asan/tests" +if @ASAN_TEST_DYNAMIC@: + test_dir = "dynamic" +else: + test_dir = "default" +config.test_exec_root = os.path.join("@COMPILER_RT_BINARY_DIR@", + "lib", "asan", "tests", test_dir) + config.test_source_root = config.test_exec_root # Set LD_LIBRARY_PATH to pick dynamic runtime up properly. diff --git a/test/asan/android_commands/android_run.py b/test/asan/android_commands/android_run.py index 7f8c612a0cf0..621844fd30a2 100755 --- a/test/asan/android_commands/android_run.py +++ b/test/asan/android_commands/android_run.py @@ -14,7 +14,7 @@ def build_env(): args.append('LD_LIBRARY_PATH=%s:%s' % (ANDROID_TMPDIR, os.environ.get('LD_LIBRARY_PATH', ''))) for (key, value) in os.environ.items(): - if key in ['ASAN_OPTIONS']: + if key in ['ASAN_OPTIONS', 'ASAN_ACTIVATION_OPTIONS']: args.append('%s="%s"' % (key, value)) return ' '.join(args) diff --git a/test/asan/lit.cfg b/test/asan/lit.cfg index 82a36de9cdda..8be7062614b3 100644 --- a/test/asan/lit.cfg +++ b/test/asan/lit.cfg @@ -19,7 +19,7 @@ def push_dynamic_library_lookup_path(config, new_path): dynamic_library_lookup_var = 'LD_LIBRARY_PATH' new_ld_library_path = os.path.pathsep.join( - (new_path, config.environment[dynamic_library_lookup_var])) + (new_path, config.environment.get(dynamic_library_lookup_var, ''))) config.environment[dynamic_library_lookup_var] = new_ld_library_path # Setup config name. @@ -28,17 +28,19 @@ config.name = 'AddressSanitizer' + config.name_suffix # Setup source root. config.test_source_root = os.path.dirname(__file__) +# There is no libdl on FreeBSD. +if config.host_os != 'FreeBSD': + libdl_flag = "-ldl" +else: + libdl_flag = "" + # GCC-ASan doesn't link in all the necessary libraries automatically, so # we have to do it ourselves. if config.compiler_id == 'GNU': - extra_linkflags = ["-pthread", "-lstdc++"] + extra_linkflags = ["-pthread", "-lstdc++", libdl_flag] else: extra_linkflags = [] -# There is no libdl on FreeBSD. -if config.compiler_id == 'GNU' and config.host_os != 'FreeBSD': - extra_linkflags += ["-ldl"] - # Setup default compiler flags used with -fsanitize=address option. # FIXME: Review the set of required flags and check if it can be reduced. target_cflags = [get_required_attr(config, "target_cflags")] + extra_linkflags @@ -121,6 +123,8 @@ else: config.substitutions.append( ('CHECK-%kernel_bits', ("CHECK-kernel-" + kernel_bits + "-bits"))) +config.substitutions.append( ("%libdl", libdl_flag) ) + config.available_features.add("asan-" + config.bits + "-bits") # Allow tests to use REQUIRES=stable-runtime. For use when you cannot use XFAIL diff --git a/test/builtins/Unit/clear_cache_test.c b/test/builtins/Unit/clear_cache_test.c index 3507fd80b288..3c893018545f 100644 --- a/test/builtins/Unit/clear_cache_test.c +++ b/test/builtins/Unit/clear_cache_test.c @@ -38,7 +38,18 @@ int func2() return 2; } - +void *__attribute__((noinline)) +memcpy_f(void *dst, const void *src, size_t n) { +// ARM and MIPS nartually align functions, but use the LSB for ISA selection +// (THUMB, MIPS16/uMIPS respectively). Ensure that the ISA bit is ignored in +// the memcpy +#if defined(__arm__) || defined(__mips__) + return (void *)((uintptr_t)memcpy(dst, (void *)((uintptr_t)src & ~1), n) | + ((uintptr_t)src & 1)); +#else + return memcpy(dst, (void *)((uintptr_t)src), n); +#endif +} unsigned char execution_buffer[128]; @@ -59,16 +70,14 @@ int main() return 1; // verify you can copy and execute a function - memcpy(execution_buffer, (void *)(uintptr_t)&func1, 128); + pfunc f1 = (pfunc)memcpy_f(execution_buffer, func1, 128); __clear_cache(execution_buffer, &execution_buffer[128]); - pfunc f1 = (pfunc)(uintptr_t)execution_buffer; if ((*f1)() != 1) return 1; // verify you can overwrite a function with another - memcpy(execution_buffer, (void *)(uintptr_t)&func2, 128); + pfunc f2 = (pfunc)memcpy_f(execution_buffer, func2, 128); __clear_cache(execution_buffer, &execution_buffer[128]); - pfunc f2 = (pfunc)(uintptr_t)execution_buffer; if ((*f2)() != 2) return 1; diff --git a/test/builtins/Unit/enable_execute_stack_test.c b/test/builtins/Unit/enable_execute_stack_test.c index c0f67b337939..38a142afb24d 100644 --- a/test/builtins/Unit/enable_execute_stack_test.c +++ b/test/builtins/Unit/enable_execute_stack_test.c @@ -45,8 +45,18 @@ int func2() return 2; } - - +void *__attribute__((noinline)) +memcpy_f(void *dst, const void *src, size_t n) { +// ARM and MIPS nartually align functions, but use the LSB for ISA selection +// (THUMB, MIPS16/uMIPS respectively). Ensure that the ISA bit is ignored in +// the memcpy +#if defined(__arm__) || defined(__mips__) + return (void *)((uintptr_t)memcpy(dst, (void *)((uintptr_t)src & ~1), n) | + ((uintptr_t)src & 1)); +#else + return memcpy(dst, (void *)((uintptr_t)src), n); +#endif +} int main() { @@ -55,16 +65,14 @@ int main() __enable_execute_stack(execution_buffer); // verify you can copy and execute a function - memcpy(execution_buffer, (void *)(uintptr_t)&func1, 128); + pfunc f1 = (pfunc)memcpy_f(execution_buffer, func1, 128); __clear_cache(execution_buffer, &execution_buffer[128]); - pfunc f1 = (pfunc)(uintptr_t)execution_buffer; if ((*f1)() != 1) return 1; // verify you can overwrite a function with another - memcpy(execution_buffer, (void *)(uintptr_t)&func2, 128); + pfunc f2 = (pfunc)memcpy_f(execution_buffer, func2, 128); __clear_cache(execution_buffer, &execution_buffer[128]); - pfunc f2 = (pfunc)(uintptr_t)execution_buffer; if ((*f2)() != 2) return 1; diff --git a/test/lit.common.configured.in b/test/lit.common.configured.in index beecaa25886a..ceab67d4ad07 100644 --- a/test/lit.common.configured.in +++ b/test/lit.common.configured.in @@ -30,7 +30,7 @@ set_default("emulator", "@COMPILER_RT_EMULATOR@") # apply substitution. try: config.llvm_tools_dir = config.llvm_tools_dir % lit_config.params -except KeyError,e: +except KeyError as e: key, = e.args lit_config.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key)) diff --git a/test/lsan/TestCases/ignore_object.cc b/test/lsan/TestCases/ignore_object.cc index 38d76e6798b2..ac69e12a4ba6 100644 --- a/test/lsan/TestCases/ignore_object.cc +++ b/test/lsan/TestCases/ignore_object.cc @@ -1,5 +1,5 @@ // Test for __lsan_ignore_object(). -// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=0:verbosity=2" +// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=0" // RUN: %clangxx_lsan %s -o %t // RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck %s @@ -20,5 +20,4 @@ int main() { return 0; } // CHECK: Test alloc: [[ADDR:.*]]. -// CHECK: ignoring heap object at [[ADDR]] // CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: 1337 byte(s) leaked in 1 allocation(s) diff --git a/test/lsan/TestCases/ignore_object_errors.cc b/test/lsan/TestCases/ignore_object_errors.cc index 39b9b0288bb3..41603274a306 100644 --- a/test/lsan/TestCases/ignore_object_errors.cc +++ b/test/lsan/TestCases/ignore_object_errors.cc @@ -1,5 +1,4 @@ // Test for incorrect use of __lsan_ignore_object(). -// RUN: LSAN_BASE="verbosity=2" // RUN: %clangxx_lsan %s -o %t // RUN: LSAN_OPTIONS=$LSAN_BASE %run %t 2>&1 | FileCheck %s @@ -18,5 +17,4 @@ int main() { return 0; } // CHECK: Test alloc: [[ADDR:.*]]. -// CHECK: heap object at [[ADDR]] is already being ignored -// CHECK: no heap object found at [[ADDR]] +// CHECK-NOT: SUMMARY: {{.*}} leaked diff --git a/test/lsan/TestCases/leak_check_at_exit.cc b/test/lsan/TestCases/leak_check_at_exit.cc index fe3f70e40005..6f1cd22cf68d 100644 --- a/test/lsan/TestCases/leak_check_at_exit.cc +++ b/test/lsan/TestCases/leak_check_at_exit.cc @@ -4,7 +4,7 @@ // RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do // RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-do // RUN: LSAN_OPTIONS=$LSAN_BASE:"leak_check_at_exit=0" not %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do -// RUN: LSAN_OPTIONS=%LSAN_BASE:"leak_check_at_exit=0" %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont +// RUN: LSAN_OPTIONS=$LSAN_BASE:"leak_check_at_exit=0" %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont #include <stdio.h> #include <stdlib.h> diff --git a/test/lsan/TestCases/leak_check_before_thread_started.cc b/test/lsan/TestCases/leak_check_before_thread_started.cc index 891cd699a255..0bd4837f14c0 100644 --- a/test/lsan/TestCases/leak_check_before_thread_started.cc +++ b/test/lsan/TestCases/leak_check_before_thread_started.cc @@ -1,8 +1,7 @@ // Regression test for http://llvm.org/bugs/show_bug.cgi?id=21621 // This test relies on timing between threads, so any failures will be flaky. -// RUN: LSAN_BASE="use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t -// RUN: %run %t +// RUN: LSAN_OPTIONS="log_pointers=1:log_threads=1" %run %t #include <assert.h> #include <pthread.h> #include <stdlib.h> diff --git a/test/lsan/TestCases/suppressions_file.cc b/test/lsan/TestCases/suppressions_file.cc index 16ad9323461e..d030896d519f 100644 --- a/test/lsan/TestCases/suppressions_file.cc +++ b/test/lsan/TestCases/suppressions_file.cc @@ -1,11 +1,11 @@ // RUN: LSAN_BASE="use_registers=0:use_stacks=0" // RUN: %clangxx_lsan %s -o %t -// RUN: echo "leak:*LSanTestLeakingFunc*" > %t.supp1 -// RUN: LSAN_OPTIONS=$LSAN_BASE:suppressions=%t.supp1 not %run %t 2>&1 | FileCheck %s +// RUN: echo "leak:*LSanTestLeakingFunc*" > %t.supp +// RUN: LSAN_OPTIONS="$LSAN_BASE:suppressions='%t.supp'" not %run %t 2>&1 | FileCheck %s -// RUN: echo "leak:%t" > %t.supp2 -// RUN: LSAN_OPTIONS=$LSAN_BASE:suppressions="%t.supp2":symbolize=false %run %t +// RUN: echo "leak:%t" > %t.supp +// RUN: LSAN_OPTIONS="$LSAN_BASE:suppressions='%t.supp':symbolize=false" %run %t #include <stdio.h> #include <stdlib.h> diff --git a/test/msan/msan_print_shadow.cc b/test/msan/msan_print_shadow.cc index 0cc1d660be1b..f4894596a0e2 100644 --- a/test/msan/msan_print_shadow.cc +++ b/test/msan/msan_print_shadow.cc @@ -99,7 +99,7 @@ int main(void) { // CHECK-ORIGINS: #1 {{.*}} in main{{.*}}msan_print_shadow.cc:14 // CHECK-ORIGINS: Origin B (origin_id {{.*}}): -// CHECK-ORIGINS: Uninitialized value was created by a heap allocation +// CHECK-ORIGINS: Memory was marked as uninitialized // CHECK-ORIGINS: #0 {{.*}} in __msan_allocated_memory // CHECK-ORIGINS: #1 {{.*}} in main{{.*}}msan_print_shadow.cc:18 @@ -110,13 +110,13 @@ int main(void) { // CHECK-ORIGINS: #0 {{.*}} in main{{.*}}msan_print_shadow.cc:12 // CHECK-ORIGINS: Origin D (origin_id {{.*}}): -// CHECK-ORIGINS: Uninitialized value was created by a heap allocation +// CHECK-ORIGINS: Memory was marked as uninitialized // CHECK-ORIGINS: #0 {{.*}} in __msan_allocated_memory // CHECK-ORIGINS: #1 {{.*}} in main{{.*}}msan_print_shadow.cc:20 // ... // CHECK-ORIGINS: Origin Z (origin_id {{.*}}): -// CHECK-ORIGINS: Uninitialized value was created by a heap allocation +// CHECK-ORIGINS: Memory was marked as uninitialized // CHECK-ORIGINS: #0 {{.*}} in __msan_allocated_memory // CHECK-ORIGINS: #1 {{.*}} in main{{.*}}msan_print_shadow.cc:42 diff --git a/test/msan/origin-store-long.cc b/test/msan/origin-store-long.cc new file mode 100644 index 000000000000..a7c2b7a7d578 --- /dev/null +++ b/test/msan/origin-store-long.cc @@ -0,0 +1,21 @@ +// Check that 8-byte store updates origin for the full store range. +// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out && FileCheck %s < %t.out +// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out && FileCheck %s < %t.out + +#include <sanitizer/msan_interface.h> + +int main() { + uint64_t *volatile p = new uint64_t; + uint64_t *volatile q = new uint64_t; + *p = *q; + char *z = (char *)p; + return z[6]; +// CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value +// CHECK: in main {{.*}}origin-store-long.cc:[[@LINE-2]] + +// CHECK: Uninitialized value was created by a heap allocation +// CHECK: in main {{.*}}origin-store-long.cc:[[@LINE-8]] +} + diff --git a/test/msan/realloc-large-origin.cc b/test/msan/realloc-large-origin.cc new file mode 100644 index 000000000000..de39394cbb79 --- /dev/null +++ b/test/msan/realloc-large-origin.cc @@ -0,0 +1,30 @@ +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// This is a regression test: there used to be broken "stored to memory at" +// stacks with +// in __msan_memcpy +// in __msan::MsanReallocate +// and nothing below that. + +#include <stdlib.h> +int main(int argc, char **argv) { + char *p = (char *)malloc(100); + p = (char *)realloc(p, 10000); + char x = p[50]; + free(p); + return x; + +// CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value +// 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: Uninitialized value was created by a heap allocation +// CHECK: {{#0 0x.* in .*malloc}} +// CHECK: {{#1 0x.* in main .*realloc-large-origin.cc:}}[[@LINE-15]] +} diff --git a/test/msan/realloc-origin.cc b/test/msan/realloc-origin.cc new file mode 100644 index 000000000000..6707cc9049a4 --- /dev/null +++ b/test/msan/realloc-origin.cc @@ -0,0 +1,21 @@ +// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out +// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O2 %s -o %t && not %run %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// This test relies on realloc from 100 to 101 being done in-place. + +#include <stdlib.h> +int main(int argc, char **argv) { + char *p = (char *)malloc(100); + p = (char *)realloc(p, 101); + char x = p[100]; + free(p); + return x; + // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value + // CHECK: {{#0 0x.* in main .*realloc-origin.cc:}}[[@LINE-2]] + + // CHECK: Uninitialized value was created by a heap allocation + // CHECK: {{#0 0x.* in .*realloc}} + // CHECK: {{#1 0x.* in main .*realloc-origin.cc:}}[[@LINE-9]] +} diff --git a/test/msan/select_float_origin.cc b/test/msan/select_float_origin.cc index ca8f3a83b0ed..75731dc457fb 100644 --- a/test/msan/select_float_origin.cc +++ b/test/msan/select_float_origin.cc @@ -17,7 +17,7 @@ int main() { __msan_allocated_memory(&y, sizeof(y)); float z = b ? x : y; if (z > 0) printf(".\n"); - // CHECK: Uninitialized value was created by a heap allocation + // CHECK: Memory was marked as uninitialized // CHECK: {{#0 0x.* in .*__msan_allocated_memory}} // CHECK: {{#1 0x.* in main .*select_float_origin.cc:}}[[@LINE-6]] return 0; diff --git a/test/msan/use-after-free.cc b/test/msan/use-after-free.cc index 5b408c536495..869bad98e455 100644 --- a/test/msan/use-after-free.cc +++ b/test/msan/use-after-free.cc @@ -27,7 +27,7 @@ int main(int argc, char **argv) { // CHECK: WARNING: MemorySanitizer: use-of-uninitialized-value // CHECK: {{#0 0x.* in main .*use-after-free.cc:}}[[@LINE-3]] - // CHECK-ORIGINS: Uninitialized value was created by a heap allocation + // CHECK-ORIGINS: Uninitialized value was created by a heap deallocation // CHECK-ORIGINS: {{#0 0x.* in .*free}} // CHECK-ORIGINS: {{#1 0x.* in main .*use-after-free.cc:}}[[@LINE-9]] return 0; diff --git a/test/profile/instrprof-basic.c b/test/profile/instrprof-basic.c index fd3516cfad03..995525bf9553 100644 --- a/test/profile/instrprof-basic.c +++ b/test/profile/instrprof-basic.c @@ -27,5 +27,5 @@ int main(int argc, const char *argv[]) { return 1; } -// CHECK: ![[PD1]] = metadata !{metadata !"branch_weights", i32 1, i32 2} -// CHECK: ![[PD2]] = metadata !{metadata !"branch_weights", i32 2, i32 1} +// CHECK: ![[PD1]] = !{!"branch_weights", i32 1, i32 2} +// CHECK: ![[PD2]] = !{!"branch_weights", i32 2, i32 1} diff --git a/test/profile/instrprof-reset-counters.c b/test/profile/instrprof-reset-counters.c index c92732baf45d..e8892366bcfe 100644 --- a/test/profile/instrprof-reset-counters.c +++ b/test/profile/instrprof-reset-counters.c @@ -16,4 +16,4 @@ void foo(int N) { // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[FOO:[0-9]+]] if (N) {} } -// CHECK: ![[FOO]] = metadata !{metadata !"branch_weights", i32 2, i32 1} +// CHECK: ![[FOO]] = !{!"branch_weights", i32 2, i32 1} diff --git a/test/profile/instrprof-set-filename.c b/test/profile/instrprof-set-filename.c index 045821899e44..51aa4234fea1 100644 --- a/test/profile/instrprof-set-filename.c +++ b/test/profile/instrprof-set-filename.c @@ -11,4 +11,4 @@ int main(int argc, const char *argv[]) { __llvm_profile_set_filename(argv[1]); return 0; } -// CHECK: ![[PD1]] = metadata !{metadata !"branch_weights", i32 1, i32 2} +// CHECK: ![[PD1]] = !{!"branch_weights", i32 1, i32 2} diff --git a/test/profile/instrprof-without-libc.c b/test/profile/instrprof-without-libc.c index 60ca9496c611..fc6c9b25b3ba 100644 --- a/test/profile/instrprof-without-libc.c +++ b/test/profile/instrprof-without-libc.c @@ -46,7 +46,7 @@ int main(int argc, const char *argv[]) { return fclose(File); #endif } -// CHECK: ![[PD1]] = metadata !{metadata !"branch_weights", i32 1, i32 2} +// CHECK: ![[PD1]] = !{!"branch_weights", i32 1, i32 2} // CHECK-SYMBOLS-NOT: ___cxx_global_var_init // CHECK-SYMBOLS-NOT: ___llvm_profile_register_write_file_atexit diff --git a/test/profile/instrprof-write-file-atexit-explicitly.c b/test/profile/instrprof-write-file-atexit-explicitly.c index ba229b9144fa..18c365af5003 100644 --- a/test/profile/instrprof-write-file-atexit-explicitly.c +++ b/test/profile/instrprof-write-file-atexit-explicitly.c @@ -14,4 +14,4 @@ int main(int argc, const char *argv[]) { __llvm_profile_set_filename(argv[1]); return 0; } -// CHECK: ![[PD1]] = metadata !{metadata !"branch_weights", i32 1, i32 2} +// CHECK: ![[PD1]] = !{!"branch_weights", i32 1, i32 2} diff --git a/test/profile/instrprof-write-file-only.c b/test/profile/instrprof-write-file-only.c index 0dd61de39f1a..4abbdea7c674 100644 --- a/test/profile/instrprof-write-file-only.c +++ b/test/profile/instrprof-write-file-only.c @@ -32,4 +32,4 @@ int foo(int X) { // CHECK: br i1 %{{.*}}, label %{{.*}}, label %{{[^,]+$}} return X <= 0 ? -X : X; } -// CHECK: ![[PD1]] = metadata !{metadata !"branch_weights", i32 1, i32 2} +// CHECK: ![[PD1]] = !{!"branch_weights", i32 1, i32 2} diff --git a/test/profile/instrprof-write-file.c b/test/profile/instrprof-write-file.c index 12967cb94a55..af008ed9439e 100644 --- a/test/profile/instrprof-write-file.c +++ b/test/profile/instrprof-write-file.c @@ -30,5 +30,5 @@ int foo(int X) { // CHECK2: br i1 %{{.*}}, label %{{.*}}, label %{{.*}}, !prof ![[PD2:[0-9]+]] return X <= 0 ? -X : X; } -// CHECK: ![[PD1]] = metadata !{metadata !"branch_weights", i32 1, i32 2} -// CHECK2: ![[PD2]] = metadata !{metadata !"branch_weights", i32 2, i32 1} +// CHECK: ![[PD1]] = !{!"branch_weights", i32 1, i32 2} +// CHECK2: ![[PD2]] = !{!"branch_weights", i32 2, i32 1} diff --git a/test/sanitizer_common/TestCases/Linux/hard_rss_limit_mb_test.cc b/test/sanitizer_common/TestCases/Linux/hard_rss_limit_mb_test.cc new file mode 100644 index 000000000000..225c44e25cd0 --- /dev/null +++ b/test/sanitizer_common/TestCases/Linux/hard_rss_limit_mb_test.cc @@ -0,0 +1,37 @@ +// Check hard_rss_limit_mb. Not all sanitizers implement it yet. +// RUN: %clangxx -O2 %s -o %t +// +// Run with limit should fail: +// RUN: %tool_options=hard_rss_limit_mb=100 not %run %t 2>&1 | FileCheck %s +// This run uses getrusage: +// RUN: %tool_options=hard_rss_limit_mb=100:can_use_proc_maps_statm=0 not %run %t 2>&1 | FileCheck %s +// +// Run w/o limit or with a large enough limit should pass: +// RUN: %tool_options=hard_rss_limit_mb=1000 %run %t +// RUN: %run %t +// +// FIXME: make it work for other sanitizers. +// XFAIL: lsan +// XFAIL: tsan +// XFAIL: msan + +#include <string.h> +#include <stdio.h> +#include <unistd.h> + +const int kNumAllocs = 200 * 1000; +const int kAllocSize = 1000; +volatile char *sink[kNumAllocs]; + +int main(int argc, char **argv) { + for (int i = 0; i < kNumAllocs; i++) { + if ((i % 1000) == 0) { + fprintf(stderr, "[%d]\n", i); + } + char *x = new char[kAllocSize]; + memset(x, 0, kAllocSize); + sink[i] = x; + } + sleep(1); // Make sure the background thread has time to kill the process. +// CHECK: hard rss limit exhausted +} diff --git a/test/sanitizer_common/TestCases/Linux/sanitizer_set_death_callback_test.cc b/test/sanitizer_common/TestCases/Linux/sanitizer_set_death_callback_test.cc new file mode 100644 index 000000000000..ee3d59c72172 --- /dev/null +++ b/test/sanitizer_common/TestCases/Linux/sanitizer_set_death_callback_test.cc @@ -0,0 +1,49 @@ +// RUN: %clangxx -O2 %s -o %t && not %run %t 2>&1 | FileCheck %s +// Check __sanitizer_set_death_callback. Not all sanitizers implement it yet. +// XFAIL: lsan +// XFAIL: tsan + +#include <sanitizer/common_interface_defs.h> +#include <stdio.h> +#include <pthread.h> + +volatile char *zero = 0; + +void Death() { + fprintf(stderr, "DEATH CALLBACK EXECUTED\n"); +} +// CHECK: DEATH CALLBACK EXECUTED + +int global[10]; +volatile char *sink; + +void *Thread(void *x) { + global[0]++; + return x; +} + +__attribute__((noinline)) +void MaybeInit(int *uninitialized) { + if (zero) + *uninitialized = 1; +} + +__attribute__((noinline)) +void Leak() { + sink = new char[100]; // trigger lsan report. +} + +int main(int argc, char **argv) { + int uninitialized; + __sanitizer_set_death_callback(Death); + MaybeInit(&uninitialized); + if (uninitialized) // trigger msan report. + global[0] = 77; + pthread_t t; + pthread_create(&t, 0, Thread, 0); + global[0]++; // trigger tsan report. + pthread_join(t, 0); + global[argc + 10]++; // trigger asan report. + Leak(); + sink = 0; +} diff --git a/test/sanitizer_common/TestCases/Linux/sched_getparam.cc b/test/sanitizer_common/TestCases/Linux/sched_getparam.cc new file mode 100644 index 000000000000..390c656fe209 --- /dev/null +++ b/test/sanitizer_common/TestCases/Linux/sched_getparam.cc @@ -0,0 +1,13 @@ +// RUN: %clangxx -O0 %s -o %t && %run %t + +#include <assert.h> +#include <sched.h> +#include <stdio.h> + +int main(void) { + struct sched_param param; + int res = sched_getparam(0, ¶m); + assert(res == 0); + if (param.sched_priority == 42) printf(".\n"); + return 0; +} 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 new file mode 100644 index 000000000000..145cc5d05769 --- /dev/null +++ b/test/sanitizer_common/TestCases/Linux/soft_rss_limit_mb_test.cc @@ -0,0 +1,66 @@ +// Check soft_rss_limit_mb. Not all sanitizers implement it yet. +// RUN: %clangxx -O2 %s -o %t +// +// Run with limit should fail: +// RUN: %tool_options=soft_rss_limit_mb=220:quarantine_size=1:allocator_may_return_null=1 %run %t 2>&1 | FileCheck %s -check-prefix=CHECK_MAY_RETURN_1 +// RUN: %tool_options=soft_rss_limit_mb=220:quarantine_size=1:allocator_may_return_null=0 not %run %t 2>&1 | FileCheck %s -check-prefix=CHECK_MAY_RETURN_0 + +// 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: %tool_options=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 + +// FIXME: make it work for other sanitizers. +// XFAIL: lsan +// XFAIL: tsan +// XFAIL: msan +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +static const int kMaxNumAllocs = 1 << 9; +static const int kAllocSize = 1 << 20; // Large enough to go via mmap. + +static char *allocs[kMaxNumAllocs]; + +int main() { + int num_allocs = kMaxNumAllocs / 4; + for (int i = 0; i < 3; i++, num_allocs *= 2) { + fprintf(stderr, "[%d] allocating %d times\n", i, num_allocs); + int zero_results = 0; + for (int j = 0; j < num_allocs; j++) { + if ((j % (num_allocs / 8)) == 0) { + usleep(100000); + fprintf(stderr, " [%d]\n", j); + } + allocs[j] = (char*)malloc(kAllocSize); + if (allocs[j]) + memset(allocs[j], -1, kAllocSize); + else + zero_results++; + } + if (zero_results) + fprintf(stderr, "Some of the malloc calls returned null: %d\n", + zero_results); + if (zero_results != num_allocs) + fprintf(stderr, "Some of the malloc calls returned non-null: %d\n", + num_allocs - zero_results); + for (int j = 0; j < num_allocs; j++) { + free(allocs[j]); + } + } +} + +// CHECK_MAY_RETURN_1: allocating 128 times +// CHECK_MAY_RETURN_1: Some of the malloc calls returned non-null: 128 +// CHECK_MAY_RETURN_1: allocating 256 times +// CHECK_MAY_RETURN_1: Some of the malloc calls returned null: +// CHECK_MAY_RETURN_1: Some of the malloc calls returned non-null: +// CHECK_MAY_RETURN_1: allocating 512 times +// CHECK_MAY_RETURN_1: Some of the malloc calls returned null: +// CHECK_MAY_RETURN_1: Some of the malloc calls returned non-null: + +// CHECK_MAY_RETURN_0: allocating 128 times +// CHECK_MAY_RETURN_0: Some of the malloc calls returned non-null: 128 +// CHECK_MAY_RETURN_0: allocating 256 times +// CHECK_MAY_RETURN_0: allocator is terminating the process instead of returning diff --git a/test/sanitizer_common/TestCases/options-help.cc b/test/sanitizer_common/TestCases/options-help.cc new file mode 100644 index 000000000000..eaa04a494be4 --- /dev/null +++ b/test/sanitizer_common/TestCases/options-help.cc @@ -0,0 +1,8 @@ +// RUN: %clangxx -O0 %s -o %t +// RUN: %tool_options=help=1 %run %t 2>&1 | FileCheck %s + +int main() { +} + +// CHECK: Available flags for {{.*}}Sanitizer: +// CHECK: handle_segv diff --git a/test/sanitizer_common/TestCases/options-include.cc b/test/sanitizer_common/TestCases/options-include.cc new file mode 100644 index 000000000000..ae8995164853 --- /dev/null +++ b/test/sanitizer_common/TestCases/options-include.cc @@ -0,0 +1,21 @@ +// RUN: %clangxx -O0 %s -o %t +// RUN: echo -e "symbolize=1\ninclude='%t.options2.txt'" >%t.options1.txt +// RUN: echo -e "help=1\n" >%t.options2.txt +// RUN: cat %t.options1.txt +// RUN: cat %t.options2.txt +// RUN: %tool_options="help=0:include='%t.options1.txt'" %run %t 2>&1 | tee %t.out +// RUN: FileCheck %s --check-prefix=CHECK-VERBOSITY1 <%t.out +// RUN: %tool_options="include='%t.options1.txt',help=0" %run %t 2>&1 | tee %t.out +// RUN: FileCheck %s --check-prefix=CHECK-VERBOSITY0 <%t.out +// RUN: %tool_options="include='%t.options-not-found.txt',help=1" not %run %t 2>&1 | tee %t.out +// RUN: FileCheck %s --check-prefix=CHECK-NOT-FOUND < %t.out + +#include <stdio.h> + +int main() { + fprintf(stderr, "done\n"); +} + +// CHECK-VERBOSITY1: Available flags for +// CHECK-VERBOSITY0-NOT: Available flags for +// CHECK-NOT-FOUND: Failed to read options from diff --git a/test/sanitizer_common/TestCases/options-invalid.cc b/test/sanitizer_common/TestCases/options-invalid.cc new file mode 100644 index 000000000000..3c261405c992 --- /dev/null +++ b/test/sanitizer_common/TestCases/options-invalid.cc @@ -0,0 +1,15 @@ +// RUN: %clangxx -O0 %s -o %t +// RUN: %tool_options=invalid_option_name=10,verbosity=1 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-V1 +// RUN: %tool_options=invalid_option_name=10 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-V0 + +#include <stdio.h> + +int main() { + fprintf(stderr, "done\n"); +} + +// CHECK-V1: WARNING: found 1 unrecognized +// CHECK-V1: invalid_option_name +// CHECK-V0-NOT: WARNING: found 1 unrecognized +// CHECK-V0-NOT: invalid_option_name +// CHECK: done diff --git a/test/tsan/CMakeLists.txt b/test/tsan/CMakeLists.txt index 29c0821b3c5a..5a9542fd76fc 100644 --- a/test/tsan/CMakeLists.txt +++ b/test/tsan/CMakeLists.txt @@ -1,4 +1,5 @@ set(TSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) +list(APPEND TSAN_TEST_DEPS GotsanRuntimeCheck) if(NOT COMPILER_RT_STANDALONE_BUILD) list(APPEND TSAN_TEST_DEPS tsan) endif() diff --git a/test/tsan/aligned_vs_unaligned_race.cc b/test/tsan/aligned_vs_unaligned_race.cc index f82542ed2b85..5c1189f34a4b 100644 --- a/test/tsan/aligned_vs_unaligned_race.cc +++ b/test/tsan/aligned_vs_unaligned_race.cc @@ -1,34 +1,35 @@ -// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s +// RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s // Race between an aligned access and an unaligned access, which // touches the same memory region. -// This is a real race which is not detected by tsan. -// https://code.google.com/p/thread-sanitizer/issues/detail?id=17 -#include <pthread.h> -#include <stdio.h> +#include "test.h" #include <stdint.h> uint64_t Global[2]; void *Thread1(void *x) { Global[1]++; + barrier_wait(&barrier); return NULL; } void *Thread2(void *x) { + barrier_wait(&barrier); char *p1 = reinterpret_cast<char *>(&Global[0]); - uint64_t *p4 = reinterpret_cast<uint64_t *>(p1 + 1); - (*p4)++; + struct __attribute__((packed, aligned(1))) u_uint64_t { uint64_t val; }; + u_uint64_t *p4 = reinterpret_cast<u_uint64_t *>(p1 + 1); + (*p4).val++; return NULL; } int main() { + barrier_init(&barrier, 2); pthread_t t[2]; pthread_create(&t[0], NULL, Thread1, NULL); pthread_create(&t[1], NULL, Thread2, NULL); pthread_join(t[0], NULL); pthread_join(t[1], NULL); printf("Pass\n"); - // CHECK-NOT: ThreadSanitizer: data race + // CHECK: ThreadSanitizer: data race // CHECK: Pass return 0; } diff --git a/test/tsan/annotate_happens_before.cc b/test/tsan/annotate_happens_before.cc new file mode 100644 index 000000000000..011661699a7a --- /dev/null +++ b/test/tsan/annotate_happens_before.cc @@ -0,0 +1,57 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s +#include "test.h" + +/* +Annotations usage example. + +Tsan does not see synchronization in barrier_wait. +ANNOTATE_HAPPENS_BEFORE/AFTER communicate the synchronization to tsan +and prevent the race report. + +If the compiler does not support __has_feature macro, then you can build with +CFLAGS="-fsanitize=thread -DTHREAD_SANITIZER" and then use +#ifdef THREAD_SANITIZER to enabled annotations. +*/ + +#if defined(__has_feature) && __has_feature(thread_sanitizer) +# define ANNOTATE_HAPPENS_BEFORE(addr) \ + AnnotateHappensBefore(__FILE__, __LINE__, (void*)(addr)) +# define ANNOTATE_HAPPENS_AFTER(addr) \ + AnnotateHappensAfter(__FILE__, __LINE__, (void*)(addr)) +extern "C" void AnnotateHappensBefore(const char *f, int l, void *addr); +extern "C" void AnnotateHappensAfter(const char *f, int l, void *addr); +#else +# define ANNOTATE_HAPPENS_BEFORE(addr) +# define ANNOTATE_HAPPENS_AFTER(addr) +#endif + +int Global; + +void *Thread1(void *x) { + barrier_wait(&barrier); + ANNOTATE_HAPPENS_AFTER(&barrier); + Global++; + return NULL; +} + +void *Thread2(void *x) { + Global--; + ANNOTATE_HAPPENS_BEFORE(&barrier); + barrier_wait(&barrier); + return NULL; +} + +int main() { + barrier_init(&barrier, 2); + pthread_t t[2]; + pthread_create(&t[0], NULL, Thread1, NULL); + pthread_create(&t[1], NULL, Thread2, NULL); + pthread_join(t[0], NULL); + pthread_join(t[1], NULL); + fprintf(stderr, "DONE\n"); + return 0; +} + +// CHECK-NOT: WARNING: ThreadSanitizer: data race +// CHECK: DONE + diff --git a/test/tsan/atomic_free.cc b/test/tsan/atomic_free.cc index 1dcf887c41d5..a0d8e426b49f 100644 --- a/test/tsan/atomic_free.cc +++ b/test/tsan/atomic_free.cc @@ -1,17 +1,18 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <unistd.h> +#include "test.h" void *Thread(void *a) { __atomic_fetch_add((int*)a, 1, __ATOMIC_SEQ_CST); + barrier_wait(&barrier); return 0; } int main() { + barrier_init(&barrier, 2); int *a = new int(0); pthread_t t; pthread_create(&t, 0, Thread, a); - sleep(1); + barrier_wait(&barrier); delete a; pthread_join(t, 0); } diff --git a/test/tsan/atomic_free2.cc b/test/tsan/atomic_free2.cc index c50be6bba940..4a9f268a4008 100644 --- a/test/tsan/atomic_free2.cc +++ b/test/tsan/atomic_free2.cc @@ -1,18 +1,19 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <unistd.h> +#include "test.h" void *Thread(void *a) { - sleep(1); + barrier_wait(&barrier); __atomic_fetch_add((int*)a, 1, __ATOMIC_SEQ_CST); return 0; } int main() { + barrier_init(&barrier, 2); int *a = new int(0); pthread_t t; pthread_create(&t, 0, Thread, a); delete a; + barrier_wait(&barrier); pthread_join(t, 0); } diff --git a/test/tsan/atomic_norace.cc b/test/tsan/atomic_norace.cc index d9ccda58883c..625109b1fe63 100644 --- a/test/tsan/atomic_norace.cc +++ b/test/tsan/atomic_norace.cc @@ -1,7 +1,5 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" const int kTestCount = 4; typedef long long T; @@ -36,7 +34,8 @@ void *Thread(void *p) { for (int i = 0; i < kTestCount; i++) { Test(i, &atomics[i], false); } - sleep(2); + barrier_wait(&barrier); + barrier_wait(&barrier); for (int i = 0; i < kTestCount; i++) { fprintf(stderr, "Test %d reverse\n", i); Test(i, &atomics[kTestCount + i], false); @@ -45,9 +44,10 @@ void *Thread(void *p) { } int main() { + barrier_init(&barrier, 2); pthread_t t; pthread_create(&t, 0, Thread, 0); - sleep(1); + barrier_wait(&barrier); for (int i = 0; i < kTestCount; i++) { fprintf(stderr, "Test %d\n", i); Test(i, &atomics[i], true); @@ -55,6 +55,7 @@ int main() { for (int i = 0; i < kTestCount; i++) { Test(i, &atomics[kTestCount + i], true); } + barrier_wait(&barrier); pthread_join(t, 0); } diff --git a/test/tsan/atomic_race.cc b/test/tsan/atomic_race.cc index 9cee8ed8272f..5a0317c4acfa 100644 --- a/test/tsan/atomic_race.cc +++ b/test/tsan/atomic_race.cc @@ -1,7 +1,5 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <unistd.h> -#include <stdio.h> +#include "test.h" const int kTestCount = 4; typedef long long T; @@ -36,7 +34,8 @@ void *Thread(void *p) { for (int i = 0; i < kTestCount; i++) { Test(i, &atomics[i], false); } - sleep(4); + barrier_wait(&barrier); + barrier_wait(&barrier); for (int i = 0; i < kTestCount; i++) { fprintf(stderr, "Test %d reverse\n", i); Test(i, &atomics[kTestCount + i], false); @@ -45,9 +44,10 @@ void *Thread(void *p) { } int main() { + barrier_init(&barrier, 2); pthread_t t; pthread_create(&t, 0, Thread, 0); - sleep(1); + barrier_wait(&barrier); for (int i = 0; i < kTestCount; i++) { fprintf(stderr, "Test %d\n", i); Test(i, &atomics[i], true); @@ -55,6 +55,7 @@ int main() { for (int i = 0; i < kTestCount; i++) { Test(i, &atomics[kTestCount + i], true); } + barrier_wait(&barrier); pthread_join(t, 0); } diff --git a/test/tsan/atomic_stack.cc b/test/tsan/atomic_stack.cc index 7e3176f8e784..979eaea8b699 100644 --- a/test/tsan/atomic_stack.cc +++ b/test/tsan/atomic_stack.cc @@ -1,21 +1,22 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <unistd.h> +#include "test.h" int Global; void *Thread1(void *x) { - sleep(1); + barrier_wait(&barrier); __atomic_fetch_add(&Global, 1, __ATOMIC_RELAXED); return NULL; } void *Thread2(void *x) { Global++; + barrier_wait(&barrier); return NULL; } int main() { + barrier_init(&barrier, 2); pthread_t t[2]; pthread_create(&t[0], NULL, Thread1, NULL); pthread_create(&t[1], NULL, Thread2, NULL); diff --git a/test/tsan/benign_race.cc b/test/tsan/benign_race.cc index b6cba19aa96e..2f72fe1860d0 100644 --- a/test/tsan/benign_race.cc +++ b/test/tsan/benign_race.cc @@ -1,7 +1,5 @@ // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" int Global; int WTFGlobal; @@ -18,10 +16,12 @@ void WTFAnnotateBenignRaceSized(const char *f, int l, void *Thread(void *x) { Global = 42; WTFGlobal = 142; + barrier_wait(&barrier); return 0; } int main() { + barrier_init(&barrier, 2); AnnotateBenignRaceSized(__FILE__, __LINE__, &Global, sizeof(Global), "Race on Global"); WTFAnnotateBenignRaceSized(__FILE__, __LINE__, @@ -29,7 +29,7 @@ int main() { "Race on WTFGlobal"); pthread_t t; pthread_create(&t, 0, Thread, 0); - sleep(1); + barrier_wait(&barrier); Global = 43; WTFGlobal = 143; pthread_join(t, 0); diff --git a/test/tsan/blacklist2.cc b/test/tsan/blacklist2.cc index 1092561e55bb..629b58821bfe 100644 --- a/test/tsan/blacklist2.cc +++ b/test/tsan/blacklist2.cc @@ -5,14 +5,12 @@ // RUN: %clangxx_tsan -O1 %s -fsanitize-blacklist=%t.blacklist -o %t // RUN: %deflake %run %t 2>&1 | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" int Global; void *Thread1(void *x) { - sleep(1); + barrier_wait(&barrier); // CHECK: ThreadSanitizer: data race // CHECK: Write of size 4 // CHECK: #0 Thread1{{.*}}blacklist2.cc:[[@LINE+1]] @@ -35,10 +33,12 @@ void *Blacklisted_Thread2(void *x) { Global--; // CHECK: #2 Blacklisted_Thread2{{.*}}blacklist2.cc:[[@LINE+1]] CallTouchGlobal(); + barrier_wait(&barrier); return NULL; } int main() { + barrier_init(&barrier, 2); pthread_t t[2]; pthread_create(&t[0], NULL, Thread1, NULL); pthread_create(&t[1], NULL, Blacklisted_Thread2, NULL); diff --git a/test/tsan/cond_cancel.c b/test/tsan/cond_cancel.c index 397cad4b1838..e744570b12fc 100644 --- a/test/tsan/cond_cancel.c +++ b/test/tsan/cond_cancel.c @@ -2,10 +2,7 @@ // CHECK-NOT: WARNING // CHECK: OK -#include <stdio.h> -#include <stdlib.h> -#include <pthread.h> -#include <unistd.h> +#include "test.h" pthread_mutex_t m; pthread_cond_t c; @@ -14,6 +11,7 @@ int x; void *thr1(void *p) { pthread_mutex_lock(&m); pthread_cleanup_push((void(*)(void *arg))pthread_mutex_unlock, &m); + barrier_wait(&barrier); while (x == 0) pthread_cond_wait(&c, &m); pthread_cleanup_pop(1); @@ -21,12 +19,15 @@ void *thr1(void *p) { } int main() { + barrier_init(&barrier, 2); + pthread_t th; pthread_mutex_init(&m, 0); pthread_cond_init(&c, 0); pthread_create(&th, 0, thr1, 0); + barrier_wait(&barrier); sleep(1); // let it block on cond var pthread_cancel(th); diff --git a/test/tsan/cond_race.cc b/test/tsan/cond_race.cc index fa42fafca4d2..52654f16e85c 100644 --- a/test/tsan/cond_race.cc +++ b/test/tsan/cond_race.cc @@ -3,10 +3,7 @@ // CHECK: ThreadSanitizer: data race // CHECK: pthread_cond_signal -#include <stdio.h> -#include <stdlib.h> -#include <pthread.h> -#include <unistd.h> +#include "test.h" struct Ctx { pthread_mutex_t m; @@ -20,10 +17,12 @@ void *thr(void *p) { c->done = true; pthread_mutex_unlock(&c->m); pthread_cond_signal(&c->c); + barrier_wait(&barrier); return 0; } int main() { + barrier_init(&barrier, 2); Ctx *c = new Ctx(); pthread_mutex_init(&c->m, 0); pthread_cond_init(&c->c, 0); @@ -33,8 +32,8 @@ int main() { while (!c->done) pthread_cond_wait(&c->c, &c->m); pthread_mutex_unlock(&c->m); - // w/o this sleep, it can be reported as use-after-free - sleep(1); + // otherwise it can be reported as use-after-free + barrier_wait(&barrier); delete c; pthread_join(th, 0); } diff --git a/test/tsan/deadlock_detector_stress_test.cc b/test/tsan/deadlock_detector_stress_test.cc index 53624782e07b..e02a9123f5af 100644 --- a/test/tsan/deadlock_detector_stress_test.cc +++ b/test/tsan/deadlock_detector_stress_test.cc @@ -7,12 +7,9 @@ // RUN: TSAN_OPTIONS=detect_deadlocks=1 %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-RD // RUN: %clangxx_tsan %s -o %t -DLockType=PthreadRecursiveMutex // RUN: TSAN_OPTIONS=detect_deadlocks=1 %deflake %run %t | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-REC -#include <pthread.h> +#include "test.h" #undef NDEBUG #include <assert.h> -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> #include <new> #ifndef LockType @@ -224,7 +221,7 @@ class LockTest { fprintf(stderr, "Starting Test5\n"); // CHECK: Starting Test5 Init(5); - RunThreads(&LockTest::Lock_0_1, &LockTest::Lock_1_0); + RunThreads(&LockTest::Lock_0_1<true>, &LockTest::Lock_1_0<true>); // CHECK: WARNING: ThreadSanitizer: lock-order-inversion // CHECK: Cycle in lock order graph: [[M1:M[0-9]+]] ({{.*}}) => [[M2:M[0-9]+]] ({{.*}}) => [[M1]] // CHECK: Mutex [[M2]] acquired here while holding mutex [[M1]] in thread [[T1:T[0-9]+]] @@ -503,8 +500,21 @@ class LockTest { private: void Lock2(size_t l1, size_t l2) { L(l1); L(l2); U(l2); U(l1); } - void Lock_0_1() { Lock2(0, 1); } - void Lock_1_0() { sleep(1); Lock2(1, 0); } + + template<bool wait = false> + void Lock_0_1() { + Lock2(0, 1); + if (wait) + barrier_wait(&barrier); + } + + template<bool wait = false> + void Lock_1_0() { + if (wait) + barrier_wait(&barrier); + Lock2(1, 0); + } + void Lock1_Loop(size_t i, size_t n_iter) { for (size_t it = 0; it < n_iter; it++) { // if ((it & (it - 1)) == 0) fprintf(stderr, "%zd", i); @@ -569,6 +579,7 @@ class LockTest { }; int main(int argc, char **argv) { + barrier_init(&barrier, 2); if (argc > 1) test_number = atoi(argv[1]); if (argc > 2) diff --git a/test/tsan/deep_stack1.cc b/test/tsan/deep_stack1.cc index 1d00a0e856d5..39185efee7a9 100644 --- a/test/tsan/deep_stack1.cc +++ b/test/tsan/deep_stack1.cc @@ -1,8 +1,6 @@ // RUN: %clangxx_tsan -O1 %s -o %t -DORDER1 && %deflake %run %t | FileCheck %s // RUN: %clangxx_tsan -O1 %s -o %t -DORDER2 && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" volatile int X; volatile int N; @@ -17,13 +15,17 @@ static void foo() { void *Thread(void *p) { #ifdef ORDER1 - sleep(1); + barrier_wait(&barrier); #endif F(); +#ifdef ORDER2 + barrier_wait(&barrier); +#endif return 0; } int main() { + barrier_init(&barrier, 2); N = 50000; F = foo; pthread_t t; @@ -32,9 +34,13 @@ int main() { pthread_attr_setstacksize(&a, N * 256 + (1 << 20)); pthread_create(&t, &a, Thread, 0); #ifdef ORDER2 - sleep(1); + barrier_wait(&barrier); #endif X = 43; +#ifdef ORDER1 + barrier_wait(&barrier); +#endif + pthread_join(t, 0); } diff --git a/test/tsan/fd_close_norace.cc b/test/tsan/fd_close_norace.cc index 7238d64b432b..1b52c20f990c 100644 --- a/test/tsan/fd_close_norace.cc +++ b/test/tsan/fd_close_norace.cc @@ -1,7 +1,5 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> @@ -9,17 +7,19 @@ void *Thread1(void *x) { int f = open("/dev/random", O_RDONLY); close(f); + barrier_wait(&barrier); return NULL; } void *Thread2(void *x) { - sleep(1); + barrier_wait(&barrier); int f = open("/dev/random", O_RDONLY); close(f); return NULL; } int main() { + barrier_init(&barrier, 2); pthread_t t[2]; pthread_create(&t[0], NULL, Thread1, NULL); pthread_create(&t[1], NULL, Thread2, NULL); diff --git a/test/tsan/fd_location.cc b/test/tsan/fd_location.cc index 535329e06409..1861c89cba9b 100644 --- a/test/tsan/fd_location.cc +++ b/test/tsan/fd_location.cc @@ -1,23 +1,23 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" int fds[2]; void *Thread1(void *x) { write(fds[1], "a", 1); + barrier_wait(&barrier); return NULL; } void *Thread2(void *x) { - sleep(1); + barrier_wait(&barrier); close(fds[0]); close(fds[1]); return NULL; } int main() { + barrier_init(&barrier, 2); pipe(fds); pthread_t t[2]; pthread_create(&t[0], NULL, Thread1, NULL); diff --git a/test/tsan/fd_pipe_race.cc b/test/tsan/fd_pipe_race.cc index 88c4ed4aa398..b94893b93691 100644 --- a/test/tsan/fd_pipe_race.cc +++ b/test/tsan/fd_pipe_race.cc @@ -1,23 +1,23 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" int fds[2]; void *Thread1(void *x) { write(fds[1], "a", 1); + barrier_wait(&barrier); return NULL; } void *Thread2(void *x) { - sleep(1); + barrier_wait(&barrier); close(fds[0]); close(fds[1]); return NULL; } int main() { + barrier_init(&barrier, 2); pipe(fds); pthread_t t[2]; pthread_create(&t[0], NULL, Thread1, NULL); diff --git a/test/tsan/fd_stdout_race.cc b/test/tsan/fd_stdout_race.cc index d6a2c7c796f1..fcf8c21300c6 100644 --- a/test/tsan/fd_stdout_race.cc +++ b/test/tsan/fd_stdout_race.cc @@ -1,7 +1,5 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> @@ -9,7 +7,7 @@ int X; void *Thread1(void *x) { - sleep(1); + barrier_wait(&barrier); int f = open("/dev/random", O_RDONLY); char buf; read(f, &buf, 1); @@ -21,10 +19,12 @@ void *Thread1(void *x) { void *Thread2(void *x) { X = 43; write(STDOUT_FILENO, "a", 1); + barrier_wait(&barrier); return NULL; } int main() { + barrier_init(&barrier, 2); pthread_t t[2]; pthread_create(&t[0], NULL, Thread1, NULL); pthread_create(&t[1], NULL, Thread2, NULL); diff --git a/test/tsan/fork_deadlock.cc b/test/tsan/fork_deadlock.cc index cc5b12214cf9..9418800bd336 100644 --- a/test/tsan/fork_deadlock.cc +++ b/test/tsan/fork_deadlock.cc @@ -1,9 +1,6 @@ // RUN: %clangxx_tsan -O1 %s -o %t && TSAN_OPTIONS="atexit_sleep_ms=50" %run %t 2>&1 | FileCheck %s -#include <stdlib.h> -#include <stdio.h> +#include "test.h" #include <errno.h> -#include <pthread.h> -#include <unistd.h> #include <sys/types.h> #include <sys/wait.h> @@ -16,13 +13,14 @@ static void *incrementer(void *p) { } static void *watchdog(void *p) { - sleep(100); + sleep(100); // is not intended to exit fprintf(stderr, "timed out after 100 seconds\n"); exit(1); return 0; } int main() { + barrier_init(&barrier, 2); pthread_t th1, th2; pthread_create(&th1, 0, incrementer, 0); pthread_create(&th2, 0, watchdog, 0); diff --git a/test/tsan/fork_multithreaded.cc b/test/tsan/fork_multithreaded.cc index 5176a14d6a65..3ddb417c7cb5 100644 --- a/test/tsan/fork_multithreaded.cc +++ b/test/tsan/fork_multithreaded.cc @@ -1,19 +1,21 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -check-prefix=CHECK-DIE // RUN: %clangxx_tsan -O1 %s -o %t && TSAN_OPTIONS="die_after_fork=0" %run %t 2>&1 | FileCheck %s -check-prefix=CHECK-NODIE -#include <stdlib.h> -#include <stdio.h> +#include "test.h" #include <errno.h> -#include <pthread.h> -#include <unistd.h> #include <sys/types.h> #include <sys/wait.h> static void *sleeper(void *p) { - sleep(10); + sleep(10); // not intended to exit during test + return 0; +} + +static void *nop(void *p) { return 0; } int main() { + barrier_init(&barrier, 2); pthread_t th; pthread_create(&th, 0, sleeper, 0); switch (fork()) { @@ -23,7 +25,7 @@ int main() { case 0: // child { pthread_t th2; - pthread_create(&th2, 0, sleeper, 0); + pthread_create(&th2, 0, nop, 0); exit(0); break; } diff --git a/test/tsan/free_race.c b/test/tsan/free_race.c index 663d7bcf2eb9..63cee8c4adc5 100644 --- a/test/tsan/free_race.c +++ b/test/tsan/free_race.c @@ -1,12 +1,8 @@ // RUN: %clang_tsan -O1 %s -o %t // RUN: %deflake %run %t | FileCheck %s --check-prefix=CHECK-NOZUPP -// RUN: TSAN_OPTIONS="suppressions=%s.supp print_suppressions=1" %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUPP +// RUN: TSAN_OPTIONS="suppressions='%s.supp' print_suppressions=1" %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-SUPP -#include <pthread.h> -#include <stdlib.h> -#include <stdio.h> -#include <stddef.h> -#include <unistd.h> +#include "test.h" int *mem; pthread_mutex_t mtx; @@ -15,11 +11,12 @@ void *Thread1(void *x) { pthread_mutex_lock(&mtx); free(mem); pthread_mutex_unlock(&mtx); + barrier_wait(&barrier); return NULL; } void *Thread2(void *x) { - sleep(1); + barrier_wait(&barrier); pthread_mutex_lock(&mtx); mem[0] = 42; pthread_mutex_unlock(&mtx); @@ -27,6 +24,7 @@ void *Thread2(void *x) { } int main() { + barrier_init(&barrier, 2); mem = (int*)malloc(100); pthread_mutex_init(&mtx, 0); pthread_t t; diff --git a/test/tsan/global_race.cc b/test/tsan/global_race.cc index e12bb1d220f8..d70bee4a556b 100644 --- a/test/tsan/global_race.cc +++ b/test/tsan/global_race.cc @@ -1,24 +1,23 @@ // RUN: %clangxx_tsan -O1 %s -o %T/global_race.cc.exe && %deflake %run %T/global_race.cc.exe | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <stddef.h> -#include <unistd.h> +#include "test.h" int GlobalData[10]; void *Thread(void *a) { - sleep(1); + barrier_wait(&barrier); GlobalData[2] = 42; return 0; } int main() { + barrier_init(&barrier, 2); // 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, "addr=0x%012lx\n", (unsigned long) GlobalData); pthread_t t; pthread_create(&t, 0, Thread, 0); GlobalData[2] = 43; + barrier_wait(&barrier); pthread_join(t, 0); } diff --git a/test/tsan/global_race2.cc b/test/tsan/global_race2.cc index ac994cc0f4c4..6631008d85a5 100644 --- a/test/tsan/global_race2.cc +++ b/test/tsan/global_race2.cc @@ -1,24 +1,23 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <stddef.h> -#include <unistd.h> +#include "test.h" int x; void *Thread(void *a) { - sleep(1); + barrier_wait(&barrier); x = 1; return 0; } int main() { + barrier_init(&barrier, 2); // 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, "addr2=0x%012lx\n", (unsigned long) &x); pthread_t t; pthread_create(&t, 0, Thread, 0); x = 0; + barrier_wait(&barrier); pthread_join(t, 0); } diff --git a/test/tsan/global_race3.cc b/test/tsan/global_race3.cc index a3222bb3d8cb..e7e9a7fef028 100644 --- a/test/tsan/global_race3.cc +++ b/test/tsan/global_race3.cc @@ -1,8 +1,5 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <stddef.h> -#include <unistd.h> +#include "test.h" namespace XXX { struct YYY { @@ -12,18 +9,20 @@ namespace XXX { } void *Thread(void *a) { - sleep(1); + barrier_wait(&barrier); XXX::YYY::ZZZ[0] = 1; return 0; } int main() { + barrier_init(&barrier, 2); // 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, "addr3=0x%012lx\n", (unsigned long) XXX::YYY::ZZZ); pthread_t t; pthread_create(&t, 0, Thread, 0); XXX::YYY::ZZZ[0] = 0; + barrier_wait(&barrier); pthread_join(t, 0); } diff --git a/test/tsan/halt_on_error.cc b/test/tsan/halt_on_error.cc index 3c55c60a457e..e55454b57c1d 100644 --- a/test/tsan/halt_on_error.cc +++ b/test/tsan/halt_on_error.cc @@ -1,21 +1,21 @@ // RUN: %clang_tsan -O1 %s -o %t && TSAN_OPTIONS="$TSAN_OPTIONS halt_on_error=1" %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" int X; void *Thread(void *x) { - sleep(1); + barrier_wait(&barrier); X = 42; return 0; } int main() { + barrier_init(&barrier, 2); fprintf(stderr, "BEFORE\n"); pthread_t t; pthread_create(&t, 0, Thread, 0); X = 43; + barrier_wait(&barrier); pthread_join(t, 0); fprintf(stderr, "AFTER\n"); return 0; diff --git a/test/tsan/ignore_free.cc b/test/tsan/ignore_free.cc index 1df6dce2f5e0..bb6c6ee14364 100644 --- a/test/tsan/ignore_free.cc +++ b/test/tsan/ignore_free.cc @@ -1,8 +1,5 @@ // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -#include <pthread.h> -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" extern "C" { void AnnotateIgnoreReadsBegin(const char *f, int l); @@ -13,14 +10,16 @@ void AnnotateIgnoreWritesEnd(const char *f, int l); void *Thread(void *p) { *(int*)p = 42; + barrier_wait(&barrier); return 0; } int main() { + barrier_init(&barrier, 2); int *p = new int(0); pthread_t t; pthread_create(&t, 0, Thread, p); - sleep(1); + barrier_wait(&barrier); AnnotateIgnoreReadsBegin(__FILE__, __LINE__); AnnotateIgnoreWritesBegin(__FILE__, __LINE__); free(p); diff --git a/test/tsan/ignore_lib0.cc b/test/tsan/ignore_lib0.cc index fe1a35558015..63c9340e99ac 100644 --- a/test/tsan/ignore_lib0.cc +++ b/test/tsan/ignore_lib0.cc @@ -3,7 +3,7 @@ // RUN: echo running w/o suppressions: // RUN: LD_LIBRARY_PATH=%T${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} %deflake %run %t | FileCheck %s --check-prefix=CHECK-NOSUPP // RUN: echo running with suppressions: -// RUN: LD_LIBRARY_PATH=%T${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-WITHSUPP +// RUN: LD_LIBRARY_PATH=%T${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} TSAN_OPTIONS="$TSAN_OPTIONS suppressions='%s.supp'" %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-WITHSUPP // Tests that interceptors coming from a library specified in called_from_lib // suppression are ignored. diff --git a/test/tsan/ignore_lib1.cc b/test/tsan/ignore_lib1.cc index 30a9994b94f5..ef1f973795ed 100644 --- a/test/tsan/ignore_lib1.cc +++ b/test/tsan/ignore_lib1.cc @@ -3,7 +3,7 @@ // RUN: echo running w/o suppressions: // RUN: %deflake %run %t | FileCheck %s --check-prefix=CHECK-NOSUPP // RUN: echo running with suppressions: -// RUN: TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-WITHSUPP +// RUN: TSAN_OPTIONS="$TSAN_OPTIONS suppressions='%s.supp'" %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-WITHSUPP // Tests that interceptors coming from a dynamically loaded library specified // in called_from_lib suppression are ignored. diff --git a/test/tsan/ignore_lib2.cc b/test/tsan/ignore_lib2.cc index 23a0872feabe..ad3107cf53a2 100644 --- a/test/tsan/ignore_lib2.cc +++ b/test/tsan/ignore_lib2.cc @@ -1,7 +1,7 @@ // RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib2_0.so // RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib2_1.so // RUN: %clangxx_tsan -O1 %s -o %t -// RUN: TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %deflake %run %t | FileCheck %s +// RUN: TSAN_OPTIONS="$TSAN_OPTIONS suppressions='%s.supp'" %deflake %run %t | FileCheck %s // Tests that called_from_lib suppression matched against 2 libraries // causes program crash (this is not supported). diff --git a/test/tsan/ignore_lib3.cc b/test/tsan/ignore_lib3.cc index 137109ea6cb4..96bf313f43a1 100644 --- a/test/tsan/ignore_lib3.cc +++ b/test/tsan/ignore_lib3.cc @@ -1,6 +1,6 @@ // RUN: %clangxx_tsan -O1 %s -DLIB -fPIC -fno-sanitize=thread -shared -o %T/libignore_lib3.so // RUN: %clangxx_tsan -O1 %s -o %t -// RUN: TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %deflake %run %t | FileCheck %s +// RUN: TSAN_OPTIONS="$TSAN_OPTIONS suppressions='%s.supp'" %deflake %run %t | FileCheck %s // Tests that unloading of a library matched against called_from_lib suppression // causes program crash (this is not supported). diff --git a/test/tsan/ignore_malloc.cc b/test/tsan/ignore_malloc.cc index 0f1fb5e3dfdc..1f633f062d0e 100644 --- a/test/tsan/ignore_malloc.cc +++ b/test/tsan/ignore_malloc.cc @@ -1,8 +1,5 @@ // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -#include <pthread.h> -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" extern "C" { void AnnotateIgnoreReadsBegin(const char *f, int l); @@ -16,7 +13,7 @@ int *g; void *Thread(void *a) { int *p = 0; while ((p = __atomic_load_n(&g, __ATOMIC_RELAXED)) == 0) - usleep(100); + usleep(100); // spin-wait *p = 42; return 0; } diff --git a/test/tsan/ignore_race.cc b/test/tsan/ignore_race.cc index c6e067fabec0..cc33b66b27d4 100644 --- a/test/tsan/ignore_race.cc +++ b/test/tsan/ignore_race.cc @@ -1,7 +1,5 @@ // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" int Global; @@ -16,13 +14,15 @@ void *Thread(void *x) { Global = 42; AnnotateIgnoreReadsEnd(__FILE__, __LINE__); AnnotateIgnoreWritesEnd(__FILE__, __LINE__); + barrier_wait(&barrier); return 0; } int main() { + barrier_init(&barrier, 2); pthread_t t; pthread_create(&t, 0, Thread, 0); - sleep(1); + barrier_wait(&barrier); Global = 43; pthread_join(t, 0); printf("OK\n"); diff --git a/test/tsan/inlined_memcpy_race.cc b/test/tsan/inlined_memcpy_race.cc index a95576a83c9a..e3ed07abcf89 100644 --- a/test/tsan/inlined_memcpy_race.cc +++ b/test/tsan/inlined_memcpy_race.cc @@ -1,24 +1,23 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stddef.h> -#include <stdio.h> +#include "test.h" #include <string.h> -#include <unistd.h> int x[4], z[4]; void *MemCpyThread(void *a) { memcpy((int*)a, z, 16); + barrier_wait(&barrier); return NULL; } void *MemSetThread(void *a) { - sleep(1); + barrier_wait(&barrier); memset((int*)a, 0, 16); return NULL; } int main() { + barrier_init(&barrier, 2); pthread_t t[2]; // Race on x between memcpy and memset pthread_create(&t[0], NULL, MemCpyThread, x); diff --git a/test/tsan/inlined_memcpy_race2.cc b/test/tsan/inlined_memcpy_race2.cc index 63b560f02269..37414ba5d3db 100644 --- a/test/tsan/inlined_memcpy_race2.cc +++ b/test/tsan/inlined_memcpy_race2.cc @@ -1,24 +1,23 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stddef.h> -#include <stdio.h> +#include "test.h" #include <string.h> -#include <unistd.h> int y[4], z[4]; void *MemMoveThread(void *a) { memmove((int*)a, z, 16); + barrier_wait(&barrier); return NULL; } void *MemSetThread(void *a) { - sleep(1); + barrier_wait(&barrier); memset((int*)a, 0, 16); return NULL; } int main() { + barrier_init(&barrier, 2); pthread_t t[2]; // Race on y between memmove and memset pthread_create(&t[0], NULL, MemMoveThread, y); diff --git a/test/tsan/java.h b/test/tsan/java.h index d986d08be060..35fdbc1e7bb1 100644 --- a/test/tsan/java.h +++ b/test/tsan/java.h @@ -1,7 +1,4 @@ -#include <pthread.h> -#include <stdlib.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" extern "C" { typedef unsigned long jptr; // NOLINT @@ -18,4 +15,7 @@ void __tsan_java_mutex_read_lock(jptr addr); void __tsan_java_mutex_read_unlock(jptr addr); void __tsan_java_mutex_lock_rec(jptr addr, int rec); int __tsan_java_mutex_unlock_rec(jptr addr); +int __tsan_java_acquire(jptr addr); +int __tsan_java_release(jptr addr); +int __tsan_java_release_store(jptr addr); } diff --git a/test/tsan/java_finalizer.cc b/test/tsan/java_finalizer.cc index d5c6a22d1e16..acbbf08ad711 100644 --- a/test/tsan/java_finalizer.cc +++ b/test/tsan/java_finalizer.cc @@ -2,13 +2,14 @@ #include "java.h" void *Thread(void *p) { - sleep(1); + barrier_wait(&barrier); __tsan_java_finalize(); *(int*)p = 42; return 0; } int main() { + barrier_init(&barrier, 2); int const kHeapSize = 1024 * 1024; jptr jheap = (jptr)malloc(kHeapSize + 8) + 8; __tsan_java_init(jheap, kHeapSize); @@ -17,6 +18,7 @@ int main() { pthread_t th; pthread_create(&th, 0, Thread, (void*)jheap); *(int*)jheap = 43; + barrier_wait(&barrier); pthread_join(th, 0); __tsan_java_free(jheap, kBlockSize); fprintf(stderr, "DONE\n"); diff --git a/test/tsan/java_lock.cc b/test/tsan/java_lock.cc index 36a0f8b7bff3..f1720529523c 100644 --- a/test/tsan/java_lock.cc +++ b/test/tsan/java_lock.cc @@ -1,12 +1,11 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s #include "java.h" -#include <unistd.h> jptr varaddr; jptr lockaddr; void *Thread(void *p) { - sleep(1); + barrier_wait(&barrier); __tsan_java_mutex_lock(lockaddr); *(int*)varaddr = 42; __tsan_java_mutex_unlock(lockaddr); @@ -14,6 +13,7 @@ void *Thread(void *p) { } int main() { + barrier_init(&barrier, 2); int const kHeapSize = 1024 * 1024; jptr jheap = (jptr)malloc(kHeapSize + 8) + 8; __tsan_java_init(jheap, kHeapSize); @@ -26,6 +26,7 @@ int main() { __tsan_java_mutex_lock(lockaddr); *(int*)varaddr = 43; __tsan_java_mutex_unlock(lockaddr); + barrier_wait(&barrier); pthread_join(th, 0); __tsan_java_free(jheap, kBlockSize); fprintf(stderr, "DONE\n"); diff --git a/test/tsan/java_lock_move.cc b/test/tsan/java_lock_move.cc index 19c3e35d6633..fe5491dc2aa0 100644 --- a/test/tsan/java_lock_move.cc +++ b/test/tsan/java_lock_move.cc @@ -7,7 +7,7 @@ jptr varaddr2; jptr lockaddr2; void *Thread(void *p) { - sleep(1); + barrier_wait(&barrier); __tsan_java_mutex_lock(lockaddr2); *(int*)varaddr2 = 42; __tsan_java_mutex_unlock(lockaddr2); @@ -15,6 +15,7 @@ void *Thread(void *p) { } int main() { + barrier_init(&barrier, 2); int const kHeapSize = 1024 * 1024; jptr jheap = (jptr)malloc(kHeapSize + 8) + 8; __tsan_java_init(jheap, kHeapSize); @@ -31,6 +32,7 @@ int main() { *(int*)varaddr = 43; __tsan_java_mutex_unlock(lockaddr); __tsan_java_move(varaddr, varaddr2, kBlockSize); + barrier_wait(&barrier); pthread_join(th, 0); __tsan_java_free(varaddr2, kBlockSize); printf("DONE\n"); diff --git a/test/tsan/java_lock_rec.cc b/test/tsan/java_lock_rec.cc index 2b0ab0eb92d0..f0bf40196e9f 100644 --- a/test/tsan/java_lock_rec.cc +++ b/test/tsan/java_lock_rec.cc @@ -1,6 +1,5 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s #include "java.h" -#include <unistd.h> jptr varaddr; jptr lockaddr; @@ -14,7 +13,8 @@ void *Thread(void *p) { printf("FAILED 0 rec=%d\n", rec); exit(1); } - sleep(2); + barrier_wait(&barrier); + barrier_wait(&barrier); __tsan_java_mutex_lock_rec(lockaddr, rec); if (*(int*)varaddr != 43) { printf("FAILED 3 var=%d\n", *(int*)varaddr); @@ -26,6 +26,7 @@ void *Thread(void *p) { } int main() { + barrier_init(&barrier, 2); int const kHeapSize = 1024 * 1024; jptr jheap = (jptr)malloc(kHeapSize + 8) + 8; __tsan_java_init(jheap, kHeapSize); @@ -36,7 +37,7 @@ int main() { lockaddr = jheap + 8; pthread_t th; pthread_create(&th, 0, Thread, 0); - sleep(1); + barrier_wait(&barrier); __tsan_java_mutex_lock(lockaddr); if (*(int*)varaddr != 42) { printf("FAILED 1 var=%d\n", *(int*)varaddr); @@ -44,6 +45,7 @@ int main() { } *(int*)varaddr = 43; __tsan_java_mutex_unlock(lockaddr); + barrier_wait(&barrier); pthread_join(th, 0); __tsan_java_free(jheap, kBlockSize); printf("DONE\n"); diff --git a/test/tsan/java_lock_rec_race.cc b/test/tsan/java_lock_rec_race.cc index 841aa396360d..3da8ad076990 100644 --- a/test/tsan/java_lock_rec_race.cc +++ b/test/tsan/java_lock_rec_race.cc @@ -1,6 +1,5 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s #include "java.h" -#include <unistd.h> jptr varaddr; jptr lockaddr; @@ -15,7 +14,8 @@ void *Thread(void *p) { exit(1); } *(int*)varaddr = 42; - sleep(2); + barrier_wait(&barrier); + barrier_wait(&barrier); __tsan_java_mutex_lock_rec(lockaddr, rec); __tsan_java_mutex_unlock(lockaddr); __tsan_java_mutex_unlock(lockaddr); @@ -24,6 +24,7 @@ void *Thread(void *p) { } int main() { + barrier_init(&barrier, 2); int const kHeapSize = 1024 * 1024; jptr jheap = (jptr)malloc(kHeapSize + 8) + 8; __tsan_java_init(jheap, kHeapSize); @@ -34,10 +35,11 @@ int main() { lockaddr = jheap + 8; pthread_t th; pthread_create(&th, 0, Thread, 0); - sleep(1); + barrier_wait(&barrier); __tsan_java_mutex_lock(lockaddr); *(int*)varaddr = 43; __tsan_java_mutex_unlock(lockaddr); + barrier_wait(&barrier); pthread_join(th, 0); __tsan_java_free(jheap, kBlockSize); printf("DONE\n"); diff --git a/test/tsan/java_move_overlap.cc b/test/tsan/java_move_overlap.cc index 12955b4ba0de..7ed98ef1a210 100644 --- a/test/tsan/java_move_overlap.cc +++ b/test/tsan/java_move_overlap.cc @@ -13,7 +13,7 @@ jptr lockaddr1_new; jptr lockaddr2_new; void *Thread(void *p) { - sleep(1); + barrier_wait(&barrier); __tsan_java_mutex_lock(lockaddr1_new); *(char*)varaddr1_new = 43; __tsan_java_mutex_unlock(lockaddr1_new); @@ -24,6 +24,7 @@ void *Thread(void *p) { } int main(int argc, char **argv) { + barrier_init(&barrier, 2); int const kHeapSize = 1024 * 1024; void *jheap = malloc(kHeapSize); jheap = (char*)jheap + 8; @@ -62,6 +63,7 @@ int main(int argc, char **argv) { __tsan_java_mutex_unlock(lockaddr2_old); __tsan_java_move(varaddr1_old, varaddr1_new, kBlockSize); + barrier_wait(&barrier); pthread_join(th, 0); __tsan_java_free(varaddr1_new, kBlockSize); printf("DONE\n"); diff --git a/test/tsan/java_move_overlap_race.cc b/test/tsan/java_move_overlap_race.cc index 2b3769be6117..874b90b26341 100644 --- a/test/tsan/java_move_overlap_race.cc +++ b/test/tsan/java_move_overlap_race.cc @@ -9,13 +9,14 @@ jptr varaddr1_new; jptr varaddr2_new; void *Thread(void *p) { - sleep(1); + barrier_wait(&barrier); *(int*)varaddr1_new = 43; *(int*)varaddr2_new = 43; return 0; } int main(int argc, char **argv) { + barrier_init(&barrier, 2); int const kHeapSize = 1024 * 1024; void *jheap = malloc(kHeapSize); jheap = (char*)jheap + 8; @@ -42,6 +43,7 @@ int main(int argc, char **argv) { *(int*)varaddr2_old = 43; __tsan_java_move(varaddr1_old, varaddr1_new, kBlockSize); + barrier_wait(&barrier); pthread_join(th, 0); __tsan_java_free(varaddr1_new, kBlockSize); printf("DONE\n"); diff --git a/test/tsan/java_race_move.cc b/test/tsan/java_race_move.cc index 8a51be92aa10..6d1b092160e0 100644 --- a/test/tsan/java_race_move.cc +++ b/test/tsan/java_race_move.cc @@ -5,12 +5,13 @@ jptr varaddr; jptr varaddr2; void *Thread(void *p) { - sleep(1); + barrier_wait(&barrier); *(int*)varaddr2 = 42; return 0; } int main() { + barrier_init(&barrier, 2); int const kHeapSize = 1024 * 1024; jptr jheap = (jptr)malloc(kHeapSize + 8) + 8; __tsan_java_init(jheap, kHeapSize); @@ -23,6 +24,7 @@ int main() { pthread_create(&th, 0, Thread, 0); *(int*)varaddr = 43; __tsan_java_move(varaddr, varaddr2, kBlockSize); + barrier_wait(&barrier); pthread_join(th, 0); __tsan_java_free(varaddr2, kBlockSize); fprintf(stderr, "DONE\n"); diff --git a/test/tsan/java_rwlock.cc b/test/tsan/java_rwlock.cc index b03afa6e092d..a4cc92a13635 100644 --- a/test/tsan/java_rwlock.cc +++ b/test/tsan/java_rwlock.cc @@ -1,12 +1,11 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s #include "java.h" -#include <unistd.h> jptr varaddr; jptr lockaddr; void *Thread(void *p) { - sleep(1); + barrier_wait(&barrier); __tsan_java_mutex_read_lock(lockaddr); *(int*)varaddr = 42; __tsan_java_mutex_read_unlock(lockaddr); @@ -14,6 +13,7 @@ void *Thread(void *p) { } int main() { + barrier_init(&barrier, 2); int const kHeapSize = 1024 * 1024; jptr jheap = (jptr)malloc(kHeapSize + 8) + 8; __tsan_java_init(jheap, kHeapSize); @@ -26,6 +26,7 @@ int main() { __tsan_java_mutex_lock(lockaddr); *(int*)varaddr = 43; __tsan_java_mutex_unlock(lockaddr); + barrier_wait(&barrier); pthread_join(th, 0); __tsan_java_free(jheap, kBlockSize); printf("DONE\n"); diff --git a/test/tsan/java_volatile.cc b/test/tsan/java_volatile.cc new file mode 100644 index 000000000000..885b4f241712 --- /dev/null +++ b/test/tsan/java_volatile.cc @@ -0,0 +1,42 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s +#include "java.h" + +jptr varaddr; +jptr lockaddr; + +void *Thread(void *p) { + while (__atomic_load_n((int*)lockaddr, __ATOMIC_RELAXED) == 0) + usleep(1000); // spin-wait + __tsan_java_acquire(lockaddr); + *(int*)varaddr = 42; + return 0; +} + +int main() { + barrier_init(&barrier, 2); + int const kHeapSize = 1024 * 1024; + jptr jheap = (jptr)malloc(kHeapSize + 8) + 8; + __tsan_java_init(jheap, kHeapSize); + const int kBlockSize = 16; + __tsan_java_alloc(jheap, kBlockSize); + varaddr = jheap; + lockaddr = jheap + 8; + pthread_t th; + pthread_create(&th, 0, Thread, 0); + *(int*)varaddr = 43; + __tsan_java_release(lockaddr); + __atomic_store_n((int*)lockaddr, 1, __ATOMIC_RELAXED); + pthread_join(th, 0); + *(int*)lockaddr = 0; + pthread_create(&th, 0, Thread, 0); + *(int*)varaddr = 43; + __tsan_java_release_store(lockaddr); + __atomic_store_n((int*)lockaddr, 1, __ATOMIC_RELAXED); + pthread_join(th, 0); + __tsan_java_free(jheap, kBlockSize); + fprintf(stderr, "DONE\n"); + return __tsan_java_fini(); +} + +// CHECK-NOT: WARNING: ThreadSanitizer: data race +// CHECK: DONE diff --git a/test/tsan/load_shared_lib.cc b/test/tsan/load_shared_lib.cc index a27dc1cc6ffb..b7934b82df73 100644 --- a/test/tsan/load_shared_lib.cc +++ b/test/tsan/load_shared_lib.cc @@ -7,35 +7,39 @@ #ifdef BUILD_SO -#include <stddef.h> -#include <unistd.h> +#include "test.h" int GLOB_SHARED = 0; extern "C" +void init_so() { + barrier_init(&barrier, 2); +} + +extern "C" void *write_from_so(void *unused) { - if (unused) - sleep(1); + if (unused == 0) + barrier_wait(&barrier); GLOB_SHARED++; + if (unused != 0) + barrier_wait(&barrier); return NULL; } #else // BUILD_SO +#include "test.h" #include <dlfcn.h> -#include <pthread.h> -#include <stdio.h> -#include <stddef.h> -#include <unistd.h> - #include <string> int GLOB = 0; void *write_glob(void *unused) { - if (unused) - sleep(1); + if (unused == 0) + barrier_wait(&barrier); GLOB++; + if (unused != 0) + barrier_wait(&barrier); return NULL; } @@ -48,6 +52,7 @@ void race_two_threads(void *(*access_callback)(void *unused)) { } int main(int argc, char *argv[]) { + barrier_init(&barrier, 2); std::string path = std::string(argv[0]) + std::string("-so.so"); race_two_threads(write_glob); // CHECK: write_glob @@ -56,6 +61,9 @@ int main(int argc, char *argv[]) { printf("error in dlopen(): %s\n", dlerror()); return 1; } + void (*init_so)(); + *(void **)&init_so = dlsym(lib, "init_so"); + init_so(); void *(*write_from_so)(void *unused); *(void **)&write_from_so = dlsym(lib, "write_from_so"); race_two_threads(write_from_so); diff --git a/test/tsan/malloc_stack.cc b/test/tsan/malloc_stack.cc index 6027360754aa..ba1d62bcd9e7 100644 --- a/test/tsan/malloc_stack.cc +++ b/test/tsan/malloc_stack.cc @@ -1,20 +1,21 @@ // RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <unistd.h> +#include "test.h" _Atomic(int*) p; void *thr(void *a) { - sleep(1); + barrier_wait(&barrier); int *pp = __c11_atomic_load(&p, __ATOMIC_RELAXED); *pp = 42; return 0; } int main() { + barrier_init(&barrier, 2); pthread_t th; pthread_create(&th, 0, thr, p); __c11_atomic_store(&p, new int, __ATOMIC_RELAXED); + barrier_wait(&barrier); pthread_join(th, 0); } diff --git a/test/tsan/map32bit.cc b/test/tsan/map32bit.cc index 3a76fa2f6d62..9dae6880e7fe 100644 --- a/test/tsan/map32bit.cc +++ b/test/tsan/map32bit.cc @@ -1,9 +1,6 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <stddef.h> +#include "test.h" #include <stdint.h> -#include <unistd.h> #include <errno.h> #include <sys/mman.h> @@ -12,10 +9,12 @@ void *Thread(void *ptr) { *(int*)ptr = 42; + barrier_wait(&barrier); return 0; } int main() { + barrier_init(&barrier, 2); void *ptr = mmap(0, 128 << 10, PROT_READ|PROT_WRITE, MAP_32BIT|MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); fprintf(stderr, "ptr=%p\n", ptr); @@ -29,7 +28,7 @@ int main() { } pthread_t t; pthread_create(&t, 0, Thread, ptr); - sleep(1); + barrier_wait(&barrier); *(int*)ptr = 42; pthread_join(t, 0); munmap(ptr, 128 << 10); diff --git a/test/tsan/memcpy_race.cc b/test/tsan/memcpy_race.cc index 8ec8e0a3e6a5..d49577306d6c 100644 --- a/test/tsan/memcpy_race.cc +++ b/test/tsan/memcpy_race.cc @@ -1,9 +1,6 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stddef.h> -#include <stdio.h> +#include "test.h" #include <string.h> -#include <unistd.h> char *data = new char[10]; char *data1 = new char[10]; @@ -12,17 +9,19 @@ char *data2 = new char[10]; void *Thread1(void *x) { static volatile int size = 1; memcpy(data+5, data1, size); + barrier_wait(&barrier); return NULL; } void *Thread2(void *x) { static volatile int size = 4; - sleep(1); + barrier_wait(&barrier); memcpy(data+3, data2, size); return NULL; } int main() { + barrier_init(&barrier, 2); fprintf(stderr, "addr=%p\n", &data[5]); pthread_t t[2]; pthread_create(&t[0], NULL, Thread1, NULL); diff --git a/test/tsan/mop_with_offset.cc b/test/tsan/mop_with_offset.cc index e44c78b7d1b4..c67e81e09cda 100644 --- a/test/tsan/mop_with_offset.cc +++ b/test/tsan/mop_with_offset.cc @@ -1,23 +1,22 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stddef.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" void *Thread1(void *x) { int *p = (int*)x; p[0] = 1; + barrier_wait(&barrier); return NULL; } void *Thread2(void *x) { - sleep(1); + barrier_wait(&barrier); char *p = (char*)x; p[2] = 1; return NULL; } int main() { + barrier_init(&barrier, 2); int *data = new int(42); fprintf(stderr, "ptr1=%p\n", data); fprintf(stderr, "ptr2=%p\n", (char*)data + 2); diff --git a/test/tsan/mop_with_offset2.cc b/test/tsan/mop_with_offset2.cc index a465d5f09471..460267359cec 100644 --- a/test/tsan/mop_with_offset2.cc +++ b/test/tsan/mop_with_offset2.cc @@ -1,11 +1,8 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stddef.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" void *Thread1(void *x) { - sleep(1); + barrier_wait(&barrier); int *p = (int*)x; p[0] = 1; return NULL; @@ -14,10 +11,12 @@ void *Thread1(void *x) { void *Thread2(void *x) { char *p = (char*)x; p[2] = 1; + barrier_wait(&barrier); return NULL; } int main() { + barrier_init(&barrier, 2); int *data = new int(42); fprintf(stderr, "ptr1=%p\n", data); fprintf(stderr, "ptr2=%p\n", (char*)data + 2); diff --git a/test/tsan/mutex_cycle2.c b/test/tsan/mutex_cycle2.c index 031830d5ec63..85d19a0d0c35 100644 --- a/test/tsan/mutex_cycle2.c +++ b/test/tsan/mutex_cycle2.c @@ -2,10 +2,10 @@ // RUN: not %run %t 2>&1 | FileCheck %s // RUN: TSAN_OPTIONS=detect_deadlocks=1 not %run %t 2>&1 | FileCheck %s // RUN: TSAN_OPTIONS=detect_deadlocks=0 %run %t 2>&1 | FileCheck %s --check-prefix=DISABLED -// RUN: echo "deadlock:main" > %t.sup -// RUN: TSAN_OPTIONS="suppressions=%t.sup" %run %t 2>&1 | FileCheck %s --check-prefix=DISABLED -// RUN: echo "deadlock:zzzz" > %t.sup -// RUN: TSAN_OPTIONS="suppressions=%t.sup" not %run %t 2>&1 | FileCheck %s +// RUN: echo "deadlock:main" > %t.supp +// RUN: TSAN_OPTIONS="suppressions='%t.supp'" %run %t 2>&1 | FileCheck %s --check-prefix=DISABLED +// RUN: echo "deadlock:zzzz" > %t.supp +// RUN: TSAN_OPTIONS="suppressions='%t.supp'" not %run %t 2>&1 | FileCheck %s #include <pthread.h> #include <stdio.h> diff --git a/test/tsan/mutexset1.cc b/test/tsan/mutexset1.cc index 72964edfb1e7..407cfe5bd9f1 100644 --- a/test/tsan/mutexset1.cc +++ b/test/tsan/mutexset1.cc @@ -1,13 +1,11 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" int Global; pthread_mutex_t mtx; void *Thread1(void *x) { - sleep(1); + barrier_wait(&barrier); pthread_mutex_lock(&mtx); Global++; pthread_mutex_unlock(&mtx); @@ -16,10 +14,12 @@ void *Thread1(void *x) { void *Thread2(void *x) { Global--; + barrier_wait(&barrier); return NULL; } int main() { + barrier_init(&barrier, 2); // CHECK: WARNING: ThreadSanitizer: data race // CHECK: Write of size 4 at {{.*}} by thread T1 // CHECK: (mutexes: write [[M1:M[0-9]+]]): diff --git a/test/tsan/mutexset2.cc b/test/tsan/mutexset2.cc index 01a5f5df6e94..2a3e5bb95e87 100644 --- a/test/tsan/mutexset2.cc +++ b/test/tsan/mutexset2.cc @@ -1,7 +1,5 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" int Global; pthread_mutex_t mtx; @@ -10,16 +8,18 @@ void *Thread1(void *x) { pthread_mutex_lock(&mtx); Global++; pthread_mutex_unlock(&mtx); + barrier_wait(&barrier); return NULL; } void *Thread2(void *x) { - sleep(1); + barrier_wait(&barrier); Global--; return NULL; } int main() { + barrier_init(&barrier, 2); // CHECK: WARNING: ThreadSanitizer: data race // CHECK: Write of size 4 at {{.*}} by thread T2: // CHECK: Previous write of size 4 at {{.*}} by thread T1 diff --git a/test/tsan/mutexset3.cc b/test/tsan/mutexset3.cc index e14bb1111e32..ce64cf86e37c 100644 --- a/test/tsan/mutexset3.cc +++ b/test/tsan/mutexset3.cc @@ -1,14 +1,12 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" int Global; pthread_mutex_t mtx1; pthread_mutex_t mtx2; void *Thread1(void *x) { - sleep(1); + barrier_wait(&barrier); pthread_mutex_lock(&mtx1); pthread_mutex_lock(&mtx2); Global++; @@ -19,10 +17,12 @@ void *Thread1(void *x) { void *Thread2(void *x) { Global--; + barrier_wait(&barrier); return NULL; } int main() { + barrier_init(&barrier, 2); // CHECK: WARNING: ThreadSanitizer: data race // CHECK: Write of size 4 at {{.*}} by thread T1 // CHECK: (mutexes: write [[M1:M[0-9]+]], write [[M2:M[0-9]+]]): diff --git a/test/tsan/mutexset4.cc b/test/tsan/mutexset4.cc index db860e005d67..b961efd2136c 100644 --- a/test/tsan/mutexset4.cc +++ b/test/tsan/mutexset4.cc @@ -1,7 +1,5 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" int Global; pthread_mutex_t mtx1; @@ -13,16 +11,18 @@ void *Thread1(void *x) { Global++; pthread_mutex_unlock(&mtx2); pthread_mutex_unlock(&mtx1); + barrier_wait(&barrier); return NULL; } void *Thread2(void *x) { - sleep(1); + barrier_wait(&barrier); Global--; return NULL; } int main() { + barrier_init(&barrier, 2); // CHECK: WARNING: ThreadSanitizer: data race // CHECK: Write of size 4 at {{.*}} by thread T2: // CHECK: Previous write of size 4 at {{.*}} by thread T1 diff --git a/test/tsan/mutexset5.cc b/test/tsan/mutexset5.cc index e1cc2fcacf62..8ef9af0ced52 100644 --- a/test/tsan/mutexset5.cc +++ b/test/tsan/mutexset5.cc @@ -1,14 +1,12 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" int Global; pthread_mutex_t mtx1; pthread_mutex_t mtx2; void *Thread1(void *x) { - sleep(1); + barrier_wait(&barrier); pthread_mutex_lock(&mtx1); Global++; pthread_mutex_unlock(&mtx1); @@ -19,10 +17,12 @@ void *Thread2(void *x) { pthread_mutex_lock(&mtx2); Global--; pthread_mutex_unlock(&mtx2); + barrier_wait(&barrier); return NULL; } int main() { + barrier_init(&barrier, 2); // CHECK: WARNING: ThreadSanitizer: data race // CHECK: Write of size 4 at {{.*}} by thread T1 // CHECK: (mutexes: write [[M1:M[0-9]+]]): diff --git a/test/tsan/mutexset6.cc b/test/tsan/mutexset6.cc index 07dcc0a7394d..f4251db6970e 100644 --- a/test/tsan/mutexset6.cc +++ b/test/tsan/mutexset6.cc @@ -1,7 +1,5 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" int Global; pthread_mutex_t mtx1; @@ -9,7 +7,7 @@ pthread_spinlock_t mtx2; pthread_rwlock_t mtx3; void *Thread1(void *x) { - sleep(1); + barrier_wait(&barrier); pthread_mutex_lock(&mtx1); Global++; pthread_mutex_unlock(&mtx1); @@ -24,10 +22,12 @@ void *Thread2(void *x) { Global--; pthread_spin_unlock(&mtx2); pthread_rwlock_unlock(&mtx3); + barrier_wait(&barrier); return NULL; } int main() { + barrier_init(&barrier, 2); // CHECK: WARNING: ThreadSanitizer: data race // CHECK: Write of size 4 at {{.*}} by thread T1 // CHECK: (mutexes: write [[M1:M[0-9]+]]): diff --git a/test/tsan/mutexset7.cc b/test/tsan/mutexset7.cc index 12174844c799..d3a221d1b421 100644 --- a/test/tsan/mutexset7.cc +++ b/test/tsan/mutexset7.cc @@ -1,13 +1,11 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" int Global; __thread int huge[1024*1024]; void *Thread1(void *x) { - sleep(1); + barrier_wait(&barrier); Global++; return NULL; } @@ -20,10 +18,12 @@ void *Thread2(void *x) { pthread_mutex_unlock(mtx); pthread_mutex_destroy(mtx); delete mtx; + barrier_wait(&barrier); return NULL; } int main() { + barrier_init(&barrier, 2); pthread_t t[2]; pthread_create(&t[0], NULL, Thread1, NULL); pthread_create(&t[1], NULL, Thread2, NULL); diff --git a/test/tsan/mutexset8.cc b/test/tsan/mutexset8.cc index 3e1ab8c5a744..40d5d043dedd 100644 --- a/test/tsan/mutexset8.cc +++ b/test/tsan/mutexset8.cc @@ -1,13 +1,11 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" int Global; pthread_mutex_t *mtx; void *Thread1(void *x) { - sleep(1); + barrier_wait(&barrier); pthread_mutex_lock(mtx); Global++; pthread_mutex_unlock(mtx); @@ -16,10 +14,12 @@ void *Thread1(void *x) { void *Thread2(void *x) { Global--; + barrier_wait(&barrier); return NULL; } int main() { + barrier_init(&barrier, 2); // CHECK: WARNING: ThreadSanitizer: data race // CHECK: Write of size 4 at {{.*}} by thread T1 // CHECK: (mutexes: write [[M1:M[0-9]+]]): diff --git a/test/tsan/process_sleep.h b/test/tsan/process_sleep.h deleted file mode 100644 index 5938a42bf8b2..000000000000 --- a/test/tsan/process_sleep.h +++ /dev/null @@ -1,7 +0,0 @@ -#include <time.h> - -static void process_sleep(int sec) { - clock_t beg = clock(); - while((clock() - beg) / CLOCKS_PER_SEC < sec) - usleep(100); -} diff --git a/test/tsan/pthread_atfork_deadlock.c b/test/tsan/pthread_atfork_deadlock.c index 0f33b9022e5f..4aeec82b6850 100644 --- a/test/tsan/pthread_atfork_deadlock.c +++ b/test/tsan/pthread_atfork_deadlock.c @@ -4,14 +4,12 @@ // When the data race was reported, pthread_atfork() handler used to be // executed which caused another race report in the same thread, which resulted // in a deadlock. -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" int glob = 0; void *worker(void *unused) { - sleep(1); + barrier_wait(&barrier); glob++; return NULL; } @@ -22,10 +20,12 @@ void atfork() { } int main() { + barrier_init(&barrier, 2); pthread_atfork(atfork, NULL, NULL); pthread_t t; pthread_create(&t, NULL, worker, NULL); glob++; + barrier_wait(&barrier); pthread_join(t, NULL); // CHECK: ThreadSanitizer: data race // CHECK-NOT: ATFORK diff --git a/test/tsan/race_on_barrier.c b/test/tsan/race_on_barrier.c index 99b18fe4d8e6..cf8a4cb99274 100644 --- a/test/tsan/race_on_barrier.c +++ b/test/tsan/race_on_barrier.c @@ -1,25 +1,24 @@ // RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <stddef.h> -#include <unistd.h> +#include "test.h" pthread_barrier_t B; int Global; void *Thread1(void *x) { pthread_barrier_init(&B, 0, 2); + barrier_wait(&barrier); pthread_barrier_wait(&B); return NULL; } void *Thread2(void *x) { - sleep(1); + barrier_wait(&barrier); pthread_barrier_wait(&B); return NULL; } int main() { + barrier_init(&barrier, 2); pthread_t t; pthread_create(&t, NULL, Thread1, NULL); Thread2(0); diff --git a/test/tsan/race_on_mutex.c b/test/tsan/race_on_mutex.c index b4adeeb4df72..7bd461bf3731 100644 --- a/test/tsan/race_on_mutex.c +++ b/test/tsan/race_on_mutex.c @@ -1,8 +1,5 @@ // RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <stddef.h> -#include <unistd.h> +#include "test.h" pthread_mutex_t Mtx; int Global; @@ -12,11 +9,12 @@ void *Thread1(void *x) { pthread_mutex_lock(&Mtx); Global = 42; pthread_mutex_unlock(&Mtx); + barrier_wait(&barrier); return NULL; } void *Thread2(void *x) { - sleep(1); + barrier_wait(&barrier); pthread_mutex_lock(&Mtx); Global = 43; pthread_mutex_unlock(&Mtx); @@ -24,6 +22,7 @@ void *Thread2(void *x) { } int main() { + barrier_init(&barrier, 2); pthread_t t[2]; pthread_create(&t[0], NULL, Thread1, NULL); pthread_create(&t[1], NULL, Thread2, NULL); @@ -36,7 +35,7 @@ int main() { // CHECK: WARNING: ThreadSanitizer: data race // CHECK-NEXT: Atomic read of size 1 at {{.*}} by thread T2: // CHECK-NEXT: #0 pthread_mutex_lock -// CHECK-NEXT: #1 Thread2{{.*}} {{.*}}race_on_mutex.c:20{{(:3)?}} ({{.*}}) +// CHECK-NEXT: #1 Thread2{{.*}} {{.*}}race_on_mutex.c:18{{(:3)?}} ({{.*}}) // CHECK: Previous write of size 1 at {{.*}} by thread T1: // CHECK-NEXT: #0 pthread_mutex_init {{.*}} ({{.*}}) -// CHECK-NEXT: #1 Thread1{{.*}} {{.*}}race_on_mutex.c:11{{(:3)?}} ({{.*}}) +// CHECK-NEXT: #1 Thread1{{.*}} {{.*}}race_on_mutex.c:8{{(:3)?}} ({{.*}}) diff --git a/test/tsan/race_on_mutex2.c b/test/tsan/race_on_mutex2.c index 1796d0c6480b..6ee5438f566e 100644 --- a/test/tsan/race_on_mutex2.c +++ b/test/tsan/race_on_mutex2.c @@ -1,21 +1,20 @@ // RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <stddef.h> -#include <unistd.h> +#include "test.h" void *Thread(void *x) { pthread_mutex_lock((pthread_mutex_t*)x); pthread_mutex_unlock((pthread_mutex_t*)x); + barrier_wait(&barrier); return 0; } int main() { + barrier_init(&barrier, 2); pthread_mutex_t Mtx; pthread_mutex_init(&Mtx, 0); pthread_t t; pthread_create(&t, 0, Thread, &Mtx); - sleep(1); + barrier_wait(&barrier); pthread_mutex_destroy(&Mtx); pthread_join(t, 0); return 0; diff --git a/test/tsan/race_on_puts.cc b/test/tsan/race_on_puts.cc index 1f2b4db836ed..f2541823bf0c 100644 --- a/test/tsan/race_on_puts.cc +++ b/test/tsan/race_on_puts.cc @@ -1,21 +1,22 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" char s[] = "abracadabra"; void *Thread0(void *p) { puts(s); + barrier_wait(&barrier); return 0; } void *Thread1(void *p) { + barrier_wait(&barrier); s[3] = 'z'; return 0; } int main() { + barrier_init(&barrier, 2); pthread_t th[2]; pthread_create(&th[0], 0, Thread0, 0); pthread_create(&th[1], 0, Thread1, 0); diff --git a/test/tsan/race_on_read.cc b/test/tsan/race_on_read.cc index 1ec0522b9035..d388bbacde5b 100644 --- a/test/tsan/race_on_read.cc +++ b/test/tsan/race_on_read.cc @@ -1,31 +1,35 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> -#include <unistd.h> #include <errno.h> int fd; char buf; -void *Thread(void *x) { - sleep(1); +void *Thread1(void *x) { + barrier_wait(&barrier); read(fd, &buf, 1); return NULL; } +void *Thread2(void *x) { + read(fd, &buf, 1); + barrier_wait(&barrier); + return NULL; +} + int main() { + barrier_init(&barrier, 2); fd = open("/dev/random", O_RDONLY); if (fd < 0) { fprintf(stderr, "failed to open /dev/random (%d)\n", errno); return 1; } pthread_t t[2]; - pthread_create(&t[0], NULL, Thread, NULL); - pthread_create(&t[1], NULL, Thread, NULL); + pthread_create(&t[0], NULL, Thread1, NULL); + pthread_create(&t[1], NULL, Thread2, NULL); pthread_join(t[0], NULL); pthread_join(t[1], NULL); close(fd); diff --git a/test/tsan/race_on_speculative_load.cc b/test/tsan/race_on_speculative_load.cc index f816db9e8853..b50b69677d4b 100644 --- a/test/tsan/race_on_speculative_load.cc +++ b/test/tsan/race_on_speculative_load.cc @@ -1,9 +1,8 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %run %t | FileCheck %s // Regtest for https://code.google.com/p/thread-sanitizer/issues/detail?id=40 // This is a correct program and tsan should not report a race. -#include <pthread.h> -#include <unistd.h> -#include <stdio.h> +#include "test.h" + int g; __attribute__((noinline)) int foo(int cond) { @@ -11,17 +10,21 @@ int foo(int cond) { return g; return 0; } + void *Thread1(void *p) { + barrier_wait(&barrier); long res = foo((long)p); - sleep(1); return (void*) res; } int main() { + barrier_init(&barrier, 2); pthread_t t; pthread_create(&t, 0, Thread1, 0); g = 1; + barrier_wait(&barrier); pthread_join(t, 0); printf("PASS\n"); + // CHECK-NOT: ThreadSanitizer: data race // CHECK: PASS } diff --git a/test/tsan/race_on_write.cc b/test/tsan/race_on_write.cc index 484bbb7ae022..147591a39b9b 100644 --- a/test/tsan/race_on_write.cc +++ b/test/tsan/race_on_write.cc @@ -1,7 +1,5 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> @@ -11,7 +9,7 @@ char buf; void *Thread1(void *x) { buf = 1; - sleep(1); + barrier_wait(&barrier); return NULL; } @@ -21,11 +19,12 @@ void *Thread2(void *x) { } int main() { + barrier_init(&barrier, 2); fd = open("/dev/null", O_WRONLY); if (fd < 0) return 1; pthread_t t[2]; pthread_create(&t[0], NULL, Thread1, NULL); - sleep(1); + barrier_wait(&barrier); pthread_create(&t[1], NULL, Thread2, NULL); pthread_join(t[0], NULL); pthread_join(t[1], NULL); diff --git a/test/tsan/race_with_finished_thread.cc b/test/tsan/race_with_finished_thread.cc index d28760093c42..755a7bd982bb 100644 --- a/test/tsan/race_with_finished_thread.cc +++ b/test/tsan/race_with_finished_thread.cc @@ -1,9 +1,5 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stddef.h> -#include <stdio.h> -#include <string.h> -#include <unistd.h> +#include "test.h" // Ensure that we can restore a stack of a finished thread. @@ -15,16 +11,19 @@ void __attribute__((noinline)) foobar(int *p) { void *Thread1(void *x) { foobar(&g_data); + barrier_wait(&barrier); return NULL; } void *Thread2(void *x) { - sleep(1); + barrier_wait(&barrier); + sleep(1); // let the thread finish and exit g_data = 43; return NULL; } int main() { + barrier_init(&barrier, 2); pthread_t t[2]; pthread_create(&t[0], NULL, Thread1, NULL); pthread_create(&t[1], NULL, Thread2, NULL); diff --git a/test/tsan/real_deadlock_detector_stress_test.cc b/test/tsan/real_deadlock_detector_stress_test.cc new file mode 100644 index 000000000000..67c878f45084 --- /dev/null +++ b/test/tsan/real_deadlock_detector_stress_test.cc @@ -0,0 +1,186 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s + +#include <pthread.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <time.h> +#include <errno.h> +#include <vector> +#include <algorithm> + +const int kThreads = 4; +const int kMutexes = 16 << 10; +const int kIters = 400 << 10; +const int kMaxPerThread = 10; + +const int kStateInited = 0; +const int kStateNotInited = -1; +const int kStateLocked = -2; + +struct Mutex { + int state; + pthread_rwlock_t m; +}; + +Mutex mtx[kMutexes]; + +void check(int res) { + if (res != 0) { + printf("SOMETHING HAS FAILED\n"); + exit(1); + } +} + +bool cas(int *a, int oldval, int newval) { + return __atomic_compare_exchange_n(a, &oldval, newval, false, + __ATOMIC_ACQ_REL, __ATOMIC_RELAXED); +} + +void *Thread(void *seed) { + unsigned rnd = (unsigned)(unsigned long)seed; + int err; + std::vector<int> locked; + for (int i = 0; i < kIters; i++) { + int what = rand_r(&rnd) % 10; + if (what < 4 && locked.size() < kMaxPerThread) { + // lock + int max_locked = -1; + if (!locked.empty()) { + max_locked = *std::max_element(locked.begin(), locked.end()); + if (max_locked == kMutexes - 1) { + i--; + continue; + } + } + int id = (rand_r(&rnd) % (kMutexes - max_locked - 1)) + max_locked + 1; + Mutex *m = &mtx[id]; + // init the mutex if necessary or acquire a reference + for (;;) { + int old = __atomic_load_n(&m->state, __ATOMIC_RELAXED); + if (old == kStateLocked) { + pthread_yield(); + continue; + } + int newv = old + 1; + if (old == kStateNotInited) + newv = kStateLocked; + if (cas(&m->state, old, newv)) { + if (old == kStateNotInited) { + if ((err = pthread_rwlock_init(&m->m, 0))) { + fprintf(stderr, "pthread_rwlock_init failed with %d\n", err); + exit(1); + } + if (!cas(&m->state, kStateLocked, 1)) { + fprintf(stderr, "init commit failed\n"); + exit(1); + } + } + break; + } + } + // now we have an inited and referenced mutex, choose what to do + bool failed = false; + switch (rand_r(&rnd) % 4) { + case 0: + if ((err = pthread_rwlock_wrlock(&m->m))) { + fprintf(stderr, "pthread_rwlock_wrlock failed with %d\n", err); + exit(1); + } + break; + case 1: + if ((err = pthread_rwlock_rdlock(&m->m))) { + fprintf(stderr, "pthread_rwlock_rdlock failed with %d\n", err); + exit(1); + } + break; + case 2: + err = pthread_rwlock_trywrlock(&m->m); + if (err != 0 && err != EBUSY) { + fprintf(stderr, "pthread_rwlock_trywrlock failed with %d\n", err); + exit(1); + } + failed = err == EBUSY; + break; + case 3: + err = pthread_rwlock_tryrdlock(&m->m); + if (err != 0 && err != EBUSY) { + fprintf(stderr, "pthread_rwlock_tryrdlock failed with %d\n", err); + exit(1); + } + failed = err == EBUSY; + break; + } + if (failed) { + if (__atomic_fetch_sub(&m->state, 1, __ATOMIC_ACQ_REL) <= 0) { + fprintf(stderr, "failed to unref after failed trylock\n"); + exit(1); + } + continue; + } + locked.push_back(id); + } else if (what < 9 && !locked.empty()) { + // unlock + int pos = rand_r(&rnd) % locked.size(); + int id = locked[pos]; + locked[pos] = locked[locked.size() - 1]; + locked.pop_back(); + Mutex *m = &mtx[id]; + if ((err = pthread_rwlock_unlock(&m->m))) { + fprintf(stderr, "pthread_rwlock_unlock failed with %d\n", err); + exit(1); + } + if (__atomic_fetch_sub(&m->state, 1, __ATOMIC_ACQ_REL) <= 0) { + fprintf(stderr, "failed to unref after unlock\n"); + exit(1); + } + } else { + // Destroy a random mutex. + int id = rand_r(&rnd) % kMutexes; + Mutex *m = &mtx[id]; + if (!cas(&m->state, kStateInited, kStateLocked)) { + i--; + continue; + } + if ((err = pthread_rwlock_destroy(&m->m))) { + fprintf(stderr, "pthread_rwlock_destroy failed with %d\n", err); + exit(1); + } + if (!cas(&m->state, kStateLocked, kStateNotInited)) { + fprintf(stderr, "destroy commit failed\n"); + exit(1); + } + } + } + // Unlock all previously locked mutexes, otherwise other threads can deadlock. + for (int i = 0; i < locked.size(); i++) { + int id = locked[i]; + Mutex *m = &mtx[id]; + if ((err = pthread_rwlock_unlock(&m->m))) { + fprintf(stderr, "pthread_rwlock_unlock failed with %d\n", err); + exit(1); + } + } + return 0; +} + +int main() { + timespec ts; + clock_gettime(CLOCK_MONOTONIC, &ts); + unsigned s = (unsigned)ts.tv_nsec; + fprintf(stderr, "seed %d\n", s); + srand(s); + for (int i = 0; i < kMutexes; i++) + mtx[i].state = kStateNotInited; + pthread_t t[kThreads]; + for (int i = 0; i < kThreads; i++) + pthread_create(&t[i], 0, Thread, (void*)(unsigned long)rand()); + for (int i = 0; i < kThreads; i++) + pthread_join(t[i], 0); + fprintf(stderr, "DONE\n"); + return 0; +} + +// CHECK-NOT: WARNING: ThreadSanitizer +// CHECK: DONE + diff --git a/test/tsan/restore_stack.cc b/test/tsan/restore_stack.cc new file mode 100644 index 000000000000..39c11011ca49 --- /dev/null +++ b/test/tsan/restore_stack.cc @@ -0,0 +1,50 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && not %run %t 2>&1 | FileCheck %s +#include "test.h" + +int Global; +volatile int x; +const int kSize = 64 << 10; +volatile long data[kSize]; + +void __attribute__((noinline)) foo() { + for (int i = 0; i < kSize; i++) + data[i]++; +} + +void *Thread(void *a) { + __atomic_store_n(&x, 1, __ATOMIC_RELEASE); + foo(); + data[0]++; + if (a != 0) + barrier_wait(&barrier); + return 0; +} + +int main() { + barrier_init(&barrier, 2); + for (int i = 0; i < 50; i++) { + pthread_t t; + pthread_create(&t, 0, Thread, 0); + pthread_join(t, 0); + } + pthread_t t; + pthread_create(&t, 0, Thread, (void*)1); + barrier_wait(&barrier); + for (int i = 0; i < kSize; i++) + data[i]++; + pthread_join(t, 0); + fprintf(stderr, "DONE\n"); + return 0; +} + +// Previously this test produced bogus stack traces like: +// Previous write of size 8 at 0x0000006a8ff8 by thread T17: +// #0 foo() restore_stack.cc:13:5 (restore_stack.cc.exe+0x00000040622c) +// #1 Thread(void*) restore_stack.cc:18:3 (restore_stack.cc.exe+0x000000406283) +// #2 __tsan_thread_start_func rtl/tsan_interceptors.cc:886 (restore_stack.cc.exe+0x00000040a749) +// #3 Thread(void*) restore_stack.cc:18:3 (restore_stack.cc.exe+0x000000406283) + +// CHECK: WARNING: ThreadSanitizer: data race +// CHECK-NOT: __tsan_thread_start_func +// CHECK-NOT: #3 Thread +// CHECK: DONE diff --git a/test/tsan/signal_errno.cc b/test/tsan/signal_errno.cc index 1fa20f36810b..8305e84930f3 100644 --- a/test/tsan/signal_errno.cc +++ b/test/tsan/signal_errno.cc @@ -1,10 +1,7 @@ // RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <stdlib.h> +#include "test.h" #include <signal.h> #include <sys/types.h> -#include <unistd.h> #include <errno.h> pthread_t mainth; @@ -16,12 +13,13 @@ static void MyHandler(int, siginfo_t *s, void *c) { } static void* sendsignal(void *p) { - sleep(1); + barrier_wait(&barrier); pthread_kill(mainth, SIGPROF); return 0; } static __attribute__((noinline)) void loop() { + barrier_wait(&barrier); while (done == 0) { volatile char *p = (char*)malloc(1); p[0] = 0; @@ -31,6 +29,7 @@ static __attribute__((noinline)) void loop() { } int main() { + barrier_init(&barrier, 2); mainth = pthread_self(); struct sigaction act = {}; act.sa_sigaction = &MyHandler; diff --git a/test/tsan/signal_malloc.cc b/test/tsan/signal_malloc.cc index 06932fba42db..1dccb139c415 100644 --- a/test/tsan/signal_malloc.cc +++ b/test/tsan/signal_malloc.cc @@ -1,9 +1,7 @@ // RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <stdio.h> -#include <stdlib.h> +#include "test.h" #include <signal.h> #include <sys/types.h> -#include <unistd.h> static void handler(int, siginfo_t*, void*) { // CHECK: WARNING: ThreadSanitizer: signal-unsafe call inside of a signal @@ -20,7 +18,7 @@ int main() { act.sa_sigaction = &handler; sigaction(SIGPROF, &act, 0); kill(getpid(), SIGPROF); - sleep(1); + sleep(1); // let the signal handler run return 0; } diff --git a/test/tsan/signal_recursive.cc b/test/tsan/signal_recursive.cc index bbb6807586a5..825338de9fba 100644 --- a/test/tsan/signal_recursive.cc +++ b/test/tsan/signal_recursive.cc @@ -3,19 +3,13 @@ // Test case for recursive signal handlers, adopted from: // https://code.google.com/p/thread-sanitizer/issues/detail?id=71 -#include <pthread.h> +#include "test.h" #include <semaphore.h> #include <signal.h> -#include <unistd.h> #include <errno.h> -#include <stdlib.h> -#include <stdio.h> - -#include "process_sleep.h" static const int kSigSuspend = SIGUSR1; static const int kSigRestart = SIGUSR2; -static sigset_t g_suspend_handler_mask; static sem_t g_thread_suspend_ack_sem; @@ -27,7 +21,7 @@ static void SaveRegistersInStack() { // Mono walks thread stacks to detect unreferenced objects. // If last object reference is kept in register the object will be collected // This is why threads can't be suspended with something like pthread_suspend -}; +} static void fail(const char *what) { fprintf(stderr, "FAILED: %s (errno=%d)\n", what, errno); @@ -37,15 +31,19 @@ static void fail(const char *what) { static void SuspendHandler(int sig) { int old_errno = errno; SaveRegistersInStack(); + + // Enable kSigRestart handling, tsan disables signals around signal handlers. + sigset_t sigset; + sigemptyset(&sigset); + pthread_sigmask(SIG_SETMASK, &sigset, 0); + // Acknowledge that thread is saved and suspended if (sem_post(&g_thread_suspend_ack_sem) != 0) fail("sem_post failed"); - do { - g_busy_thread_received_restart = false; - if (sigsuspend(&g_suspend_handler_mask) != -1 || errno != EINTR) - fail("sigsuspend failed"); - } while (!g_busy_thread_received_restart); + // Wait for wakeup signal. + while (!g_busy_thread_received_restart) + usleep(100); // wait for kSigRestart signal // Acknowledge that thread restarted if (sem_post(&g_thread_suspend_ack_sem) != 0) @@ -83,21 +81,15 @@ static void StartWorld(pthread_t thread) { static void CollectGarbage(pthread_t thread) { StopWorld(thread); // Walk stacks - process_sleep(1); StartWorld(thread); } static void Init() { - if (sigfillset(&g_suspend_handler_mask) != 0) - fail("sigfillset failed"); - if (sigdelset(&g_suspend_handler_mask, kSigRestart) != 0) - fail("sigdelset failed"); if (sem_init(&g_thread_suspend_ack_sem, 0, 0) != 0) fail("sem_init failed"); struct sigaction act = {}; act.sa_flags = SA_RESTART; - sigfillset(&act.sa_mask); act.sa_handler = &SuspendHandler; if (sigaction(kSigSuspend, &act, NULL) != 0) fail("sigaction failed"); diff --git a/test/tsan/signal_reset.cc b/test/tsan/signal_reset.cc new file mode 100644 index 000000000000..aec98dc399e9 --- /dev/null +++ b/test/tsan/signal_reset.cc @@ -0,0 +1,74 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/time.h> +#include <unistd.h> +#include <errno.h> + +volatile int X; +int stop; + +static void handler(int sig) { + (void)sig; + if (X != 0) + printf("bad"); +} + +static void* busy(void *p) { + while (__atomic_load_n(&stop, __ATOMIC_RELAXED) == 0) { + } + return 0; +} + +static void* reset(void *p) { + struct sigaction act = {}; + for (int i = 0; i < 1000000; i++) { + act.sa_handler = &handler; + if (sigaction(SIGPROF, &act, 0)) { + perror("sigaction"); + exit(1); + } + act.sa_handler = SIG_IGN; + if (sigaction(SIGPROF, &act, 0)) { + perror("sigaction"); + exit(1); + } + } + return 0; +} + +int main() { + struct sigaction act = {}; + act.sa_handler = SIG_IGN; + if (sigaction(SIGPROF, &act, 0)) { + perror("sigaction"); + exit(1); + } + + itimerval t; + t.it_value.tv_sec = 0; + t.it_value.tv_usec = 10; + t.it_interval = t.it_value; + if (setitimer(ITIMER_PROF, &t, 0)) { + perror("setitimer"); + exit(1); + } + + pthread_t th[2]; + pthread_create(&th[0], 0, busy, 0); + pthread_create(&th[1], 0, reset, 0); + + pthread_join(th[1], 0); + __atomic_store_n(&stop, 1, __ATOMIC_RELAXED); + pthread_join(th[0], 0); + + fprintf(stderr, "DONE\n"); + return 0; +} + +// CHECK-NOT: WARNING: ThreadSanitizer: +// CHECK: DONE +// CHECK-NOT: WARNING: ThreadSanitizer: diff --git a/test/tsan/signal_sync.cc b/test/tsan/signal_sync.cc index 15387b754dfb..6ff19d3bd120 100644 --- a/test/tsan/signal_sync.cc +++ b/test/tsan/signal_sync.cc @@ -1,11 +1,8 @@ // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <stdlib.h> +#include "test.h" #include <signal.h> #include <sys/types.h> #include <sys/time.h> -#include <unistd.h> #include <errno.h> volatile int X; @@ -18,7 +15,7 @@ static void handler(int sig) { static void* thr(void *p) { for (int i = 0; i != 1000; i++) - usleep(1000); + usleep(1000); // process signals return 0; } diff --git a/test/tsan/signal_thread.cc b/test/tsan/signal_thread.cc new file mode 100644 index 000000000000..8eda80a52264 --- /dev/null +++ b/test/tsan/signal_thread.cc @@ -0,0 +1,52 @@ +// RUN: %clangxx_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <sys/types.h> +#include <sys/time.h> +#include <unistd.h> +#include <errno.h> + +volatile int X; + +static void handler(int sig) { + (void)sig; + if (X != 0) + printf("bad"); +} + +static void* thr(void *p) { + return 0; +} + +int main() { + struct sigaction act = {}; + act.sa_handler = &handler; + if (sigaction(SIGPROF, &act, 0)) { + perror("sigaction"); + exit(1); + } + + itimerval t; + t.it_value.tv_sec = 0; + t.it_value.tv_usec = 10; + t.it_interval = t.it_value; + if (setitimer(ITIMER_PROF, &t, 0)) { + perror("setitimer"); + exit(1); + } + + for (int i = 0; i < 10000; i++) { + pthread_t th; + pthread_create(&th, 0, thr, 0); + pthread_join(th, 0); + } + + fprintf(stderr, "DONE\n"); + return 0; +} + +// CHECK-NOT: WARNING: ThreadSanitizer: +// CHECK: DONE +// CHECK-NOT: WARNING: ThreadSanitizer: diff --git a/test/tsan/signal_write.cc b/test/tsan/signal_write.cc index 626d87a7acc7..edb3d2356bd2 100644 --- a/test/tsan/signal_write.cc +++ b/test/tsan/signal_write.cc @@ -16,7 +16,7 @@ int main() { act.sa_sigaction = &handler; sigaction(SIGPROF, &act, 0); kill(getpid(), SIGPROF); - sleep(1); + sleep(1); // let the signal handler run, can't use barrier in sig handler fprintf(stderr, "DONE\n"); return 0; } diff --git a/test/tsan/simple_race.c b/test/tsan/simple_race.c index 7b60c5ec249e..b4234acd7f89 100644 --- a/test/tsan/simple_race.c +++ b/test/tsan/simple_race.c @@ -1,22 +1,22 @@ // RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" int Global; void *Thread1(void *x) { - sleep(1); + barrier_wait(&barrier); Global = 42; return NULL; } void *Thread2(void *x) { Global = 43; + barrier_wait(&barrier); return NULL; } int main() { + barrier_init(&barrier, 2); pthread_t t[2]; pthread_create(&t[0], NULL, Thread1, NULL); pthread_create(&t[1], NULL, Thread2, NULL); diff --git a/test/tsan/simple_race.cc b/test/tsan/simple_race.cc index f711bb5d114d..612ce2dc0c4f 100644 --- a/test/tsan/simple_race.cc +++ b/test/tsan/simple_race.cc @@ -1,22 +1,22 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t 2>&1 | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" int Global; void *Thread1(void *x) { - sleep(1); + barrier_wait(&barrier); Global++; return NULL; } void *Thread2(void *x) { Global--; + barrier_wait(&barrier); return NULL; } int main() { + barrier_init(&barrier, 2); pthread_t t[2]; pthread_create(&t[0], NULL, Thread1, NULL); pthread_create(&t[1], NULL, Thread2, NULL); diff --git a/test/tsan/simple_stack.c b/test/tsan/simple_stack.c index 87367033b4c9..6ef92fb46c68 100644 --- a/test/tsan/simple_stack.c +++ b/test/tsan/simple_stack.c @@ -1,7 +1,5 @@ // RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" int Global; @@ -24,13 +22,14 @@ void __attribute__((noinline)) bar2() { } void *Thread1(void *x) { - sleep(1); + barrier_wait(&barrier); bar1(); return NULL; } void *Thread2(void *x) { bar2(); + barrier_wait(&barrier); return NULL; } @@ -39,6 +38,7 @@ void StartThread(pthread_t *t, void *(*f)(void*)) { } int main() { + barrier_init(&barrier, 2); pthread_t t[2]; StartThread(&t[0], Thread1); StartThread(&t[1], Thread2); @@ -49,18 +49,18 @@ int main() { // CHECK: WARNING: ThreadSanitizer: data race // CHECK-NEXT: Write of size 4 at {{.*}} by thread T1: -// CHECK-NEXT: #0 foo1{{.*}} {{.*}}simple_stack.c:9{{(:3)?}} ({{.*}}) -// CHECK-NEXT: #1 bar1{{.*}} {{.*}}simple_stack.c:14{{(:3)?}} ({{.*}}) -// CHECK-NEXT: #2 Thread1{{.*}} {{.*}}simple_stack.c:28{{(:3)?}} ({{.*}}) +// 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: Previous read of size 4 at {{.*}} by thread T2: -// CHECK-NEXT: #0 foo2{{.*}} {{.*}}simple_stack.c:18{{(:3)?}} ({{.*}}) -// CHECK-NEXT: #1 bar2{{.*}} {{.*}}simple_stack.c:23{{(:3)?}} ({{.*}}) -// CHECK-NEXT: #2 Thread2{{.*}} {{.*}}simple_stack.c:33{{(:3)?}} ({{.*}}) +// 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: Thread T1 (tid={{.*}}, running) created by main thread at: // CHECK-NEXT: #0 pthread_create {{.*}} ({{.*}}) -// CHECK-NEXT: #1 StartThread{{.*}} {{.*}}simple_stack.c:38{{(:3)?}} ({{.*}}) +// CHECK-NEXT: #1 StartThread{{.*}} {{.*}}simple_stack.c:37{{(:3)?}} ({{.*}}) // CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack.c:43{{(:3)?}} ({{.*}}) // CHECK: Thread T2 ({{.*}}) created by main thread at: // CHECK-NEXT: #0 pthread_create {{.*}} ({{.*}}) -// CHECK-NEXT: #1 StartThread{{.*}} {{.*}}simple_stack.c:38{{(:3)?}} ({{.*}}) +// CHECK-NEXT: #1 StartThread{{.*}} {{.*}}simple_stack.c:37{{(:3)?}} ({{.*}}) // CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack.c:44{{(:3)?}} ({{.*}}) diff --git a/test/tsan/simple_stack2.cc b/test/tsan/simple_stack2.cc index b07d863e4008..20ef729f7857 100644 --- a/test/tsan/simple_stack2.cc +++ b/test/tsan/simple_stack2.cc @@ -1,7 +1,5 @@ // RUN: %clangxx_tsan -O1 %s -o %T/simple_stack2.cc.exe && %deflake %run %T/simple_stack2.cc.exe | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" int Global; @@ -30,24 +28,26 @@ void __attribute__((noinline)) bar2() { } void *Thread1(void *x) { - sleep(1); + barrier_wait(&barrier); bar1(); return NULL; } int main() { + barrier_init(&barrier, 2); pthread_t t; pthread_create(&t, NULL, Thread1, NULL); bar2(); + barrier_wait(&barrier); pthread_join(t, NULL); } // CHECK: WARNING: ThreadSanitizer: data race // CHECK-NEXT: Write of size 4 at {{.*}} by thread T1: -// CHECK-NEXT: #0 foo1{{.*}} {{.*}}simple_stack2.cc:9{{(:3)?}} (simple_stack2.cc.exe+{{.*}}) -// CHECK-NEXT: #1 bar1{{.*}} {{.*}}simple_stack2.cc:16{{(:3)?}} (simple_stack2.cc.exe+{{.*}}) -// CHECK-NEXT: #2 Thread1{{.*}} {{.*}}simple_stack2.cc:34{{(:3)?}} (simple_stack2.cc.exe+{{.*}}) +// CHECK-NEXT: #0 foo1{{.*}} {{.*}}simple_stack2.cc:7{{(:10)?}} (simple_stack2.cc.exe+{{.*}}) +// CHECK-NEXT: #1 bar1{{.*}} {{.*}}simple_stack2.cc:14{{(:3)?}} (simple_stack2.cc.exe+{{.*}}) +// CHECK-NEXT: #2 Thread1{{.*}} {{.*}}simple_stack2.cc:32{{(:3)?}} (simple_stack2.cc.exe+{{.*}}) // CHECK: Previous read of size 4 at {{.*}} by main thread: -// CHECK-NEXT: #0 foo2{{.*}} {{.*}}simple_stack2.cc:20{{(:3)?}} (simple_stack2.cc.exe+{{.*}}) -// CHECK-NEXT: #1 bar2{{.*}} {{.*}}simple_stack2.cc:29{{(:3)?}} (simple_stack2.cc.exe+{{.*}}) -// CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack2.cc:41{{(:3)?}} (simple_stack2.cc.exe+{{.*}}) +// CHECK-NEXT: #0 foo2{{.*}} {{.*}}simple_stack2.cc:18{{(:22)?}} (simple_stack2.cc.exe+{{.*}}) +// CHECK-NEXT: #1 bar2{{.*}} {{.*}}simple_stack2.cc:27{{(:3)?}} (simple_stack2.cc.exe+{{.*}}) +// CHECK-NEXT: #2 main{{.*}} {{.*}}simple_stack2.cc:40{{(:3)?}} (simple_stack2.cc.exe+{{.*}}) diff --git a/test/tsan/sleep_sync.cc b/test/tsan/sleep_sync.cc index c7614e16bf3e..b2c6a1220f42 100644 --- a/test/tsan/sleep_sync.cc +++ b/test/tsan/sleep_sync.cc @@ -1,23 +1,25 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <unistd.h> +#include "test.h" int X = 0; void MySleep() { - sleep(1); + sleep(1); // the sleep that must appear in the report } void *Thread(void *p) { + barrier_wait(&barrier); MySleep(); // Assume the main thread has done the write. X = 42; return 0; } int main() { + barrier_init(&barrier, 2); pthread_t t; pthread_create(&t, 0, Thread, 0); X = 43; + barrier_wait(&barrier); pthread_join(t, 0); return 0; } diff --git a/test/tsan/sleep_sync2.cc b/test/tsan/sleep_sync2.cc index 4e616992ecc9..a1a7a3accb48 100644 --- a/test/tsan/sleep_sync2.cc +++ b/test/tsan/sleep_sync2.cc @@ -1,18 +1,20 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <unistd.h> +#include "test.h" int X = 0; void *Thread(void *p) { X = 42; + barrier_wait(&barrier); return 0; } int main() { + barrier_init(&barrier, 2); pthread_t t; - sleep(1); + sleep(1); // must not appear in the report pthread_create(&t, 0, Thread, 0); + barrier_wait(&barrier); X = 43; pthread_join(t, 0); return 0; diff --git a/test/tsan/stack_race.cc b/test/tsan/stack_race.cc index 2e02f46a281f..1ada2953547b 100644 --- a/test/tsan/stack_race.cc +++ b/test/tsan/stack_race.cc @@ -1,19 +1,19 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stddef.h> -#include <unistd.h> +#include "test.h" void *Thread(void *a) { - sleep(1); + barrier_wait(&barrier); *(int*)a = 43; return 0; } int main() { + barrier_init(&barrier, 2); int Var = 42; pthread_t t; pthread_create(&t, 0, Thread, &Var); Var = 43; + barrier_wait(&barrier); pthread_join(t, 0); } diff --git a/test/tsan/stack_race2.cc b/test/tsan/stack_race2.cc index 818db367bab6..00e31fb96b08 100644 --- a/test/tsan/stack_race2.cc +++ b/test/tsan/stack_race2.cc @@ -1,10 +1,8 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stddef.h> -#include <unistd.h> +#include "test.h" void *Thread2(void *a) { - sleep(1); + barrier_wait(&barrier); *(int*)a = 43; return 0; } @@ -14,11 +12,13 @@ void *Thread(void *a) { pthread_t t; pthread_create(&t, 0, Thread2, &Var); Var = 42; + barrier_wait(&barrier); pthread_join(t, 0); return 0; } int main() { + barrier_init(&barrier, 2); pthread_t t; pthread_create(&t, 0, Thread, 0); pthread_join(t, 0); diff --git a/test/tsan/stack_sync_reuse.cc b/test/tsan/stack_sync_reuse.cc new file mode 100644 index 000000000000..5ea9e84b085a --- /dev/null +++ b/test/tsan/stack_sync_reuse.cc @@ -0,0 +1,65 @@ +// RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s +#include "test.h" + +// Test case https://code.google.com/p/thread-sanitizer/issues/detail?id=87 +// Tsan sees false HB edge on address pointed to by syncp variable. +// It is false because when acquire is done syncp points to a var in one frame, +// and during release it points to a var in a different frame. +// The code is somewhat tricky because it prevents compiler from optimizing +// our accesses away, structured to not introduce other data races and +// not introduce other synchronization, and to arrange the vars in different +// frames to occupy the same address. + +// The data race CHECK-NOT below actually must be CHECK, because the program +// does contain the data race on global. + +// CHECK-NOT: WARNING: ThreadSanitizer: data race +// CHECK: DONE + +long global; +long *syncp; +long *addr; +long sink; + +void *Thread(void *x) { + while (__atomic_load_n(&syncp, __ATOMIC_ACQUIRE) == 0) + usleep(1000); // spin wait + global = 42; + __atomic_store_n(syncp, 1, __ATOMIC_RELEASE); + __atomic_store_n(&syncp, 0, __ATOMIC_RELAXED); + return NULL; +} + +void __attribute__((noinline)) foobar() { + long s; + addr = &s; + __atomic_store_n(&s, 0, __ATOMIC_RELAXED); + __atomic_store_n(&syncp, &s, __ATOMIC_RELEASE); + while (__atomic_load_n(&syncp, __ATOMIC_RELAXED) != 0) + usleep(1000); // spin wait +} + +void __attribute__((noinline)) barfoo() { + long s; + if (addr != &s) { + printf("address mismatch addr=%p &s=%p\n", addr, &s); + exit(1); + } + __atomic_store_n(&addr, &s, __ATOMIC_RELAXED); + __atomic_store_n(&s, 0, __ATOMIC_RELAXED); + sink = __atomic_load_n(&s, __ATOMIC_ACQUIRE); + global = 43; +} + +int main() { + pthread_t t; + pthread_create(&t, 0, Thread, 0); + foobar(); + barfoo(); + pthread_join(t, 0); + if (sink != 0) + exit(1); + fprintf(stderr, "DONE\n"); + return 0; +} + diff --git a/test/tsan/suppress_same_address.cc b/test/tsan/suppress_same_address.cc index df19da1cc7ae..3ec13ee8302f 100644 --- a/test/tsan/suppress_same_address.cc +++ b/test/tsan/suppress_same_address.cc @@ -1,11 +1,10 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <unistd.h> +#include "test.h" volatile int X; void *Thread1(void *x) { - sleep(1); + barrier_wait(&barrier); X = 42; X = 66; X = 78; @@ -16,10 +15,12 @@ void *Thread2(void *x) { X = 11; X = 99; X = 73; + barrier_wait(&barrier); return 0; } int main() { + barrier_init(&barrier, 2); pthread_t t; pthread_create(&t, 0, Thread1, 0); Thread2(0); diff --git a/test/tsan/suppressions_global.cc b/test/tsan/suppressions_global.cc index c808a63d9e84..c7b9bb99eb17 100644 --- a/test/tsan/suppressions_global.cc +++ b/test/tsan/suppressions_global.cc @@ -1,4 +1,4 @@ -// RUN: %clang_tsan -O1 %s -o %t && TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %run %t 2>&1 | FileCheck %s +// RUN: %clang_tsan -O1 %s -o %t && TSAN_OPTIONS="$TSAN_OPTIONS suppressions='%s.supp'" %run %t 2>&1 | FileCheck %s #include <pthread.h> #include <stdio.h> diff --git a/test/tsan/suppressions_race.cc b/test/tsan/suppressions_race.cc index 1d72874d9586..45c30481f0cd 100644 --- a/test/tsan/suppressions_race.cc +++ b/test/tsan/suppressions_race.cc @@ -1,22 +1,22 @@ -// RUN: %clang_tsan -O1 %s -o %t && TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %run %t 2>&1 | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +// RUN: %clang_tsan -O1 %s -o %t && TSAN_OPTIONS="$TSAN_OPTIONS suppressions='%s.supp'" %run %t 2>&1 | FileCheck %s +#include "test.h" int Global; void *Thread1(void *x) { - sleep(1); + barrier_wait(&barrier); Global = 42; return NULL; } void *Thread2(void *x) { Global = 43; + barrier_wait(&barrier); return NULL; } int main() { + barrier_init(&barrier, 2); pthread_t t[2]; pthread_create(&t[0], NULL, Thread1, NULL); pthread_create(&t[1], NULL, Thread2, NULL); diff --git a/test/tsan/suppressions_race2.cc b/test/tsan/suppressions_race2.cc index 4ababddf6311..24ecd8ef119f 100644 --- a/test/tsan/suppressions_race2.cc +++ b/test/tsan/suppressions_race2.cc @@ -1,22 +1,22 @@ -// RUN: %clang_tsan -O1 %s -o %t && TSAN_OPTIONS="$TSAN_OPTIONS suppressions=%s.supp" %run %t 2>&1 | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +// RUN: %clang_tsan -O1 %s -o %t && TSAN_OPTIONS="$TSAN_OPTIONS suppressions='%s.supp'" %run %t 2>&1 | FileCheck %s +#include "test.h" int Global; void *Thread1(void *x) { Global = 42; + barrier_wait(&barrier); return NULL; } void *Thread2(void *x) { - sleep(1); + barrier_wait(&barrier); Global = 43; return NULL; } int main() { + barrier_init(&barrier, 2); pthread_t t[2]; pthread_create(&t[0], NULL, Thread1, NULL); pthread_create(&t[1], NULL, Thread2, NULL); diff --git a/test/tsan/test.h b/test/tsan/test.h new file mode 100644 index 000000000000..4496e56cda87 --- /dev/null +++ b/test/tsan/test.h @@ -0,0 +1,31 @@ +#include <pthread.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <dlfcn.h> +#include <stddef.h> + +// TSan-invisible barrier. +// Tests use it to establish necessary execution order in a way that does not +// interfere with tsan (does not establish synchronization between threads). +__typeof(pthread_barrier_wait) *barrier_wait; + +void barrier_init(pthread_barrier_t *barrier, unsigned count) { + if (barrier_wait == 0) { + void *h = dlopen("libpthread.so.0", RTLD_LAZY); + if (h == 0) { + fprintf(stderr, "failed to dlopen libpthread.so.0, exiting\n"); + exit(1); + } + barrier_wait = (__typeof(barrier_wait))dlsym(h, "pthread_barrier_wait"); + if (barrier_wait == 0) { + fprintf(stderr, "failed to resolve pthread_barrier_wait, exiting\n"); + exit(1); + } + } + pthread_barrier_init(barrier, 0, count); +} + +// Default instance of the barrier, but a test can declare more manually. +pthread_barrier_t barrier; + diff --git a/test/tsan/thread_detach.c b/test/tsan/thread_detach.c index 32cf641b141a..802d8ded0fad 100644 --- a/test/tsan/thread_detach.c +++ b/test/tsan/thread_detach.c @@ -1,16 +1,16 @@ // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" void *Thread(void *x) { + barrier_wait(&barrier); return 0; } int main() { + barrier_init(&barrier, 2); pthread_t t; pthread_create(&t, 0, Thread, 0); - sleep(1); + barrier_wait(&barrier); pthread_detach(t); printf("PASS\n"); return 0; diff --git a/test/tsan/thread_leak3.c b/test/tsan/thread_leak3.c index f4db484219a0..c09fb714d7ab 100644 --- a/test/tsan/thread_leak3.c +++ b/test/tsan/thread_leak3.c @@ -1,15 +1,17 @@ // RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <unistd.h> +#include "test.h" void *Thread(void *x) { + barrier_wait(&barrier); return 0; } int main() { + barrier_init(&barrier, 2); pthread_t t; pthread_create(&t, 0, Thread, 0); - sleep(1); + barrier_wait(&barrier); + sleep(1); // wait for the thread to finish and exit return 0; } diff --git a/test/tsan/thread_leak4.c b/test/tsan/thread_leak4.c index 0d3b8307000a..1ebca58871ac 100644 --- a/test/tsan/thread_leak4.c +++ b/test/tsan/thread_leak4.c @@ -1,18 +1,18 @@ // RUN: %clang_tsan -O1 %s -o %t && %run %t 2>&1 | FileCheck %s -#include <pthread.h> -#include <unistd.h> -#include <stdio.h> +#include "test.h" void *Thread(void *x) { - sleep(10); + sleep(100); // leave the thread "running" return 0; } int main() { pthread_t t; pthread_create(&t, 0, Thread, 0); - printf("OK\n"); + printf("DONE\n"); return 0; } +// CHECK: DONE // CHECK-NOT: WARNING: ThreadSanitizer: thread leak + diff --git a/test/tsan/thread_leak5.c b/test/tsan/thread_leak5.c index ca244a9f24e1..acdbd1d38a9b 100644 --- a/test/tsan/thread_leak5.c +++ b/test/tsan/thread_leak5.c @@ -1,18 +1,20 @@ // RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <unistd.h> +#include "test.h" void *Thread(void *x) { + barrier_wait(&barrier); return 0; } int main() { volatile int N = 5; // prevent loop unrolling + barrier_init(&barrier, N + 1); for (int i = 0; i < N; i++) { pthread_t t; pthread_create(&t, 0, Thread, 0); } - sleep(1); + barrier_wait(&barrier); + sleep(1); // wait for the threads to finish and exit return 0; } diff --git a/test/tsan/thread_name.cc b/test/tsan/thread_name.cc index a790c668c084..80d30b82d8b5 100644 --- a/test/tsan/thread_name.cc +++ b/test/tsan/thread_name.cc @@ -1,7 +1,5 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" #if defined(__linux__) #define USE_PTHREAD_SETNAME_NP __GLIBC_PREREQ(2, 12) @@ -18,7 +16,7 @@ extern "C" void AnnotateThreadName(const char *f, int l, const char *name); int Global; void *Thread1(void *x) { - sleep(1); + barrier_wait(&barrier); AnnotateThreadName(__FILE__, __LINE__, "Thread1"); Global++; return NULL; @@ -31,10 +29,12 @@ void *Thread2(void *x) { AnnotateThreadName(__FILE__, __LINE__, "Thread2"); #endif Global--; + barrier_wait(&barrier); return NULL; } int main() { + barrier_init(&barrier, 2); pthread_t t[2]; pthread_create(&t[0], NULL, Thread1, NULL); pthread_create(&t[1], NULL, Thread2, NULL); diff --git a/test/tsan/thread_name2.cc b/test/tsan/thread_name2.cc index 6a3dafe9c763..a44f4b9d3247 100644 --- a/test/tsan/thread_name2.cc +++ b/test/tsan/thread_name2.cc @@ -1,7 +1,5 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" #if defined(__FreeBSD__) #include <pthread_np.h> @@ -11,7 +9,7 @@ int Global; void *Thread1(void *x) { - sleep(1); + barrier_wait(&barrier); Global++; return 0; } @@ -19,14 +17,17 @@ void *Thread1(void *x) { void *Thread2(void *x) { pthread_setname_np(pthread_self(), "foobar2"); Global--; + barrier_wait(&barrier); return 0; } int main() { + barrier_init(&barrier, 3); pthread_t t[2]; pthread_create(&t[0], 0, Thread1, 0); pthread_create(&t[1], 0, Thread2, 0); pthread_setname_np(t[0], "foobar1"); + barrier_wait(&barrier); pthread_join(t[0], NULL); pthread_join(t[1], NULL); } diff --git a/test/tsan/tiny_race.c b/test/tsan/tiny_race.c index c10eab15c5a9..b6937febd117 100644 --- a/test/tsan/tiny_race.c +++ b/test/tsan/tiny_race.c @@ -1,19 +1,20 @@ // RUN: %clang_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <unistd.h> +#include "test.h" int Global; void *Thread1(void *x) { - sleep(1); + barrier_wait(&barrier); Global = 42; return x; } int main() { + barrier_init(&barrier, 2); pthread_t t; pthread_create(&t, 0, Thread1, 0); Global = 43; + barrier_wait(&barrier); pthread_join(t, 0); return Global; } diff --git a/test/tsan/tls_race.cc b/test/tsan/tls_race.cc index 18589347e806..5e8172276708 100644 --- a/test/tsan/tls_race.cc +++ b/test/tsan/tls_race.cc @@ -1,19 +1,19 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stddef.h> -#include <unistd.h> +#include "test.h" void *Thread(void *a) { - sleep(1); + barrier_wait(&barrier); *(int*)a = 43; return 0; } int main() { + barrier_init(&barrier, 2); static __thread int Var = 42; pthread_t t; pthread_create(&t, 0, Thread, &Var); Var = 43; + barrier_wait(&barrier); pthread_join(t, 0); } diff --git a/test/tsan/tls_race2.cc b/test/tsan/tls_race2.cc index 0ca629ada5cc..d0f7b03e09a1 100644 --- a/test/tsan/tls_race2.cc +++ b/test/tsan/tls_race2.cc @@ -1,10 +1,8 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stddef.h> -#include <unistd.h> +#include "test.h" void *Thread2(void *a) { - sleep(1); + barrier_wait(&barrier); *(int*)a = 43; return 0; } @@ -14,11 +12,13 @@ void *Thread(void *a) { pthread_t t; pthread_create(&t, 0, Thread2, &Var); Var = 42; + barrier_wait(&barrier); pthread_join(t, 0); return 0; } int main() { + barrier_init(&barrier, 2); pthread_t t; pthread_create(&t, 0, Thread, 0); pthread_join(t, 0); diff --git a/test/tsan/unaligned_norace.cc b/test/tsan/unaligned_norace.cc index 20cb545f7426..94df1cf74cc1 100644 --- a/test/tsan/unaligned_norace.cc +++ b/test/tsan/unaligned_norace.cc @@ -7,20 +7,20 @@ uint64_t objs[8*3*3*2][3]; extern "C" { -uint16_t __tsan_unaligned_read2(void *addr); -uint32_t __tsan_unaligned_read4(void *addr); -uint64_t __tsan_unaligned_read8(void *addr); -void __tsan_unaligned_write2(void *addr, uint16_t v); -void __tsan_unaligned_write4(void *addr, uint32_t v); -void __tsan_unaligned_write8(void *addr, uint64_t v); +void __tsan_unaligned_read2(void *addr); +void __tsan_unaligned_read4(void *addr); +void __tsan_unaligned_read8(void *addr); +void __tsan_unaligned_write2(void *addr); +void __tsan_unaligned_write4(void *addr); +void __tsan_unaligned_write8(void *addr); } static void access(char *p, int sz, int rw) { if (rw) { switch (sz) { - case 0: __tsan_unaligned_write2(p, 0); break; - case 1: __tsan_unaligned_write4(p, 0); break; - case 2: __tsan_unaligned_write8(p, 0); break; + case 0: __tsan_unaligned_write2(p); break; + case 1: __tsan_unaligned_write4(p); break; + case 2: __tsan_unaligned_write8(p); break; default: exit(1); } } else { diff --git a/test/tsan/unaligned_race.cc b/test/tsan/unaligned_race.cc index 6e9b5a33f0da..030642a4ddfb 100644 --- a/test/tsan/unaligned_race.cc +++ b/test/tsan/unaligned_race.cc @@ -1,9 +1,6 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <stdlib.h> +#include "test.h" #include <stdint.h> -#include <unistd.h> #define NOINLINE __attribute__((noinline)) @@ -123,15 +120,17 @@ NOINLINE void Test(bool main) { void *Thread(void *p) { (void)p; - sleep(1); + barrier_wait(&barrier); Test(false); return 0; } int main() { + barrier_init(&barrier, 2); pthread_t th; pthread_create(&th, 0, Thread, 0); Test(true); + barrier_wait(&barrier); pthread_join(th, 0); } diff --git a/test/tsan/vptr_harmful_race.cc b/test/tsan/vptr_harmful_race.cc index 68e12e8e7e89..d15b3969ab81 100644 --- a/test/tsan/vptr_harmful_race.cc +++ b/test/tsan/vptr_harmful_race.cc @@ -1,8 +1,6 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> +#include "test.h" #include <semaphore.h> -#include <stdio.h> -#include <unistd.h> struct A { A() { @@ -31,16 +29,18 @@ static A *obj = new B; void *Thread1(void *x) { obj->F(); obj->Done(); + barrier_wait(&barrier); return NULL; } void *Thread2(void *x) { - sleep(1); + barrier_wait(&barrier); delete obj; return NULL; } int main() { + barrier_init(&barrier, 2); pthread_t t[2]; pthread_create(&t[0], NULL, Thread1, NULL); pthread_create(&t[1], NULL, Thread2, NULL); diff --git a/test/tsan/vptr_harmful_race2.cc b/test/tsan/vptr_harmful_race2.cc index aa53bbb90fcf..a56b74c09689 100644 --- a/test/tsan/vptr_harmful_race2.cc +++ b/test/tsan/vptr_harmful_race2.cc @@ -1,8 +1,6 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> +#include "test.h" #include <semaphore.h> -#include <stdio.h> -#include <unistd.h> struct A { A() { @@ -29,18 +27,20 @@ struct B : A { static A *obj = new B; void *Thread1(void *x) { - sleep(1); obj->F(); + barrier_wait(&barrier); obj->Done(); return NULL; } void *Thread2(void *x) { + barrier_wait(&barrier); delete obj; return NULL; } int main() { + barrier_init(&barrier, 2); pthread_t t[2]; pthread_create(&t[0], NULL, Thread1, NULL); pthread_create(&t[1], NULL, Thread2, NULL); diff --git a/test/tsan/vptr_harmful_race3.cc b/test/tsan/vptr_harmful_race3.cc index ac6ea94e51eb..3810a1068d64 100644 --- a/test/tsan/vptr_harmful_race3.cc +++ b/test/tsan/vptr_harmful_race3.cc @@ -1,8 +1,6 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> +#include "test.h" #include <semaphore.h> -#include <stdio.h> -#include <unistd.h> struct A { A() { @@ -30,18 +28,20 @@ static A *obj = new B; static void (A::*fn)() = &A::F; void *Thread1(void *x) { - sleep(1); (obj->*fn)(); + barrier_wait(&barrier); obj->Done(); return NULL; } void *Thread2(void *x) { + barrier_wait(&barrier); delete obj; return NULL; } int main() { + barrier_init(&barrier, 2); pthread_t t[2]; pthread_create(&t[0], NULL, Thread1, NULL); pthread_create(&t[1], NULL, Thread2, NULL); diff --git a/test/tsan/vptr_harmful_race4.cc b/test/tsan/vptr_harmful_race4.cc index 969c9d58a016..543514de8387 100644 --- a/test/tsan/vptr_harmful_race4.cc +++ b/test/tsan/vptr_harmful_race4.cc @@ -1,7 +1,5 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <stdio.h> -#include <unistd.h> +#include "test.h" struct A { virtual void F() { @@ -17,16 +15,18 @@ struct B : A { }; void *Thread(void *x) { - sleep(1); + barrier_wait(&barrier); ((A*)x)->F(); return 0; } int main() { + barrier_init(&barrier, 2); A *obj = new B; pthread_t t; pthread_create(&t, 0, Thread, obj); delete obj; + barrier_wait(&barrier); pthread_join(t, 0); } diff --git a/test/tsan/write_in_reader_lock.cc b/test/tsan/write_in_reader_lock.cc index 55882139b153..3f7cb3579f77 100644 --- a/test/tsan/write_in_reader_lock.cc +++ b/test/tsan/write_in_reader_lock.cc @@ -1,6 +1,5 @@ // RUN: %clangxx_tsan -O1 %s -o %t && %deflake %run %t | FileCheck %s -#include <pthread.h> -#include <unistd.h> +#include "test.h" pthread_rwlock_t rwlock; int GLOB; @@ -8,14 +7,15 @@ int GLOB; void *Thread1(void *p) { (void)p; pthread_rwlock_rdlock(&rwlock); + barrier_wait(&barrier); // Write under reader lock. - sleep(1); GLOB++; pthread_rwlock_unlock(&rwlock); return 0; } int main(int argc, char *argv[]) { + barrier_init(&barrier, 2); pthread_rwlock_init(&rwlock, NULL); pthread_rwlock_rdlock(&rwlock); pthread_t t; @@ -23,6 +23,7 @@ int main(int argc, char *argv[]) { volatile int x = GLOB; (void)x; pthread_rwlock_unlock(&rwlock); + barrier_wait(&barrier); pthread_join(t, 0); pthread_rwlock_destroy(&rwlock); return 0; @@ -30,6 +31,6 @@ int main(int argc, char *argv[]) { // CHECK: WARNING: ThreadSanitizer: data race // CHECK: Write of size 4 at {{.*}} by thread T1{{.*}}: -// CHECK: #0 Thread1(void*) {{.*}}write_in_reader_lock.cc:13 +// CHECK: #0 Thread1(void*) {{.*}}write_in_reader_lock.cc:12 // CHECK: Previous read of size 4 at {{.*}} by main thread{{.*}}: // CHECK: #0 main {{.*}}write_in_reader_lock.cc:23 diff --git a/test/ubsan/TestCases/Float/cast-overflow.cpp b/test/ubsan/TestCases/Float/cast-overflow.cpp index 22991e0a6c55..526817153d02 100644 --- a/test/ubsan/TestCases/Float/cast-overflow.cpp +++ b/test/ubsan/TestCases/Float/cast-overflow.cpp @@ -14,6 +14,7 @@ // This test assumes float and double are IEEE-754 single- and double-precision. // XFAIL: armv7l-unknown-linux-gnueabihf +// XFAIL: aarch64 #if defined(__APPLE__) # include <machine/endian.h> diff --git a/test/ubsan/TestCases/Integer/no-recover.cpp b/test/ubsan/TestCases/Integer/no-recover.cpp index 575bd0a553fb..bbc2f8d2c1c4 100644 --- a/test/ubsan/TestCases/Integer/no-recover.cpp +++ b/test/ubsan/TestCases/Integer/no-recover.cpp @@ -1,6 +1,6 @@ // RUN: %clangxx -fsanitize=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=RECOVER -// RUN: %clangxx -fsanitize=unsigned-integer-overflow -fsanitize-recover %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=RECOVER -// RUN: %clangxx -fsanitize=unsigned-integer-overflow -fno-sanitize-recover %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=ABORT +// RUN: %clangxx -fsanitize=unsigned-integer-overflow -fno-sanitize-recover=all -fsanitize-recover=unsigned-integer-overflow %s -o %t && %run %t 2>&1 | FileCheck %s --check-prefix=RECOVER +// RUN: %clangxx -fsanitize=unsigned-integer-overflow -fno-sanitize-recover=unsigned-integer-overflow %s -o %t && not %run %t 2>&1 | FileCheck %s --check-prefix=ABORT #include <stdint.h> diff --git a/test/ubsan/TestCases/Misc/coverage-levels.cc b/test/ubsan/TestCases/Misc/coverage-levels.cc new file mode 100644 index 000000000000..2fe12ffefd4b --- /dev/null +++ b/test/ubsan/TestCases/Misc/coverage-levels.cc @@ -0,0 +1,38 @@ +// Test various levels of coverage +// +// RUN: mkdir -p %T/coverage-levels +// RUN: OPT=coverage=1:verbosity=1:coverage_dir=%T/coverage-levels +// RUN: %clangxx -fsanitize=shift -DGOOD_SHIFT=1 -O1 -fsanitize-coverage=1 %s -o %t +// RUN: UBSAN_OPTIONS=$OPT ASAN_OPTIONS=$OPT %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_NOWARN +// RUN: %clangxx -fsanitize=undefined -DGOOD_SHIFT=1 -O1 -fsanitize-coverage=1 %s -o %t +// RUN: UBSAN_OPTIONS=$OPT ASAN_OPTIONS=$OPT %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_NOWARN + +// RUN: %clangxx -fsanitize=shift -O1 -fsanitize-coverage=1 %s -o %t +// RUN: UBSAN_OPTIONS=$OPT ASAN_OPTIONS=$OPT %run %t 2>&1 | FileCheck %s --check-prefix=CHECK1 --check-prefix=CHECK_WARN +// RUN: %clangxx -fsanitize=shift -O1 -fsanitize-coverage=2 %s -o %t +// RUN: UBSAN_OPTIONS=$OPT ASAN_OPTIONS=$OPT %run %t 2>&1 | FileCheck %s --check-prefix=CHECK2 --check-prefix=CHECK_WARN +// RUN: %clangxx -fsanitize=shift -O1 -fsanitize-coverage=3 %s -o %t +// RUN: UBSAN_OPTIONS=$OPT ASAN_OPTIONS=$OPT %run %t 2>&1 | FileCheck %s --check-prefix=CHECK3 --check-prefix=CHECK_WARN + +// XFAIL: darwin + +volatile int sink; +int main(int argc, char **argv) { + int shift = argc * 32; +#if GOOD_SHIFT + shift = 3; +#endif + if ((argc << shift) == 16) // False. + return 1; + return 0; +} + +// CHECK_WARN: shift exponent 32 is too large +// CHECK_NOWARN-NOT: ERROR +// FIXME: Currently, coverage instrumentation kicks in after ubsan, so we get +// more than the minimal number of instrumented blocks. +// FIXME: Currently, ubsan with -fno-sanitize-recover and w/o asan will fail +// to dump coverage. +// CHECK1: 1 PCs written +// CHECK2: 3 PCs written +// CHECK3: 4 PCs written diff --git a/test/ubsan/TestCases/Misc/nonnull-arg.cpp b/test/ubsan/TestCases/Misc/nonnull-arg.cpp index b1061b757899..084dedc27b85 100644 --- a/test/ubsan/TestCases/Misc/nonnull-arg.cpp +++ b/test/ubsan/TestCases/Misc/nonnull-arg.cpp @@ -1,4 +1,4 @@ -// RUN: %clangxx -fsanitize=nonnull-attribute -fno-sanitize-recover %s -O3 -o %t +// RUN: %clangxx -fsanitize=nonnull-attribute -fno-sanitize-recover=all %s -O3 -o %t // RUN: %run %t nc // RUN: %run %t nm // RUN: %run %t nf diff --git a/test/ubsan/TestCases/TypeCheck/misaligned.cpp b/test/ubsan/TestCases/TypeCheck/misaligned.cpp index 79f5136db963..9c8455d5f1c3 100644 --- a/test/ubsan/TestCases/TypeCheck/misaligned.cpp +++ b/test/ubsan/TestCases/TypeCheck/misaligned.cpp @@ -9,9 +9,8 @@ // RUN: %run %t u1 2>&1 | FileCheck %s --check-prefix=CHECK-UPCAST // RUN: UBSAN_OPTIONS=print_stacktrace=1 %run %t l1 2>&1 | FileCheck %s --check-prefix=CHECK-LOAD --check-prefix=CHECK-%os-STACK-LOAD -// RUN: %clangxx -fsanitize=alignment -fno-sanitize-recover %s -O3 -o %t +// RUN: %clangxx -fsanitize=alignment -fno-sanitize-recover=alignment %s -O3 -o %t // RUN: not %run %t w1 2>&1 | FileCheck %s --check-prefix=CHECK-WILD -// XFAIL: armv7l-unknown-linux-gnueabihf #include <new> @@ -81,7 +80,7 @@ int main(int, char **argv) { return s->f() && 0; case 'n': - // CHECK-NEW: misaligned.cpp:[[@LINE+4]]:5: runtime error: constructor call on misaligned address [[PTR:0x[0-9a-f]*]] for type 'S', which requires 4 byte alignment + // CHECK-NEW: misaligned.cpp:[[@LINE+4]]:21: runtime error: constructor call on misaligned address [[PTR:0x[0-9a-f]*]] for type 'S', which requires 4 byte alignment // CHECK-NEW-NEXT: [[PTR]]: note: pointer points here // CHECK-NEW-NEXT: {{^ 00 00 00 01 02 03 04 05}} // CHECK-NEW-NEXT: {{^ \^}} @@ -97,8 +96,8 @@ int main(int, char **argv) { } case 'w': - // CHECK-WILD: misaligned.cpp:[[@LINE+3]]:35: runtime error: member access within misaligned address 0x000000000123 for type 'S', which requires 4 byte alignment - // CHECK-WILD-NEXT: 0x000000000123: note: pointer points here + // CHECK-WILD: misaligned.cpp:[[@LINE+3]]:35: runtime error: member access within misaligned address 0x{{0+}}123 for type 'S', which requires 4 byte alignment + // CHECK-WILD-NEXT: 0x{{0+}}123: note: pointer points here // CHECK-WILD-NEXT: <memory cannot be printed> return static_cast<S*>(wild)->k; } diff --git a/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp b/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp index 5261e71c2d3d..033da24451c2 100644 --- a/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp +++ b/test/ubsan/TestCases/TypeCheck/vptr-virtual-base.cpp @@ -1,4 +1,4 @@ -// RUN: %clangxx -fsanitize=vptr -fno-sanitize-recover -g %s -O3 -o %t +// RUN: %clangxx -fsanitize=vptr -fno-sanitize-recover=vptr -g %s -O3 -o %t // RUN: not %run %t 2>&1 | FileCheck %s // FIXME: This test produces linker errors on Darwin. diff --git a/test/ubsan/TestCases/TypeCheck/vptr.cpp b/test/ubsan/TestCases/TypeCheck/vptr.cpp index 3a6b1553f9b3..98eac271c3a1 100644 --- a/test/ubsan/TestCases/TypeCheck/vptr.cpp +++ b/test/ubsan/TestCases/TypeCheck/vptr.cpp @@ -12,16 +12,16 @@ // RUN: %run %t m0 2>&1 | FileCheck %s --check-prefix=CHECK-NULL-MEMBER --strict-whitespace // RUN: (echo "vptr_check:S"; echo "vptr_check:T"; echo "vptr_check:U") > %t.supp -// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t mS 2>&1 -// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t fS 2>&1 -// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t cS 2>&1 -// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t mV 2>&1 -// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t fV 2>&1 -// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t cV 2>&1 -// RUN: ASAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.supp:halt_on_error=1 %run %t oU 2>&1 +// RUN: ASAN_OPTIONS="suppressions='%t.supp'" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t mS 2>&1 +// RUN: ASAN_OPTIONS="suppressions='%t.supp'" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t fS 2>&1 +// RUN: ASAN_OPTIONS="suppressions='%t.supp'" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t cS 2>&1 +// RUN: ASAN_OPTIONS="suppressions='%t.supp'" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t mV 2>&1 +// RUN: ASAN_OPTIONS="suppressions='%t.supp'" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t fV 2>&1 +// RUN: ASAN_OPTIONS="suppressions='%t.supp'" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t cV 2>&1 +// RUN: ASAN_OPTIONS="suppressions='%t.supp'" UBSAN_OPTIONS="suppressions='%t.supp':halt_on_error=1" %run %t oU 2>&1 // RUN: echo "vptr_check:S" > %t.loc-supp -// RUN: ASAN_OPTIONS=suppressions=%t.loc-supp:halt_on_error=1 UBSAN_OPTIONS=suppressions=%t.loc-supp:halt_on_error=1 not %run %t x- 2>&1 | FileCheck %s --check-prefix=CHECK-LOC-SUPPRESS +// RUN: ASAN_OPTIONS="suppressions='%t.loc-supp'" UBSAN_OPTIONS="suppressions='%t.loc-supp':halt_on_error=1" not %run %t x- 2>&1 | FileCheck %s --check-prefix=CHECK-LOC-SUPPRESS // FIXME: This test produces linker errors on Darwin. // XFAIL: darwin @@ -48,8 +48,7 @@ struct T : S { virtual int v() { return 1; } }; -struct X {}; -struct U : S, T, virtual X { virtual int v() { return 2; } }; +struct U : S, T { virtual int v() { return 2; } }; struct V : S {}; |