diff options
author | Dimitry Andric <dim@FreeBSD.org> | 2015-01-07 19:55:37 +0000 |
---|---|---|
committer | Dimitry Andric <dim@FreeBSD.org> | 2015-01-07 19:55:37 +0000 |
commit | ca9211ecdede9bdedb812b2243a4abdb8dacd1b9 (patch) | |
tree | 9b19e801150082c33e9152275829a6ce90614b55 /test/lsan | |
parent | 8ef50bf3d1c287b5013c3168de77a462dfce3495 (diff) | |
download | src-test2-ca9211ecdede9bdedb812b2243a4abdb8dacd1b9.tar.gz src-test2-ca9211ecdede9bdedb812b2243a4abdb8dacd1b9.zip |
Notes
Diffstat (limited to 'test/lsan')
37 files changed, 1097 insertions, 0 deletions
diff --git a/test/lsan/CMakeLists.txt b/test/lsan/CMakeLists.txt new file mode 100644 index 000000000000..7f49b0d3983d --- /dev/null +++ b/test/lsan/CMakeLists.txt @@ -0,0 +1,23 @@ +set(LSAN_LIT_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + +set(LSAN_LIT_TEST_MODE "Standalone") +configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/LsanConfig/lit.site.cfg) + +set(LSAN_LIT_TEST_MODE "AddressSanitizer") +configure_lit_site_cfg( + ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.in + ${CMAKE_CURRENT_BINARY_DIR}/AsanConfig/lit.site.cfg) + +if(NOT APPLE AND NOT ANDROID) + set(LSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS}) + if(NOT COMPILER_RT_STANDALONE_BUILD) + list(APPEND LSAN_TEST_DEPS lsan asan) + endif() + add_lit_testsuite(check-lsan "Running the LeakSanitizer tests" + ${CMAKE_CURRENT_BINARY_DIR}/LsanConfig + ${CMAKE_CURRENT_BINARY_DIR}/AsanConfig + DEPENDS ${LSAN_TEST_DEPS}) + set_target_properties(check-lsan PROPERTIES FOLDER "LSan tests") +endif() diff --git a/test/lsan/TestCases/cleanup_in_tsd_destructor.cc b/test/lsan/TestCases/cleanup_in_tsd_destructor.cc new file mode 100644 index 000000000000..5335454ffbeb --- /dev/null +++ b/test/lsan/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 %run %t +// RUN: LSAN_OPTIONS=$LSAN_BASE:use_tls=0 not %run %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: [[ADDR]] (1337 bytes) diff --git a/test/lsan/TestCases/disabler.cc b/test/lsan/TestCases/disabler.cc new file mode 100644 index 000000000000..f83106501fa3 --- /dev/null +++ b/test/lsan/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 %run %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/test/lsan/TestCases/disabler_in_tsd_destructor.cc b/test/lsan/TestCases/disabler_in_tsd_destructor.cc new file mode 100644 index 000000000000..a0012c74dd96 --- /dev/null +++ b/test/lsan/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 %run %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/test/lsan/TestCases/do_leak_check_override.cc b/test/lsan/TestCases/do_leak_check_override.cc new file mode 100644 index 000000000000..bedb0cad6908 --- /dev/null +++ b/test/lsan/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 %run %t 2>&1 | FileCheck --check-prefix=CHECK-strict %s +// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %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/test/lsan/TestCases/fork.cc b/test/lsan/TestCases/fork.cc new file mode 100644 index 000000000000..9e72fe871cf1 --- /dev/null +++ b/test/lsan/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: %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/test/lsan/TestCases/fork_threaded.cc b/test/lsan/TestCases/fork_threaded.cc new file mode 100644 index 000000000000..62702b4dfe47 --- /dev/null +++ b/test/lsan/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: %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/test/lsan/TestCases/high_allocator_contention.cc b/test/lsan/TestCases/high_allocator_contention.cc new file mode 100644 index 000000000000..2543897bcbb4 --- /dev/null +++ b/test/lsan/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: %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/test/lsan/TestCases/ignore_object.cc b/test/lsan/TestCases/ignore_object.cc new file mode 100644 index 000000000000..38d76e6798b2 --- /dev/null +++ b/test/lsan/TestCases/ignore_object.cc @@ -0,0 +1,24 @@ +// 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: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck %s + +#include <stdio.h> +#include <stdlib.h> + +#include "sanitizer/lsan_interface.h" + +int main() { + // 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/test/lsan/TestCases/ignore_object_errors.cc b/test/lsan/TestCases/ignore_object_errors.cc new file mode 100644 index 000000000000..39b9b0288bb3 --- /dev/null +++ b/test/lsan/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 %run %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/test/lsan/TestCases/large_allocation_leak.cc b/test/lsan/TestCases/large_allocation_leak.cc new file mode 100644 index 000000000000..f41143a8a501 --- /dev/null +++ b/test/lsan/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 %run %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: LeakSanitizer: detected memory leaks +// CHECK: [[ADDR]] (33554432 bytes) +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/leak_check_at_exit.cc b/test/lsan/TestCases/leak_check_at_exit.cc new file mode 100644 index 000000000000..fe3f70e40005 --- /dev/null +++ b/test/lsan/TestCases/leak_check_at_exit.cc @@ -0,0 +1,21 @@ +// Test for the leak_check_at_exit flag. +// RUN: LSAN_BASE="use_stacks=0:use_registers=0" +// RUN: %clangxx_lsan %s -o %t +// 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 + +#include <stdio.h> +#include <stdlib.h> +#include <sanitizer/lsan_interface.h> + +int main(int argc, char *argv[]) { + fprintf(stderr, "Test alloc: %p.\n", malloc(1337)); + 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/test/lsan/TestCases/leak_check_before_thread_started.cc b/test/lsan/TestCases/leak_check_before_thread_started.cc new file mode 100644 index 000000000000..891cd699a255 --- /dev/null +++ b/test/lsan/TestCases/leak_check_before_thread_started.cc @@ -0,0 +1,32 @@ +// 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 +#include <assert.h> +#include <pthread.h> +#include <stdlib.h> +#include <unistd.h> + +void *func(void *arg) { + sleep(1); + free(arg); + return 0; +} + +void create_detached_thread() { + pthread_t thread_id; + pthread_attr_t attr; + + pthread_attr_init(&attr); + pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED); + + void *arg = malloc(1337); + assert(arg); + int res = pthread_create(&thread_id, &attr, func, arg); + assert(res == 0); +} + +int main() { + create_detached_thread(); +} diff --git a/test/lsan/TestCases/link_turned_off.cc b/test/lsan/TestCases/link_turned_off.cc new file mode 100644 index 000000000000..2482f6197d92 --- /dev/null +++ b/test/lsan/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 %run %t +// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %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/test/lsan/TestCases/new_array_with_dtor_0.cc b/test/lsan/TestCases/new_array_with_dtor_0.cc new file mode 100644 index 000000000000..59259616e827 --- /dev/null +++ b/test/lsan/TestCases/new_array_with_dtor_0.cc @@ -0,0 +1,19 @@ +// Regression test: +// https://code.google.com/p/address-sanitizer/issues/detail?id=257 +// RUN: %clangxx_lsan %s -o %t && %run %t 2>&1 | FileCheck %s + +#include <stdio.h> + +struct T { + ~T() { printf("~T\n"); } +}; + +T *t; + +int main(int argc, char **argv) { + t = new T[argc - 1]; + printf("OK\n"); +} + +// CHECK: OK + diff --git a/test/lsan/TestCases/pointer_to_self.cc b/test/lsan/TestCases/pointer_to_self.cc new file mode 100644 index 000000000000..63bde2ccf35d --- /dev/null +++ b/test/lsan/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 %run %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: LeakSanitizer: detected memory leaks +// CHECK: [[ADDR]] (1337 bytes) +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/print_suppressions.cc b/test/lsan/TestCases/print_suppressions.cc new file mode 100644 index 000000000000..b292c0a7c3cf --- /dev/null +++ b/test/lsan/TestCases/print_suppressions.cc @@ -0,0 +1,33 @@ +// Print matched suppressions only if print_suppressions=1 AND at least one is +// matched. Default is print_suppressions=true. +// RUN: LSAN_BASE="use_registers=0:use_stacks=0" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE:print_suppressions=0 %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont-print +// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t 2>&1 | FileCheck %s --check-prefix=CHECK-dont-print +// RUN: LSAN_OPTIONS=$LSAN_BASE:print_suppressions=0 %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-dont-print +// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t foo 2>&1 | FileCheck %s --check-prefix=CHECK-print + +#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(int argc, char **argv) { + printf("print for nonempty output\n"); + if (argc > 1) + LSanTestLeakingFunc(); + return 0; +} +// CHECK-print: Suppressions used: +// CHECK-print: 1 666 *LSanTestLeakingFunc* +// CHECK-dont-print-NOT: Suppressions used: diff --git a/test/lsan/TestCases/register_root_region.cc b/test/lsan/TestCases/register_root_region.cc new file mode 100644 index 000000000000..6fc84c2fb50f --- /dev/null +++ b/test/lsan/TestCases/register_root_region.cc @@ -0,0 +1,32 @@ +// Test for __lsan_(un)register_root_region(). +// RUN: LSAN_BASE="use_stacks=0:use_registers=0" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t +// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:use_root_regions=0 not %run %t 2>&1 | FileCheck %s + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <sys/mman.h> +#include <unistd.h> + +#include <sanitizer/lsan_interface.h> + +int main(int argc, char *argv[]) { + size_t size = getpagesize() * 2; + void *p = + mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); + assert(p); + // Make half of the memory inaccessible. LSan must not crash trying to read it. + assert(0 == mprotect((char *)p + size / 2, size / 2, PROT_NONE)); + + __lsan_register_root_region(p, size); + *((void **)p) = malloc(1337); + fprintf(stderr, "Test alloc: %p.\n", p); + if (argc > 1) + __lsan_unregister_root_region(p, size); + return 0; +} +// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: 1337 byte(s) leaked in 1 allocation(s) diff --git a/test/lsan/TestCases/sanity_check_pure_c.c b/test/lsan/TestCases/sanity_check_pure_c.c new file mode 100644 index 000000000000..085412b47d55 --- /dev/null +++ b/test/lsan/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/test/lsan/TestCases/stale_stack_leak.cc b/test/lsan/TestCases/stale_stack_leak.cc new file mode 100644 index 000000000000..4b8a54edf4cc --- /dev/null +++ b/test/lsan/TestCases/stale_stack_leak.cc @@ -0,0 +1,43 @@ +// 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 %run %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE":exitcode=0" %run %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)) +__attribute__((no_sanitize_address)) +void ConfirmPointerHasSurvived() { + fprintf(stderr, "Value after LSan: %p.\n", *pp); +} +// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK-sanity: Test alloc: [[ADDR:.*]]. +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: [[ADDR]] (1337 bytes) +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: +// CHECK-sanity: Value after LSan: [[ADDR]]. diff --git a/test/lsan/TestCases/suppressions_default.cc b/test/lsan/TestCases/suppressions_default.cc new file mode 100644 index 000000000000..b4c0de016cd1 --- /dev/null +++ b/test/lsan/TestCases/suppressions_default.cc @@ -0,0 +1,28 @@ +// RUN: LSAN_BASE="use_registers=0:use_stacks=0" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %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/test/lsan/TestCases/suppressions_file.cc b/test/lsan/TestCases/suppressions_file.cc new file mode 100644 index 000000000000..16ad9323461e --- /dev/null +++ b/test/lsan/TestCases/suppressions_file.cc @@ -0,0 +1,26 @@ +// 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:%t" > %t.supp2 +// RUN: LSAN_OPTIONS=$LSAN_BASE:suppressions="%t.supp2":symbolize=false %run %t + +#include <stdio.h> +#include <stdlib.h> + +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/test/lsan/TestCases/swapcontext.cc b/test/lsan/TestCases/swapcontext.cc new file mode 100644 index 000000000000..f7e95ed2ca5c --- /dev/null +++ b/test/lsan/TestCases/swapcontext.cc @@ -0,0 +1,47 @@ +// 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: %run %t 2>&1 +// RUN: not %run %t foo 2>&1 | FileCheck %s + +#include <stdio.h> +#if defined(__APPLE__) +// Note: ucontext.h is deprecated on OSX, so this test may stop working +// someday. We define _XOPEN_SOURCE to keep using ucontext.h for now. +#define _XOPEN_SOURCE 1 +#endif +#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/test/lsan/TestCases/use_after_return.cc b/test/lsan/TestCases/use_after_return.cc new file mode 100644 index 000000000000..eb917c01ea80 --- /dev/null +++ b/test/lsan/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 %run %t 2>&1 | FileCheck %s +// RUN: ASAN_OPTIONS=$ASAN_OPTIONS:detect_stack_use_after_return=1 LSAN_OPTIONS=$LSAN_BASE:"use_stacks=1" %run %t 2>&1 +// RUN: ASAN_OPTIONS=$ASAN_OPTIONS:detect_stack_use_after_return=1 LSAN_OPTIONS="" %run %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: LeakSanitizer: detected memory leaks +// CHECK: [[ADDR]] (1337 bytes) +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/use_globals_initialized.cc b/test/lsan/TestCases/use_globals_initialized.cc new file mode 100644 index 000000000000..172d22a9f056 --- /dev/null +++ b/test/lsan/TestCases/use_globals_initialized.cc @@ -0,0 +1,21 @@ +// 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" not %run %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_globals=1" %run %t 2>&1 +// RUN: LSAN_OPTIONS="" %run %t 2>&1 + +#include <stdio.h> +#include <stdlib.h> + +void *data_var = (void *)1; + +int main() { + data_var = malloc(1337); + fprintf(stderr, "Test alloc: %p.\n", data_var); + return 0; +} +// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: [[ADDR]] (1337 bytes) +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/use_globals_uninitialized.cc b/test/lsan/TestCases/use_globals_uninitialized.cc new file mode 100644 index 000000000000..2daa661611f4 --- /dev/null +++ b/test/lsan/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 %run %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_globals=1" %run %t 2>&1 +// RUN: LSAN_OPTIONS="" %run %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: LeakSanitizer: detected memory leaks +// CHECK: [[ADDR]] (1337 bytes) +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/use_poisoned_asan.cc b/test/lsan/TestCases/use_poisoned_asan.cc new file mode 100644 index 000000000000..a1c544c55f28 --- /dev/null +++ b/test/lsan/TestCases/use_poisoned_asan.cc @@ -0,0 +1,25 @@ +// ASan-poisoned memory should be ignored if use_poisoned is false. +// REQUIRES: asan +// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0" +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_poisoned=0" not %run %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_poisoned=1" %run %t 2>&1 + +#include <stdio.h> +#include <stdlib.h> +#include <sanitizer/asan_interface.h> +#include <assert.h> + +void **p; + +int main() { + p = new void *; + *p = malloc(1337); + fprintf(stderr, "Test alloc: %p.\n", *p); + __asan_poison_memory_region(p, sizeof(*p)); + return 0; +} +// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: [[ADDR]] (1337 bytes) +// CHECK: SUMMARY: AddressSanitizer: diff --git a/test/lsan/TestCases/use_registers.cc b/test/lsan/TestCases/use_registers.cc new file mode 100644 index 000000000000..ce11c3f77bcb --- /dev/null +++ b/test/lsan/TestCases/use_registers.cc @@ -0,0 +1,52 @@ +// 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 %run %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_registers=1" %run %t 2>&1 +// RUN: LSAN_OPTIONS="" %run %t 2>&1 + +#include <assert.h> +#include <pthread.h> +#include <sched.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) + sched_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)) + sched_yield(); + return 0; +} +// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: [[ADDR]] (1337 bytes) +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/use_stacks.cc b/test/lsan/TestCases/use_stacks.cc new file mode 100644 index 000000000000..7afcde15c733 --- /dev/null +++ b/test/lsan/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 %run %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=1" %run %t 2>&1 +// RUN: LSAN_OPTIONS="" %run %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: LeakSanitizer: detected memory leaks +// CHECK: [[ADDR]] (1337 bytes) +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/use_stacks_threaded.cc b/test/lsan/TestCases/use_stacks_threaded.cc new file mode 100644 index 000000000000..a1d4383e9569 --- /dev/null +++ b/test/lsan/TestCases/use_stacks_threaded.cc @@ -0,0 +1,37 @@ +// 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 %run %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_stacks=1" %run %t 2>&1 +// RUN: LSAN_OPTIONS="" %run %t 2>&1 + +#include <assert.h> +#include <pthread.h> +#include <sched.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) + sched_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)) + sched_yield(); + return 0; +} +// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: [[ADDR]] (1337 bytes) +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/use_tls_dynamic.cc b/test/lsan/TestCases/use_tls_dynamic.cc new file mode 100644 index 000000000000..860db041ae40 --- /dev/null +++ b/test/lsan/TestCases/use_tls_dynamic.cc @@ -0,0 +1,50 @@ +// 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 %s -DBUILD_DSO -fPIC -shared -o %t-so.so +// RUN: %clangxx_lsan %s -o %t +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=0" not %run %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1 +// RUN: LSAN_OPTIONS="" %run %t 2>&1 + +#ifndef BUILD_DSO +#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); + // If we don't know about dynamic TLS, we will return a false leak above. + void **p_in_tls = StoreToTLS(p); + assert(*p_in_tls == p); + fprintf(stderr, "Test alloc: %p.\n", p); + return 0; +} +// CHECK: Test alloc: [[ADDR:.*]]. +// CHECK: LeakSanitizer: detected memory leaks +// CHECK: [[ADDR]] (1337 bytes) +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: + +#else // BUILD_DSO +// 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]; +} +#endif // BUILD_DSO diff --git a/test/lsan/TestCases/use_tls_pthread_specific_dynamic.cc b/test/lsan/TestCases/use_tls_pthread_specific_dynamic.cc new file mode 100644 index 000000000000..14883712e608 --- /dev/null +++ b/test/lsan/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 %run %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1 +// RUN: LSAN_OPTIONS="" %run %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: LeakSanitizer: detected memory leaks +// CHECK: [[ADDR]] (1337 bytes) +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/use_tls_pthread_specific_static.cc b/test/lsan/TestCases/use_tls_pthread_specific_static.cc new file mode 100644 index 000000000000..1fd5681b6080 --- /dev/null +++ b/test/lsan/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 %run %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1 +// RUN: LSAN_OPTIONS="" %run %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: LeakSanitizer: detected memory leaks +// CHECK: [[ADDR]] (1337 bytes) +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/use_tls_static.cc b/test/lsan/TestCases/use_tls_static.cc new file mode 100644 index 000000000000..50db23abb825 --- /dev/null +++ b/test/lsan/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 %run %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_tls=1" %run %t 2>&1 +// RUN: LSAN_OPTIONS="" %run %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: LeakSanitizer: detected memory leaks +// CHECK: [[ADDR]] (1337 bytes) +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/TestCases/use_unaligned.cc b/test/lsan/TestCases/use_unaligned.cc new file mode 100644 index 000000000000..3e43ed4c092c --- /dev/null +++ b/test/lsan/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 %run %t 2>&1 | FileCheck %s +// RUN: LSAN_OPTIONS=$LSAN_BASE:"use_unaligned=1" %run %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: LeakSanitizer: detected memory leaks +// CHECK: [[ADDR]] (1337 bytes) +// CHECK: SUMMARY: {{(Leak|Address)}}Sanitizer: diff --git a/test/lsan/lit.common.cfg b/test/lsan/lit.common.cfg new file mode 100644 index 000000000000..bd1aa2769c42 --- /dev/null +++ b/test/lsan/lit.common.cfg @@ -0,0 +1,51 @@ +# -*- 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 attr_value == None: + 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. +config.test_source_root = os.path.dirname(__file__) + +# Choose between standalone and LSan+ASan modes. +lsan_lit_test_mode = get_required_attr(config, 'lsan_lit_test_mode') +if lsan_lit_test_mode == "Standalone": + config.name = "LeakSanitizer-Standalone" + lsan_cflags = ["-fsanitize=leak"] +elif lsan_lit_test_mode == "AddressSanitizer": + config.name = "LeakSanitizer-AddressSanitizer" + lsan_cflags = ["-fsanitize=address"] + config.available_features.add('asan') +else: + lit_config.fatal("Unknown LSan test mode: %r" % lsan_lit_test_mode) + +clang_cflags = ["-O0", "-m64"] + config.debug_info_flags +clang_cxxflags = config.cxx_mode_flags + clang_cflags +clang_lsan_cflags = clang_cflags + lsan_cflags +clang_lsan_cxxflags = clang_cxxflags + lsan_cflags + +config.clang_cflags = clang_cflags +config.clang_cxxflags = clang_cxxflags + +def build_invocation(compile_flags): + return " " + " ".join([config.clang] + compile_flags) + " " + +config.substitutions.append( ("%clang ", build_invocation(clang_cflags)) ) +config.substitutions.append( ("%clangxx ", build_invocation(clang_cxxflags)) ) +config.substitutions.append( ("%clang_lsan ", build_invocation(clang_lsan_cflags)) ) +config.substitutions.append( ("%clangxx_lsan ", build_invocation(clang_lsan_cxxflags)) ) + +# 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/test/lsan/lit.site.cfg.in b/test/lsan/lit.site.cfg.in new file mode 100644 index 000000000000..7d2877bdc528 --- /dev/null +++ b/test/lsan/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@/test/lit.common.configured") + +# Tool-specific config options. +config.lsan_lit_test_mode = "@LSAN_LIT_TEST_MODE@" + +# Load tool-specific config that would do the real work. +lit_config.load_config(config, "@LSAN_LIT_SOURCE_DIR@/lit.common.cfg") |