aboutsummaryrefslogtreecommitdiff
path: root/lib/lsan/lit_tests
diff options
context:
space:
mode:
Diffstat (limited to 'lib/lsan/lit_tests')
-rw-r--r--lib/lsan/lit_tests/AsanConfig/lit.cfg32
-rw-r--r--lib/lsan/lit_tests/AsanConfig/lit.site.cfg.in8
-rw-r--r--lib/lsan/lit_tests/CMakeLists.txt25
-rw-r--r--lib/lsan/lit_tests/LsanConfig/lit.cfg30
-rw-r--r--lib/lsan/lit_tests/LsanConfig/lit.site.cfg.in8
-rw-r--r--lib/lsan/lit_tests/TestCases/SharedLibs/huge_tls_lib_so.cc12
-rw-r--r--lib/lsan/lit_tests/TestCases/SharedLibs/lit.local.cfg (renamed from lib/lsan/lit_tests/SharedLibs/lit.local.cfg)0
-rw-r--r--lib/lsan/lit_tests/TestCases/cleanup_in_tsd_destructor.cc45
-rw-r--r--lib/lsan/lit_tests/TestCases/disabler.cc23
-rw-r--r--lib/lsan/lit_tests/TestCases/disabler_in_tsd_destructor.cc38
-rw-r--r--lib/lsan/lit_tests/TestCases/do_leak_check_override.cc36
-rw-r--r--lib/lsan/lit_tests/TestCases/fork.cc24
-rw-r--r--lib/lsan/lit_tests/TestCases/fork_threaded.cc43
-rw-r--r--lib/lsan/lit_tests/TestCases/high_allocator_contention.cc48
-rw-r--r--lib/lsan/lit_tests/TestCases/ignore_object.cc30
-rw-r--r--lib/lsan/lit_tests/TestCases/ignore_object_errors.cc22
-rw-r--r--lib/lsan/lit_tests/TestCases/large_allocation_leak.cc18
-rw-r--r--lib/lsan/lit_tests/TestCases/leak_check_at_exit.cc19
-rw-r--r--lib/lsan/lit_tests/TestCases/link_turned_off.cc24
-rw-r--r--lib/lsan/lit_tests/TestCases/pointer_to_self.cc18
-rw-r--r--lib/lsan/lit_tests/TestCases/sanity_check_pure_c.c10
-rw-r--r--lib/lsan/lit_tests/TestCases/stale_stack_leak.cc42
-rw-r--r--lib/lsan/lit_tests/TestCases/suppressions_default.cc29
-rw-r--r--lib/lsan/lit_tests/TestCases/suppressions_file.cc29
-rw-r--r--lib/lsan/lit_tests/TestCases/suppressions_file.cc.supp1
-rw-r--r--lib/lsan/lit_tests/TestCases/swapcontext.cc42
-rw-r--r--lib/lsan/lit_tests/TestCases/use_after_return.cc23
-rw-r--r--lib/lsan/lit_tests/TestCases/use_globals_initialized.cc (renamed from lib/lsan/lit_tests/use_globals_initialized.cc)10
-rw-r--r--lib/lsan/lit_tests/TestCases/use_globals_uninitialized.cc21
-rw-r--r--lib/lsan/lit_tests/TestCases/use_registers.cc51
-rw-r--r--lib/lsan/lit_tests/TestCases/use_stacks.cc20
-rw-r--r--lib/lsan/lit_tests/TestCases/use_stacks_threaded.cc36
-rw-r--r--lib/lsan/lit_tests/TestCases/use_tls_dynamic.cc33
-rw-r--r--lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_dynamic.cc37
-rw-r--r--lib/lsan/lit_tests/TestCases/use_tls_pthread_specific_static.cc31
-rw-r--r--lib/lsan/lit_tests/TestCases/use_tls_static.cc21
-rw-r--r--lib/lsan/lit_tests/TestCases/use_unaligned.cc23
-rw-r--r--lib/lsan/lit_tests/Unit/lit.cfg26
-rw-r--r--lib/lsan/lit_tests/Unit/lit.site.cfg.in21
-rw-r--r--lib/lsan/lit_tests/lit.cfg50
-rw-r--r--lib/lsan/lit_tests/lit.common.cfg43
-rw-r--r--lib/lsan/lit_tests/lit.site.cfg.in20
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")