summaryrefslogtreecommitdiff
path: root/test/lsan
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2015-01-07 19:55:37 +0000
committerDimitry Andric <dim@FreeBSD.org>2015-01-07 19:55:37 +0000
commitca9211ecdede9bdedb812b2243a4abdb8dacd1b9 (patch)
tree9b19e801150082c33e9152275829a6ce90614b55 /test/lsan
parent8ef50bf3d1c287b5013c3168de77a462dfce3495 (diff)
downloadsrc-test2-ca9211ecdede9bdedb812b2243a4abdb8dacd1b9.tar.gz
src-test2-ca9211ecdede9bdedb812b2243a4abdb8dacd1b9.zip
Notes
Diffstat (limited to 'test/lsan')
-rw-r--r--test/lsan/CMakeLists.txt23
-rw-r--r--test/lsan/TestCases/cleanup_in_tsd_destructor.cc45
-rw-r--r--test/lsan/TestCases/disabler.cc23
-rw-r--r--test/lsan/TestCases/disabler_in_tsd_destructor.cc38
-rw-r--r--test/lsan/TestCases/do_leak_check_override.cc36
-rw-r--r--test/lsan/TestCases/fork.cc24
-rw-r--r--test/lsan/TestCases/fork_threaded.cc43
-rw-r--r--test/lsan/TestCases/high_allocator_contention.cc48
-rw-r--r--test/lsan/TestCases/ignore_object.cc24
-rw-r--r--test/lsan/TestCases/ignore_object_errors.cc22
-rw-r--r--test/lsan/TestCases/large_allocation_leak.cc18
-rw-r--r--test/lsan/TestCases/leak_check_at_exit.cc21
-rw-r--r--test/lsan/TestCases/leak_check_before_thread_started.cc32
-rw-r--r--test/lsan/TestCases/link_turned_off.cc24
-rw-r--r--test/lsan/TestCases/new_array_with_dtor_0.cc19
-rw-r--r--test/lsan/TestCases/pointer_to_self.cc18
-rw-r--r--test/lsan/TestCases/print_suppressions.cc33
-rw-r--r--test/lsan/TestCases/register_root_region.cc32
-rw-r--r--test/lsan/TestCases/sanity_check_pure_c.c10
-rw-r--r--test/lsan/TestCases/stale_stack_leak.cc43
-rw-r--r--test/lsan/TestCases/suppressions_default.cc28
-rw-r--r--test/lsan/TestCases/suppressions_file.cc26
-rw-r--r--test/lsan/TestCases/swapcontext.cc47
-rw-r--r--test/lsan/TestCases/use_after_return.cc23
-rw-r--r--test/lsan/TestCases/use_globals_initialized.cc21
-rw-r--r--test/lsan/TestCases/use_globals_uninitialized.cc21
-rw-r--r--test/lsan/TestCases/use_poisoned_asan.cc25
-rw-r--r--test/lsan/TestCases/use_registers.cc52
-rw-r--r--test/lsan/TestCases/use_stacks.cc20
-rw-r--r--test/lsan/TestCases/use_stacks_threaded.cc37
-rw-r--r--test/lsan/TestCases/use_tls_dynamic.cc50
-rw-r--r--test/lsan/TestCases/use_tls_pthread_specific_dynamic.cc37
-rw-r--r--test/lsan/TestCases/use_tls_pthread_specific_static.cc31
-rw-r--r--test/lsan/TestCases/use_tls_static.cc21
-rw-r--r--test/lsan/TestCases/use_unaligned.cc23
-rw-r--r--test/lsan/lit.common.cfg51
-rw-r--r--test/lsan/lit.site.cfg.in8
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")