diff options
Diffstat (limited to 'lib/lsan/lit_tests')
42 files changed, 1000 insertions, 122 deletions
diff --git a/lib/lsan/lit_tests/AsanConfig/lit.cfg b/lib/lsan/lit_tests/AsanConfig/lit.cfg new file mode 100644 index 000000000000..ae9198173ffc --- /dev/null +++ b/lib/lsan/lit_tests/AsanConfig/lit.cfg @@ -0,0 +1,32 @@ +# -*- Python -*- + +import os + +def get_required_attr(config, attr_name): + attr_value = getattr(config, attr_name, None) + if not attr_value: + lit_config.fatal( + "No attribute %r in test configuration! You may need to run " + "tests from your build directory or add this attribute " + "to lit.site.cfg " % attr_name) + return attr_value + +lsan_lit_src_root = get_required_attr(config, "lsan_lit_src_root") +lsan_lit_cfg = os.path.join(lsan_lit_src_root, "lit.common.cfg") +if not os.path.exists(lsan_lit_cfg): + lit_config.fatal("Can't find common LSan lit config at: %r" % lsan_lit_cfg) +lit_config.load_config(config, lsan_lit_cfg) + +config.name = 'LeakSanitizer-AddressSanitizer' + +clang_lsan_cxxflags = config.clang_cxxflags + " -fsanitize=address " + +config.substitutions.append( ("%clangxx_lsan ", (" " + config.clang + " " + + clang_lsan_cxxflags + " ")) ) + +clang_lsan_cflags = config.clang_cflags + " -fsanitize=address " + +config.substitutions.append( ("%clang_lsan ", (" " + config.clang + " " + + clang_lsan_cflags + " ")) ) + +config.environment['ASAN_OPTIONS'] = 'detect_leaks=1' diff --git a/lib/lsan/lit_tests/AsanConfig/lit.site.cfg.in b/lib/lsan/lit_tests/AsanConfig/lit.site.cfg.in new file mode 100644 index 000000000000..9cf6572c54b7 --- /dev/null +++ b/lib/lsan/lit_tests/AsanConfig/lit.site.cfg.in @@ -0,0 +1,8 @@ +# Load common config for all compiler-rt lit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured") + +# Tool-specific config options. +config.lsan_lit_src_root = "@LSAN_LIT_SOURCE_DIR@" + +# Load tool-specific config that would do the real work. +lit_config.load_config(config, "@LSAN_LIT_SOURCE_DIR@/AsanConfig/lit.cfg") diff --git a/lib/lsan/lit_tests/CMakeLists.txt b/lib/lsan/lit_tests/CMakeLists.txt index e1be508202b8..526d71bf3418 100644 --- a/lib/lsan/lit_tests/CMakeLists.txt +++ b/lib/lsan/lit_tests/CMakeLists.txt @@ -1,9 +1,16 @@ set(LSAN_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/..) set(LSAN_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR}/..) +set(LSAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + +configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/LsanConfig/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/LsanConfig/lit.site.cfg + ) + configure_lit_site_cfg( - ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in - ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg + ${CMAKE_CURRENT_SOURCE_DIR}/AsanConfig/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/AsanConfig/lit.site.cfg ) configure_lit_site_cfg( @@ -11,18 +18,20 @@ configure_lit_site_cfg( ${CMAKE_CURRENT_BINARY_DIR}/Unit/lit.site.cfg ) -if(COMPILER_RT_CAN_EXECUTE_TESTS) +if(COMPILER_RT_CAN_EXECUTE_TESTS AND NOT APPLE AND NOT ANDROID) set(LSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS} ${LSAN_RUNTIME_LIBRARIES}) - set(LSAN_TEST_PARAMS - lsan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg) + foreach(arch ${LSAN_SUPPORTED_ARCH}) + list(APPEND LSAN_TEST_DEPS clang_rt.asan-${arch}) + endforeach() if(LLVM_INCLUDE_TESTS) - list(APPEND LSAN_TEST_DEPS LsanTests) + list(APPEND LSAN_TEST_DEPS LsanUnitTests) endif() add_lit_testsuite(check-lsan "Running the LeakSanitizer tests" - ${CMAKE_CURRENT_BINARY_DIR} - PARAMS ${LSAN_TEST_PARAMS} + ${CMAKE_CURRENT_BINARY_DIR}/LsanConfig + ${CMAKE_CURRENT_BINARY_DIR}/AsanConfig + ${CMAKE_CURRENT_BINARY_DIR}/Unit DEPENDS ${LSAN_TEST_DEPS}) set_target_properties(check-lsan PROPERTIES FOLDER "LSan tests") endif() diff --git a/lib/lsan/lit_tests/LsanConfig/lit.cfg b/lib/lsan/lit_tests/LsanConfig/lit.cfg new file mode 100644 index 000000000000..84faf9167a78 --- /dev/null +++ b/lib/lsan/lit_tests/LsanConfig/lit.cfg @@ -0,0 +1,30 @@ +# -*- Python -*- + +import os + +def get_required_attr(config, attr_name): + attr_value = getattr(config, attr_name, None) + if not attr_value: + lit_config.fatal( + "No attribute %r in test configuration! You may need to run " + "tests from your build directory or add this attribute " + "to lit.site.cfg " % attr_name) + return attr_value + +lsan_lit_src_root = get_required_attr(config, "lsan_lit_src_root") +lsan_lit_cfg = os.path.join(lsan_lit_src_root, "lit.common.cfg") +if not os.path.exists(lsan_lit_cfg): + lit_config.fatal("Can't find common LSan lit config at: %r" % lsan_lit_cfg) +lit_config.load_config(config, lsan_lit_cfg) + +config.name = 'LeakSanitizer-Standalone' + +clang_lsan_cxxflags = config.clang_cxxflags + " -fsanitize=leak " + +config.substitutions.append( ("%clangxx_lsan ", (" " + config.clang + " " + + clang_lsan_cxxflags + " ")) ) + +clang_lsan_cflags = config.clang_cflags + " -fsanitize=leak " + +config.substitutions.append( ("%clang_lsan ", (" " + config.clang + " " + + clang_lsan_cflags + " ")) ) diff --git a/lib/lsan/lit_tests/LsanConfig/lit.site.cfg.in b/lib/lsan/lit_tests/LsanConfig/lit.site.cfg.in new file mode 100644 index 000000000000..2a6d724c0436 --- /dev/null +++ b/lib/lsan/lit_tests/LsanConfig/lit.site.cfg.in @@ -0,0 +1,8 @@ +# Load common config for all compiler-rt lit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.configured") + +# Tool-specific config options. +config.lsan_lit_src_root = "@LSAN_LIT_SOURCE_DIR@" + +# Load tool-specific config that would do the real work. +lit_config.load_config(config, "@LSAN_LIT_SOURCE_DIR@/LsanConfig/lit.cfg") diff --git a/lib/lsan/lit_tests/TestCases/SharedLibs/huge_tls_lib_so.cc b/lib/lsan/lit_tests/TestCases/SharedLibs/huge_tls_lib_so.cc new file mode 100644 index 000000000000..475a66ec12a4 --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/SharedLibs/huge_tls_lib_so.cc @@ -0,0 +1,12 @@ +// A loadable module with a large thread local section, which would require +// allocation of a new TLS storage chunk when loaded with dlopen(). We use it +// to test the reachability of such chunks in LSan tests. + +// This must be large enough that it doesn't fit into preallocated static TLS +// space (see STATIC_TLS_SURPLUS in glibc). +__thread void *huge_thread_local_array[(1 << 20) / sizeof(void *)]; // NOLINT + +extern "C" void **StoreToTLS(void *p) { + huge_thread_local_array[0] = p; + return &huge_thread_local_array[0]; +} diff --git a/lib/lsan/lit_tests/SharedLibs/lit.local.cfg b/lib/lsan/lit_tests/TestCases/SharedLibs/lit.local.cfg index b3677c17a0f2..b3677c17a0f2 100644 --- a/lib/lsan/lit_tests/SharedLibs/lit.local.cfg +++ b/lib/lsan/lit_tests/TestCases/SharedLibs/lit.local.cfg diff --git a/lib/lsan/lit_tests/TestCases/cleanup_in_tsd_destructor.cc b/lib/lsan/lit_tests/TestCases/cleanup_in_tsd_destructor.cc new file mode 100644 index 000000000000..ab368245317c --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/cleanup_in_tsd_destructor.cc @@ -0,0 +1,45 @@ +// Regression test for thread lifetime tracking. Thread data should be +// considered live during the thread's termination, at least until the +// user-installed TSD destructors have finished running (since they may contain +// additional cleanup tasks). LSan doesn't actually meet that goal 100%, but it +// makes its best effort. +// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE:use_tls=1 %t +// RUN: LSAN_OPTIONS=$LSAN_BASE:use_tls=0 not %t 2>&1 | FileCheck %s + +#include <assert.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + +#include "sanitizer/lsan_interface.h" + +pthread_key_t key; +__thread void *p; + +void key_destructor(void *arg) { + // Generally this may happen on a different thread. + __lsan_do_leak_check(); +} + +void *thread_func(void *arg) { + p = malloc(1337); + fprintf(stderr, "Test alloc: %p.\n", p); + int res = pthread_setspecific(key, (void*)1); + assert(res == 0); + return 0; +} + +int main() { + int res = pthread_key_create(&key, &key_destructor); + assert(res == 0); + pthread_t thread_id; + res = pthread_create(&thread_id, 0, thread_func, 0); + assert(res == 0); + res = pthread_join(thread_id, 0); + assert(res == 0); + return 0; +} +// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: leaked 1337 byte object at [[ADDR]] diff --git a/lib/lsan/lit_tests/TestCases/disabler.cc b/lib/lsan/lit_tests/TestCases/disabler.cc new file mode 100644 index 000000000000..db0cd8fabe4d --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/disabler.cc @@ -0,0 +1,23 @@ +// Test for ScopedDisabler. +// 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 %t 2>&1 | FileCheck %s + +#include <stdio.h> +#include <stdlib.h> + +#include "sanitizer/lsan_interface.h" + +int main() { + void **p; + { + __lsan::ScopedDisabler d; + p = new void *; + } + *reinterpret_cast<void **>(p) = malloc(666); + void *q = malloc(1337); + // Break optimization. + fprintf(stderr, "Test alloc: %p.\n", q); + return 0; +} +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: 1337 byte(s) leaked in 1 allocation(s) diff --git a/lib/lsan/lit_tests/TestCases/disabler_in_tsd_destructor.cc b/lib/lsan/lit_tests/TestCases/disabler_in_tsd_destructor.cc new file mode 100644 index 000000000000..94e4fc390b3b --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/disabler_in_tsd_destructor.cc @@ -0,0 +1,38 @@ +// Regression test. Disabler should not depend on TSD validity. +// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=1" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE %t + +#include <assert.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + +#include "sanitizer/lsan_interface.h" + +pthread_key_t key; + +void key_destructor(void *arg) { + __lsan::ScopedDisabler d; + void *p = malloc(1337); + // Break optimization. + fprintf(stderr, "Test alloc: %p.\n", p); + pthread_setspecific(key, 0); +} + +void *thread_func(void *arg) { + int res = pthread_setspecific(key, (void*)1); + assert(res == 0); + return 0; +} + +int main() { + int res = pthread_key_create(&key, &key_destructor); + assert(res == 0); + pthread_t thread_id; + res = pthread_create(&thread_id, 0, thread_func, 0); + assert(res == 0); + res = pthread_join(thread_id, 0); + assert(res == 0); + return 0; +} diff --git a/lib/lsan/lit_tests/TestCases/do_leak_check_override.cc b/lib/lsan/lit_tests/TestCases/do_leak_check_override.cc new file mode 100644 index 000000000000..be0ed0a6d48f --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/do_leak_check_override.cc @@ -0,0 +1,36 @@ +// Test for __lsan_do_leak_check(). We test it by making the leak check run +// before global destructors, which also tests compatibility with HeapChecker's +// "normal" mode (LSan runs in "strict" mode by default). +// RUN: LSAN_BASE="use_stacks=0:use_registers=0" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE not %t 2>&1 | FileCheck --check-prefix=CHECK-strict %s +// RUN: LSAN_OPTIONS=$LSAN_BASE not %t foo 2>&1 | FileCheck --check-prefix=CHECK-normal %s + +#include <stdio.h> +#include <stdlib.h> +#include <sanitizer/lsan_interface.h> + +struct LeakyGlobal { + LeakyGlobal() { + p = malloc(1337); + } + ~LeakyGlobal() { + p = 0; + } + void *p; +}; + +LeakyGlobal leaky_global; + +int main(int argc, char *argv[]) { + // Register leak check to run before global destructors. + if (argc > 1) + atexit(&__lsan_do_leak_check); + void *p = malloc(666); + printf("Test alloc: %p\n", p); + printf("Test alloc in leaky global: %p\n", leaky_global.p); + return 0; +} + +// CHECK-strict: SUMMARY: {{(Leak|Address)}}Sanitizer: 2003 byte(s) leaked in 2 allocation(s) +// CHECK-normal: SUMMARY: {{(Leak|Address)}}Sanitizer: 666 byte(s) leaked in 1 allocation(s) diff --git a/lib/lsan/lit_tests/TestCases/fork.cc b/lib/lsan/lit_tests/TestCases/fork.cc new file mode 100644 index 000000000000..69258d9a0c72 --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/fork.cc @@ -0,0 +1,24 @@ +// Test that thread local data is handled correctly after forking without exec(). +// RUN: %clangxx_lsan %s -o %t +// RUN: %t 2>&1 + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/wait.h> +#include <unistd.h> + +__thread void *thread_local_var; + +int main() { + int status = 0; + thread_local_var = malloc(1337); + pid_t pid = fork(); + assert(pid >= 0); + if (pid > 0) { + waitpid(pid, &status, 0); + assert(WIFEXITED(status)); + return WEXITSTATUS(status); + } + return 0; +} diff --git a/lib/lsan/lit_tests/TestCases/fork_threaded.cc b/lib/lsan/lit_tests/TestCases/fork_threaded.cc new file mode 100644 index 000000000000..24a586109e28 --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/fork_threaded.cc @@ -0,0 +1,43 @@ +// Test that thread local data is handled correctly after forking without +// exec(). In this test leak checking is initiated from a non-main thread. +// RUN: %clangxx_lsan %s -o %t +// RUN: %t 2>&1 + +#include <assert.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/wait.h> +#include <unistd.h> + +__thread void *thread_local_var; + +void *exit_thread_func(void *arg) { + exit(0); +} + +void ExitFromThread() { + pthread_t tid; + int res; + res = pthread_create(&tid, 0, exit_thread_func, 0); + assert(res == 0); + pthread_join(tid, 0); +} + +int main() { + int status = 0; + thread_local_var = malloc(1337); + pid_t pid = fork(); + assert(pid >= 0); + if (pid > 0) { + waitpid(pid, &status, 0); + assert(WIFEXITED(status)); + return WEXITSTATUS(status); + } else { + // Spawn a thread and call exit() from there, to check that we track main + // thread's pid correctly even if leak checking is initiated from another + // thread. + ExitFromThread(); + } + return 0; +} diff --git a/lib/lsan/lit_tests/TestCases/high_allocator_contention.cc b/lib/lsan/lit_tests/TestCases/high_allocator_contention.cc new file mode 100644 index 000000000000..1cecb2a550a1 --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/high_allocator_contention.cc @@ -0,0 +1,48 @@ +// A benchmark that executes malloc/free pairs in parallel. +// Usage: ./a.out number_of_threads total_number_of_allocations +// RUN: %clangxx_lsan %s -o %t +// RUN: %t 5 1000000 2>&1 +#include <assert.h> +#include <pthread.h> +#include <stdlib.h> +#include <stdio.h> + +int num_threads; +int total_num_alloc; +const int kMaxNumThreads = 5000; +pthread_t tid[kMaxNumThreads]; + +pthread_cond_t cond = PTHREAD_COND_INITIALIZER; +pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; +bool go = false; + +void *thread_fun(void *arg) { + pthread_mutex_lock(&mutex); + while (!go) pthread_cond_wait(&cond, &mutex); + pthread_mutex_unlock(&mutex); + for (int i = 0; i < total_num_alloc / num_threads; i++) { + void *p = malloc(10); + __asm__ __volatile__("" : : "r"(p) : "memory"); + free((void *)p); + } + return 0; +} + +int main(int argc, char** argv) { + assert(argc == 3); + num_threads = atoi(argv[1]); + assert(num_threads > 0); + assert(num_threads <= kMaxNumThreads); + total_num_alloc = atoi(argv[2]); + assert(total_num_alloc > 0); + printf("%d threads, %d allocations in each\n", num_threads, + total_num_alloc / num_threads); + for (int i = 0; i < num_threads; i++) + pthread_create(&tid[i], 0, thread_fun, 0); + pthread_mutex_lock(&mutex); + go = true; + pthread_cond_broadcast(&cond); + pthread_mutex_unlock(&mutex); + for (int i = 0; i < num_threads; i++) pthread_join(tid[i], 0); + return 0; +} diff --git a/lib/lsan/lit_tests/TestCases/ignore_object.cc b/lib/lsan/lit_tests/TestCases/ignore_object.cc new file mode 100644 index 000000000000..cbc743b75497 --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/ignore_object.cc @@ -0,0 +1,30 @@ +// Test for __lsan_ignore_object(). +// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=0:verbosity=3" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE not %t 2>&1 | FileCheck %s + +#include <stdio.h> +#include <stdlib.h> + +#include "sanitizer/lsan_interface.h" + +int main() { + { + // The first malloc call can cause an allocation in libdl. Ignore it here so + // it doesn't show up in our output. + __lsan::ScopedDisabler d; + malloc(1); + } + // Explicitly ignored object. + void **p = new void *; + // Transitively ignored object. + *p = malloc(666); + // Non-ignored object. + volatile void *q = malloc(1337); + fprintf(stderr, "Test alloc: %p.\n", p); + __lsan_ignore_object(p); + 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/lib/lsan/lit_tests/TestCases/ignore_object_errors.cc b/lib/lsan/lit_tests/TestCases/ignore_object_errors.cc new file mode 100644 index 000000000000..2a6c72551772 --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/ignore_object_errors.cc @@ -0,0 +1,22 @@ +// Test for incorrect use of __lsan_ignore_object(). +// RUN: LSAN_BASE="verbosity=2" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE %t 2>&1 | FileCheck %s + +#include <stdio.h> +#include <stdlib.h> + +#include "sanitizer/lsan_interface.h" + +int main() { + void *p = malloc(1337); + fprintf(stderr, "Test alloc: %p.\n", p); + __lsan_ignore_object(p); + __lsan_ignore_object(p); + free(p); + __lsan_ignore_object(p); + return 0; +} +// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: heap object at [[ADDR]] is already being ignored +// CHECK: no heap object found at [[ADDR]] diff --git a/lib/lsan/lit_tests/TestCases/large_allocation_leak.cc b/lib/lsan/lit_tests/TestCases/large_allocation_leak.cc new file mode 100644 index 000000000000..57d056597ee2 --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/large_allocation_leak.cc @@ -0,0 +1,18 @@ +// Test that LargeMmapAllocator's chunks aren't reachable via some internal data structure. +// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE not %t 2>&1 | FileCheck %s + +#include <stdio.h> +#include <stdlib.h> + +int main() { + // maxsize in primary allocator is always less than this (1 << 25). + void *large_alloc = malloc(33554432); + fprintf(stderr, "Test alloc: %p.\n", large_alloc); + return 0; +} +// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Directly leaked 33554432 byte object at [[ADDR]] +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/lib/lsan/lit_tests/TestCases/leak_check_at_exit.cc b/lib/lsan/lit_tests/TestCases/leak_check_at_exit.cc new file mode 100644 index 000000000000..38c1063b6ebb --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/leak_check_at_exit.cc @@ -0,0 +1,19 @@ +// Test for the leak_check_at_exit flag. +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS="verbosity=1" %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do +// RUN: LSAN_OPTIONS="verbosity=1" %t 2>&1 | FileCheck %s --check-prefix=CHECK-do +// RUN: LSAN_OPTIONS="verbosity=1:leak_check_at_exit=0" ASAN_OPTIONS="$ASAN_OPTIONS:leak_check_at_exit=0" %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-do +// RUN: LSAN_OPTIONS="verbosity=1:leak_check_at_exit=0" ASAN_OPTIONS="$ASAN_OPTIONS:leak_check_at_exit=0" %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont + +#include <stdio.h> +#include <sanitizer/lsan_interface.h> + +int main(int argc, char *argv[]) { + printf("printf to break optimization\n"); + if (argc > 1) + __lsan_do_leak_check(); + return 0; +} + +// CHECK-do: SUMMARY: {{(Leak|Address)}}Sanitizer: +// CHECK-dont-NOT: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/lib/lsan/lit_tests/TestCases/link_turned_off.cc b/lib/lsan/lit_tests/TestCases/link_turned_off.cc new file mode 100644 index 000000000000..93628a1d15ee --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/link_turned_off.cc @@ -0,0 +1,24 @@ +// Test for disabling LSan at link-time. +// RUN: LSAN_BASE="use_stacks=0:use_registers=0" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE %t +// RUN: LSAN_OPTIONS=$LSAN_BASE not %t foo 2>&1 | FileCheck %s + +#include <sanitizer/lsan_interface.h> + +int argc_copy; + +extern "C" { +int __lsan_is_turned_off() { + return (argc_copy == 1); +} +} + +int main(int argc, char *argv[]) { + volatile int *x = new int; + *x = 42; + argc_copy = argc; + return 0; +} + +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: 4 byte(s) leaked in 1 allocation(s) diff --git a/lib/lsan/lit_tests/TestCases/pointer_to_self.cc b/lib/lsan/lit_tests/TestCases/pointer_to_self.cc new file mode 100644 index 000000000000..0d2818d2fa1d --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/pointer_to_self.cc @@ -0,0 +1,18 @@ +// Regression test: pointers to self should not confuse LSan into thinking the +// object is indirectly leaked. Only external pointers count. +// RUN: LSAN_BASE="report_objects=1:use_registers=0" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=0" not %t 2>&1 | FileCheck %s + +#include <stdio.h> +#include <stdlib.h> + +int main() { + void *p = malloc(1337); + *reinterpret_cast<void **>(p) = p; + fprintf(stderr, "Test alloc: %p.\n", p); +} +// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Directly leaked 1337 byte object at [[ADDR]] +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/lib/lsan/lit_tests/TestCases/sanity_check_pure_c.c b/lib/lsan/lit_tests/TestCases/sanity_check_pure_c.c new file mode 100644 index 000000000000..085412b47d55 --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/sanity_check_pure_c.c @@ -0,0 +1,10 @@ +// Check that we can build C code. +// RUN: %clang_lsan %s -o %t +#ifdef __cplusplus +#error "This test must be built in C mode" +#endif + +int main() { + // FIXME: ideally this should somehow check that we don't have libstdc++ + return 0; +} diff --git a/lib/lsan/lit_tests/TestCases/stale_stack_leak.cc b/lib/lsan/lit_tests/TestCases/stale_stack_leak.cc new file mode 100644 index 000000000000..fabfb4ff21a9 --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/stale_stack_leak.cc @@ -0,0 +1,42 @@ +// Test that out-of-scope local variables are ignored by LSan. +// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=1" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE not %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE":exitcode=0" %t 2>&1 | FileCheck --check-prefix=CHECK-sanity %s + +#include <stdio.h> +#include <stdlib.h> + +void **pp; + +// Put pointer far enough on the stack that LSan has space to run in without +// overwriting it. +// Hopefully the argument p will be passed on a register, saving us from false +// negatives. +__attribute__((noinline)) +void *PutPointerOnStaleStack(void *p) { + void *locals[2048]; + locals[0] = p; + pp = &locals[0]; + fprintf(stderr, "Test alloc: %p.\n", locals[0]); + return 0; +} + +int main() { + PutPointerOnStaleStack(malloc(1337)); + return 0; +} + +// This must run after LSan, to ensure LSan didn't overwrite the pointer before +// it had a chance to see it. If LSan is invoked with atexit(), this works. +// Otherwise, we need a different method. +__attribute__((destructor)) +void ConfirmPointerHasSurvived() { + fprintf(stderr, "Value after LSan: %p.\n", *pp); +} +// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK-sanity: Test alloc: [[ADDR:.*]]. +// CHECK: Directly leaked 1337 byte object at [[ADDR]] +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: +// CHECK-sanity: Value after LSan: [[ADDR]]. diff --git a/lib/lsan/lit_tests/TestCases/suppressions_default.cc b/lib/lsan/lit_tests/TestCases/suppressions_default.cc new file mode 100644 index 000000000000..9a165f8770f9 --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/suppressions_default.cc @@ -0,0 +1,29 @@ +// Test for ScopedDisabler. +// RUN: LSAN_BASE="use_registers=0:use_stacks=0" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE not %t 2>&1 | FileCheck %s + +#include <stdio.h> +#include <stdlib.h> + +#include "sanitizer/lsan_interface.h" + +extern "C" +const char *__lsan_default_suppressions() { + return "leak:*LSanTestLeakingFunc*"; +} + +void LSanTestLeakingFunc() { + void *p = malloc(666); + fprintf(stderr, "Test alloc: %p.\n", p); +} + +int main() { + LSanTestLeakingFunc(); + void *q = malloc(1337); + fprintf(stderr, "Test alloc: %p.\n", q); + return 0; +} +// CHECK: Suppressions used: +// CHECK: 1 666 *LSanTestLeakingFunc* +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: 1337 byte(s) leaked in 1 allocation(s) diff --git a/lib/lsan/lit_tests/TestCases/suppressions_file.cc b/lib/lsan/lit_tests/TestCases/suppressions_file.cc new file mode 100644 index 000000000000..9a165f8770f9 --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/suppressions_file.cc @@ -0,0 +1,29 @@ +// Test for ScopedDisabler. +// RUN: LSAN_BASE="use_registers=0:use_stacks=0" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE not %t 2>&1 | FileCheck %s + +#include <stdio.h> +#include <stdlib.h> + +#include "sanitizer/lsan_interface.h" + +extern "C" +const char *__lsan_default_suppressions() { + return "leak:*LSanTestLeakingFunc*"; +} + +void LSanTestLeakingFunc() { + void *p = malloc(666); + fprintf(stderr, "Test alloc: %p.\n", p); +} + +int main() { + LSanTestLeakingFunc(); + void *q = malloc(1337); + fprintf(stderr, "Test alloc: %p.\n", q); + return 0; +} +// CHECK: Suppressions used: +// CHECK: 1 666 *LSanTestLeakingFunc* +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: 1337 byte(s) leaked in 1 allocation(s) diff --git a/lib/lsan/lit_tests/TestCases/suppressions_file.cc.supp b/lib/lsan/lit_tests/TestCases/suppressions_file.cc.supp new file mode 100644 index 000000000000..8d8e560cba4c --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/suppressions_file.cc.supp @@ -0,0 +1 @@ +leak:*LSanTestLeakingFunc* diff --git a/lib/lsan/lit_tests/TestCases/swapcontext.cc b/lib/lsan/lit_tests/TestCases/swapcontext.cc new file mode 100644 index 000000000000..a06685ca2f03 --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/swapcontext.cc @@ -0,0 +1,42 @@ +// We can't unwind stack if we're running coroutines on heap-allocated +// memory. Make sure we don't report these leaks. + +// RUN: %clangxx_lsan %s -o %t +// RUN: %t 2>&1 +// RUN: not %t foo 2>&1 | FileCheck %s + +#include <stdio.h> +#include <ucontext.h> +#include <unistd.h> + +const int kStackSize = 1 << 20; + +void Child() { + int child_stack; + printf("Child: %p\n", &child_stack); + int *leaked = new int[666]; +} + +int main(int argc, char *argv[]) { + char stack_memory[kStackSize + 1]; + char *heap_memory = new char[kStackSize + 1]; + char *child_stack = (argc > 1) ? stack_memory : heap_memory; + + printf("Child stack: %p\n", child_stack); + ucontext_t orig_context; + ucontext_t child_context; + getcontext(&child_context); + child_context.uc_stack.ss_sp = child_stack; + child_context.uc_stack.ss_size = kStackSize / 2; + child_context.uc_link = &orig_context; + makecontext(&child_context, Child, 0); + if (swapcontext(&orig_context, &child_context) < 0) { + perror("swapcontext"); + return 1; + } + + delete[] heap_memory; + return 0; +} + +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: 2664 byte(s) leaked in 1 allocation(s) diff --git a/lib/lsan/lit_tests/TestCases/use_after_return.cc b/lib/lsan/lit_tests/TestCases/use_after_return.cc new file mode 100644 index 000000000000..93b0ea6068ef --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/use_after_return.cc @@ -0,0 +1,23 @@ +// Test that fake stack (introduced by ASan's use-after-return mode) is included +// in the root set. +// RUN: LSAN_BASE="report_objects=1:use_registers=0" +// RUN: %clangxx_lsan %s -O2 -o %t +// RUN: ASAN_OPTIONS=$ASAN_OPTIONS:detect_stack_use_after_return=1 LSAN_OPTIONS=$LSAN_BASE:"use_stacks=0" not %t 2>&1 | FileCheck %s +// RUN: ASAN_OPTIONS=$ASAN_OPTIONS:detect_stack_use_after_return=1 LSAN_OPTIONS=$LSAN_BASE:"use_stacks=1" %t 2>&1 +// RUN: ASAN_OPTIONS=$ASAN_OPTIONS:detect_stack_use_after_return=1 LSAN_OPTIONS="" %t 2>&1 + +#include <stdio.h> +#include <stdlib.h> + +int main() { + void *stack_var = malloc(1337); + fprintf(stderr, "Test alloc: %p.\n", stack_var); + // Take pointer to variable, to ensure it's not optimized into a register. + fprintf(stderr, "Stack var at: %p.\n", &stack_var); + // Do not return from main to prevent the pointer from going out of scope. + exit(0); +} +// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Directly leaked 1337 byte object at [[ADDR]] +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/lib/lsan/lit_tests/use_globals_initialized.cc b/lib/lsan/lit_tests/TestCases/use_globals_initialized.cc index 53c22c8ac057..5a7c48bdf49a 100644 --- a/lib/lsan/lit_tests/use_globals_initialized.cc +++ b/lib/lsan/lit_tests/TestCases/use_globals_initialized.cc @@ -1,7 +1,7 @@ -// Test that initialized globals are included in the root set. -// RUN: LSAN_BASE="report_blocks=1:use_stacks=0:use_registers=0" +// Test that initialized globals are included in the root set. +// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0" // RUN: %clangxx_lsan %s -o %t -// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_globals=0" %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_globals=0" not %t 2>&1 | FileCheck %s // RUN: LSAN_OPTIONS=$LSAN_BASE:"use_globals=1" %t 2>&1 // RUN: LSAN_OPTIONS="" %t 2>&1 @@ -16,6 +16,6 @@ int main() { return 0; } // CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Directly leaked 1337 byte object at [[ADDR]] // CHECK: LeakSanitizer: detected memory leaks -// CHECK: Directly leaked 1337 byte block at [[ADDR]] -// CHECK: SUMMARY: LeakSanitizer: +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/lib/lsan/lit_tests/TestCases/use_globals_uninitialized.cc b/lib/lsan/lit_tests/TestCases/use_globals_uninitialized.cc new file mode 100644 index 000000000000..e1d045e3f79f --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/use_globals_uninitialized.cc @@ -0,0 +1,21 @@ +// Test that uninitialized globals are included in the root set. +// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_globals=0" not %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_globals=1" %t 2>&1 +// RUN: LSAN_OPTIONS="" %t 2>&1 + +#include <stdio.h> +#include <stdlib.h> + +void *bss_var; + +int main() { + bss_var = malloc(1337); + fprintf(stderr, "Test alloc: %p.\n", bss_var); + return 0; +} +// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Directly leaked 1337 byte object at [[ADDR]] +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/lib/lsan/lit_tests/TestCases/use_registers.cc b/lib/lsan/lit_tests/TestCases/use_registers.cc new file mode 100644 index 000000000000..a7d8a69d7173 --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/use_registers.cc @@ -0,0 +1,51 @@ +// Test that registers of running threads are included in the root set. +// RUN: LSAN_BASE="report_objects=1:use_stacks=0" +// RUN: %clangxx_lsan -pthread %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_registers=0" not %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_registers=1" %t 2>&1 +// RUN: LSAN_OPTIONS="" %t 2>&1 + +#include <assert.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + +extern "C" +void *registers_thread_func(void *arg) { + int *sync = reinterpret_cast<int *>(arg); + void *p = malloc(1337); + // To store the pointer, choose a register which is unlikely to be reused by + // a function call. +#if defined(__i386__) + asm ( "mov %0, %%esi" + : + : "r" (p) + ); +#elif defined(__x86_64__) + asm ( "mov %0, %%r15" + : + : "r" (p) + ); +#else +#error "Test is not supported on this architecture." +#endif + fprintf(stderr, "Test alloc: %p.\n", p); + fflush(stderr); + __sync_fetch_and_xor(sync, 1); + while (true) + pthread_yield(); +} + +int main() { + int sync = 0; + pthread_t thread_id; + int res = pthread_create(&thread_id, 0, registers_thread_func, &sync); + assert(res == 0); + while (!__sync_fetch_and_xor(&sync, 0)) + pthread_yield(); + return 0; +} +// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Directly leaked 1337 byte object at [[ADDR]] +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/lib/lsan/lit_tests/TestCases/use_stacks.cc b/lib/lsan/lit_tests/TestCases/use_stacks.cc new file mode 100644 index 000000000000..4287a96b2285 --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/use_stacks.cc @@ -0,0 +1,20 @@ +// Test that stack of main thread is included in the root set. +// RUN: LSAN_BASE="report_objects=1:use_registers=0" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=0" not %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=1" %t 2>&1 +// RUN: LSAN_OPTIONS="" %t 2>&1 + +#include <stdio.h> +#include <stdlib.h> + +int main() { + void *stack_var = malloc(1337); + fprintf(stderr, "Test alloc: %p.\n", stack_var); + // Do not return from main to prevent the pointer from going out of scope. + exit(0); +} +// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Directly leaked 1337 byte object at [[ADDR]] +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/lib/lsan/lit_tests/TestCases/use_stacks_threaded.cc b/lib/lsan/lit_tests/TestCases/use_stacks_threaded.cc new file mode 100644 index 000000000000..c7dfaf8abad6 --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/use_stacks_threaded.cc @@ -0,0 +1,36 @@ +// Test that stacks of non-main threads are included in the root set. +// RUN: LSAN_BASE="report_objects=1:use_registers=0" +// RUN: %clangxx_lsan -pthread %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=0" not %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=1" %t 2>&1 +// RUN: LSAN_OPTIONS="" %t 2>&1 + +#include <assert.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + +extern "C" +void *stacks_thread_func(void *arg) { + int *sync = reinterpret_cast<int *>(arg); + void *p = malloc(1337); + fprintf(stderr, "Test alloc: %p.\n", p); + fflush(stderr); + __sync_fetch_and_xor(sync, 1); + while (true) + pthread_yield(); +} + +int main() { + int sync = 0; + pthread_t thread_id; + int res = pthread_create(&thread_id, 0, stacks_thread_func, &sync); + assert(res == 0); + while (!__sync_fetch_and_xor(&sync, 0)) + pthread_yield(); + return 0; +} +// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Directly leaked 1337 byte object at [[ADDR]] +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/lib/lsan/lit_tests/TestCases/use_tls_dynamic.cc b/lib/lsan/lit_tests/TestCases/use_tls_dynamic.cc new file mode 100644 index 000000000000..2570b63f0c5e --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/use_tls_dynamic.cc @@ -0,0 +1,33 @@ +// Test that dynamically allocated TLS space is included in the root set. +// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0" +// RUN: %clangxx %p/SharedLibs/huge_tls_lib_so.cc -fPIC -shared -o %t-so.so +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %t 2>&1 +// RUN: LSAN_OPTIONS="" %t 2>&1 + +#include <assert.h> +#include <dlfcn.h> +#include <stdio.h> +#include <stdlib.h> +#include <string> + +int main(int argc, char *argv[]) { + std::string path = std::string(argv[0]) + "-so.so"; + + void *handle = dlopen(path.c_str(), RTLD_LAZY); + assert(handle != 0); + typedef void **(* store_t)(void *p); + store_t StoreToTLS = (store_t)dlsym(handle, "StoreToTLS"); + assert(dlerror() == 0); + + void *p = malloc(1337); + void **p_in_tls = StoreToTLS(p); + assert(*p_in_tls == p); + fprintf(stderr, "Test alloc: %p.\n", p); + return 0; +} +// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: leaked 1337 byte object at [[ADDR]] +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_dynamic.cc b/lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_dynamic.cc new file mode 100644 index 000000000000..3dea41edddd4 --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_dynamic.cc @@ -0,0 +1,37 @@ +// Test that dynamically allocated thread-specific storage is included in the root set. +// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %t 2>&1 +// RUN: LSAN_OPTIONS="" %t 2>&1 + +#include <assert.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + +// From glibc: this many keys are stored in the thread descriptor directly. +const unsigned PTHREAD_KEY_2NDLEVEL_SIZE = 32; + +int main() { + static const unsigned kDummyKeysCount = PTHREAD_KEY_2NDLEVEL_SIZE; + int res; + pthread_key_t dummy_keys[kDummyKeysCount]; + for (unsigned i = 0; i < kDummyKeysCount; i++) { + res = pthread_key_create(&dummy_keys[i], NULL); + assert(res == 0); + } + pthread_key_t key; + res = pthread_key_create(&key, NULL); + assert(key >= PTHREAD_KEY_2NDLEVEL_SIZE); + assert(res == 0); + void *p = malloc(1337); + res = pthread_setspecific(key, p); + assert(res == 0); + fprintf(stderr, "Test alloc: %p.\n", p); + return 0; +} +// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: leaked 1337 byte object at [[ADDR]] +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_static.cc b/lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_static.cc new file mode 100644 index 000000000000..b75f15153863 --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_static.cc @@ -0,0 +1,31 @@ +// Test that statically allocated thread-specific storage is included in the root set. +// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %t 2>&1 +// RUN: LSAN_OPTIONS="" %t 2>&1 + +#include <assert.h> +#include <pthread.h> +#include <stdio.h> +#include <stdlib.h> + +// From glibc: this many keys are stored in the thread descriptor directly. +const unsigned PTHREAD_KEY_2NDLEVEL_SIZE = 32; + +int main() { + pthread_key_t key; + int res; + res = pthread_key_create(&key, NULL); + assert(res == 0); + assert(key < PTHREAD_KEY_2NDLEVEL_SIZE); + void *p = malloc(1337); + res = pthread_setspecific(key, p); + assert(res == 0); + fprintf(stderr, "Test alloc: %p.\n", p); + return 0; +} +// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Directly leaked 1337 byte object at [[ADDR]] +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/lib/lsan/lit_tests/TestCases/use_tls_static.cc b/lib/lsan/lit_tests/TestCases/use_tls_static.cc new file mode 100644 index 000000000000..9ccb2b2b7fb1 --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/use_tls_static.cc @@ -0,0 +1,21 @@ +// Test that statically allocated TLS space is included in the root set. +// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %t 2>&1 +// RUN: LSAN_OPTIONS="" %t 2>&1 + +#include <stdio.h> +#include <stdlib.h> + +__thread void *tls_var; + +int main() { + tls_var = malloc(1337); + fprintf(stderr, "Test alloc: %p.\n", tls_var); + return 0; +} +// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Directly leaked 1337 byte object at [[ADDR]] +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/lib/lsan/lit_tests/TestCases/use_unaligned.cc b/lib/lsan/lit_tests/TestCases/use_unaligned.cc new file mode 100644 index 000000000000..bc75f11b99f0 --- /dev/null +++ b/lib/lsan/lit_tests/TestCases/use_unaligned.cc @@ -0,0 +1,23 @@ +// Test that unaligned pointers are detected correctly. +// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_unaligned=0" not %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_unaligned=1" %t 2>&1 + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +void *arr[2]; + +int main() { + void *p = malloc(1337); + fprintf(stderr, "Test alloc: %p.\n", p); + char *char_arr = (char *)arr; + memcpy(char_arr + 1, &p, sizeof(p)); + return 0; +} +// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: Directly leaked 1337 byte object at [[ADDR]] +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/lib/lsan/lit_tests/Unit/lit.cfg b/lib/lsan/lit_tests/Unit/lit.cfg deleted file mode 100644 index bcd1de4477f1..000000000000 --- a/lib/lsan/lit_tests/Unit/lit.cfg +++ /dev/null @@ -1,26 +0,0 @@ -# -*- Python -*- - -import os - -def get_required_attr(config, attr_name): - attr_value = getattr(config, attr_name, None) - if not attr_value: - lit.fatal("No attribute %r in test configuration! You may need to run " - "tests from your build directory or add this attribute " - "to lit.site.cfg " % attr_name) - return attr_value - -# Setup attributes common for all compiler-rt projects. -compiler_rt_src_root = get_required_attr(config, 'compiler_rt_src_root') -compiler_rt_lit_unit_cfg = os.path.join(compiler_rt_src_root, "lib", - "lit.common.unit.cfg") -lit.load_config(config, compiler_rt_lit_unit_cfg) - -# Setup config name. -config.name = 'LeakSanitizer-Unit' - -# Setup test source and exec root. For unit tests, we define -# it as build directory with LSan unit tests. -lsan_binary_dir = get_required_attr(config, "lsan_binary_dir") -config.test_exec_root = os.path.join(lsan_binary_dir, "tests") -config.test_source_root = config.test_exec_root diff --git a/lib/lsan/lit_tests/Unit/lit.site.cfg.in b/lib/lsan/lit_tests/Unit/lit.site.cfg.in index 90c88c952156..a3a4e9ad0b13 100644 --- a/lib/lsan/lit_tests/Unit/lit.site.cfg.in +++ b/lib/lsan/lit_tests/Unit/lit.site.cfg.in @@ -1,17 +1,12 @@ ## Autogenerated by LLVM/Clang configuration. # Do not edit! -config.target_triple = "@TARGET_TRIPLE@" -config.llvm_src_root = "@LLVM_SOURCE_DIR@" -config.compiler_rt_src_root = "@COMPILER_RT_SOURCE_DIR@" -config.llvm_build_mode = "@LLVM_BUILD_MODE@" -config.lsan_binary_dir = "@LSAN_BINARY_DIR@" +# Load common config for all compiler-rt unit tests. +lit_config.load_config(config, "@COMPILER_RT_BINARY_DIR@/lib/lit.common.unit.configured") -try: - config.llvm_build_mode = config.llvm_build_mode % lit.params -except KeyError,e: - key, = e.args - lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key)) - -# Let the main config do the real work. -lit.load_config(config, "@LSAN_SOURCE_DIR@/lit_tests/Unit/lit.cfg") +# Setup config name. +config.name = 'LeakSanitizer-Unit' +# Setup test source and exec root. For unit tests, we define +# it as build directory with LSan unit tests. +config.test_exec_root = "@LSAN_BINARY_DIR@/tests" +config.test_source_root = config.test_exec_root diff --git a/lib/lsan/lit_tests/lit.cfg b/lib/lsan/lit_tests/lit.cfg deleted file mode 100644 index 48e1453334d0..000000000000 --- a/lib/lsan/lit_tests/lit.cfg +++ /dev/null @@ -1,50 +0,0 @@ -# -*- Python -*- - -import os - -def get_required_attr(config, attr_name): - attr_value = getattr(config, attr_name, None) - if not attr_value: - lit.fatal("No attribute %r in test configuration! You may need to run " - "tests from your build directory or add this attribute " - "to lit.site.cfg " % attr_name) - return attr_value - -# Setup attributes common for all compiler-rt projects. -compiler_rt_src_root = get_required_attr(config, 'compiler_rt_src_root') -compiler_rt_lit_unit_cfg = os.path.join(compiler_rt_src_root, "lib", - "lit.common.unit.cfg") -lit.load_config(config, compiler_rt_lit_unit_cfg) - -# Setup config name. -config.name = 'LeakSanitizer' - -# Setup source root. -config.test_source_root = os.path.dirname(__file__) - -# Setup attributes common for all compiler-rt projects. -compiler_rt_lit_cfg = os.path.join(compiler_rt_src_root, "lib", - "lit.common.cfg") -if (not compiler_rt_lit_cfg) or (not os.path.exists(compiler_rt_lit_cfg)): - lit.fatal("Can't find common compiler-rt lit config at: %r" - % compiler_rt_lit_cfg) -lit.load_config(config, compiler_rt_lit_cfg) - -clang_cxxflags = ("-ccc-cxx " - + "-g " - + "-O0 " - + "-m64 ") - -clang_lsan_cxxflags = clang_cxxflags + "-fsanitize=leak " - -config.substitutions.append( ("%clangxx ", (" " + config.clang + " " + - clang_cxxflags + " ")) ) -config.substitutions.append( ("%clangxx_lsan ", (" " + config.clang + " " + - clang_lsan_cxxflags + " ")) ) - -# Default test suffixes. -config.suffixes = ['.c', '.cc', '.cpp'] - -# LeakSanitizer tests are currently supported on x86-64 Linux only. -if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64']: - config.unsupported = True diff --git a/lib/lsan/lit_tests/lit.common.cfg b/lib/lsan/lit_tests/lit.common.cfg new file mode 100644 index 000000000000..96dc1b1f55fc --- /dev/null +++ b/lib/lsan/lit_tests/lit.common.cfg @@ -0,0 +1,43 @@ +# -*- Python -*- + +# Common configuration for running leak detection tests under LSan/ASan. + +import os + +def get_required_attr(config, attr_name): + attr_value = getattr(config, attr_name, None) + if not attr_value: + lit_config.fatal( + "No attribute %r in test configuration! You may need to run " + "tests from your build directory or add this attribute " + "to lit.site.cfg " % attr_name) + return attr_value + +# Setup source root. +lsan_lit_src_root = get_required_attr(config, 'lsan_lit_src_root') +config.test_source_root = os.path.join(lsan_lit_src_root, 'TestCases') + +clang_cxxflags = ("--driver-mode=g++ " + + "-g " + + "-O0 " + + "-m64 ") + +clang_cflags = ("-g " + + "-O0 " + + "-m64 ") + +config.clang_cxxflags = clang_cxxflags + +config.substitutions.append( ("%clangxx ", (" " + config.clang + " " + + clang_cxxflags + " ")) ) + +config.clang_cflags = clang_cflags + +config.substitutions.append( ("%clang ", (" " + config.clang + " " + + clang_cflags + " ")) ) + +# LeakSanitizer tests are currently supported on x86-64 Linux only. +if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64']: + config.unsupported = True + +config.suffixes = ['.c', '.cc', '.cpp'] diff --git a/lib/lsan/lit_tests/lit.site.cfg.in b/lib/lsan/lit_tests/lit.site.cfg.in deleted file mode 100644 index 3de98a9811f8..000000000000 --- a/lib/lsan/lit_tests/lit.site.cfg.in +++ /dev/null @@ -1,20 +0,0 @@ -config.host_os = "@HOST_OS@" -config.host_arch = "@HOST_ARCH@" -config.llvm_build_mode = "@LLVM_BUILD_MODE@" -config.llvm_src_root = "@LLVM_SOURCE_DIR@" -config.compiler_rt_src_root = "@COMPILER_RT_SOURCE_DIR@" -config.llvm_obj_root = "@LLVM_BINARY_DIR@" -config.llvm_tools_dir = "@LLVM_TOOLS_DIR@" -config.clang = "@LLVM_BINARY_DIR@/bin/clang" -config.compiler_rt_arch = "@COMPILER_RT_SUPPORTED_ARCH@" - -# LLVM tools dir can be passed in lit parameters, so try to -# apply substitution. -try: - config.llvm_tools_dir = config.llvm_tools_dir % lit.params -except KeyError,e: - key, = e.args - lit.fatal("unable to find %r parameter, use '--param=%s=VALUE'" % (key, key)) - -# Let the main config do the real work. -lit.load_config(config, "@CMAKE_CURRENT_SOURCE_DIR@/lit.cfg") |