Skip to content

Commit

Permalink
[lsan] Enable LSan for x86 Linux.
Browse files Browse the repository at this point in the history
People keep asking LSan to be available on 32 bit targets (e.g. google/sanitizers#403)
despite the fact that false negative ratio might be huge (up to 85%). This happens for big real world applications
that may contain random binary data (e.g. browser), but for smaller apps situation is not so terrible and LSan still might be useful.
This patch adds initial support for x86 Linux (disabled by default), ARM32 is in TODO list.
We used this patch (well, ported to GCC) on our 32 bit mobile emulators and it worked pretty fine
thus I'm posting it here to initiate further discussion.

Differential Revision: https://reviews.llvm.org/D28609

llvm-svn: 292775
  • Loading branch information
Maxim Ostapenko committed Jan 23, 2017
1 parent d501b18 commit 2523faf
Show file tree
Hide file tree
Showing 38 changed files with 140 additions and 37 deletions.
2 changes: 1 addition & 1 deletion compiler-rt/cmake/config-ix.cmake
Expand Up @@ -164,7 +164,7 @@ set(ALL_SANITIZER_COMMON_SUPPORTED_ARCH ${X86} ${X86_64} ${PPC64}
set(ALL_ASAN_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64}
${MIPS32} ${MIPS64} ${PPC64} ${S390X})
set(ALL_DFSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64})
set(ALL_LSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64})
set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64})
set(ALL_MSAN_SUPPORTED_ARCH ${X86_64} ${MIPS64} ${ARM64} ${PPC64})
set(ALL_PROFILE_SUPPORTED_ARCH ${X86} ${X86_64} ${ARM32} ${ARM64} ${PPC64}
${MIPS32} ${MIPS64} ${S390X})
Expand Down
11 changes: 10 additions & 1 deletion compiler-rt/lib/lsan/lsan_allocator.cc
Expand Up @@ -28,12 +28,21 @@ namespace __lsan {
struct ChunkMetadata {
u8 allocated : 8; // Must be first.
ChunkTag tag : 2;
#if SANITIZER_WORDSIZE == 64
uptr requested_size : 54;
#else
uptr requested_size : 32;
uptr padding : 22;
#endif
u32 stack_trace_id;
};

#if defined(__mips64) || defined(__aarch64__)
#if defined(__mips64) || defined(__aarch64__) || defined(__i386__)
#if defined(__i386__)
static const uptr kMaxAllowedMallocSize = 1UL << 30;
#else
static const uptr kMaxAllowedMallocSize = 4UL << 30;
#endif
static const uptr kRegionSizeLog = 20;
static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
Expand Down
10 changes: 10 additions & 0 deletions compiler-rt/lib/lsan/lsan_common.h
Expand Up @@ -22,9 +22,19 @@
#include "sanitizer_common/sanitizer_stoptheworld.h"
#include "sanitizer_common/sanitizer_symbolizer.h"

// LeakSanitizer relies on some Glibc's internals (e.g. TLS machinery) thus
// supported for Linux only. Also, LSan doesn't like 32 bit architectures
// because of "small" (4 bytes) pointer size that leads to high false negative
// ratio on large leaks. But we still want to have it for some 32 bit arches
// (e.g. x86), see https://github.com/google/sanitizers/issues/403.
// To enable LeakSanitizer on new architecture, one need to implement
// internal_clone function as well as (probably) adjust TLS machinery for
// new architecture inside sanitizer library.
#if (SANITIZER_LINUX && !SANITIZER_ANDROID) && (SANITIZER_WORDSIZE == 64) \
&& (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__))
#define CAN_SANITIZE_LEAKS 1
#elif SANITIZER_LINUX && !SANITIZER_ANDROID && defined(__i386__)
#define CAN_SANITIZE_LEAKS 1
#else
#define CAN_SANITIZE_LEAKS 0
#endif
Expand Down
10 changes: 6 additions & 4 deletions compiler-rt/lib/lsan/lsan_interceptors.cc
Expand Up @@ -26,6 +26,8 @@
#include "lsan_common.h"
#include "lsan_thread.h"

#include <stddef.h>

using namespace __lsan;

extern "C" {
Expand Down Expand Up @@ -161,13 +163,13 @@ INTERCEPTOR(void, cfree, void *p) ALIAS(WRAPPER_NAME(free));
return Allocate(stack, size, 1, kAlwaysClearMemory);

INTERCEPTOR_ATTRIBUTE
void *operator new(uptr size) { OPERATOR_NEW_BODY; }
void *operator new(size_t size) { OPERATOR_NEW_BODY; }
INTERCEPTOR_ATTRIBUTE
void *operator new[](uptr size) { OPERATOR_NEW_BODY; }
void *operator new[](size_t size) { OPERATOR_NEW_BODY; }
INTERCEPTOR_ATTRIBUTE
void *operator new(uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
void *operator new(size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
INTERCEPTOR_ATTRIBUTE
void *operator new[](uptr size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }
void *operator new[](size_t size, std::nothrow_t const&) { OPERATOR_NEW_BODY; }

#define OPERATOR_DELETE_BODY \
ENSURE_LSAN_INITED; \
Expand Down
3 changes: 2 additions & 1 deletion compiler-rt/lib/sanitizer_common/sanitizer_flags.inc
Expand Up @@ -62,7 +62,8 @@ COMMON_FLAG(
COMMON_FLAG(
int, verbosity, 0,
"Verbosity level (0 - silent, 1 - a bit of output, 2+ - more output).")
COMMON_FLAG(bool, detect_leaks, true, "Enable memory leak detection.")
COMMON_FLAG(bool, detect_leaks, SANITIZER_WORDSIZE == 64,
"Enable memory leak detection.")
COMMON_FLAG(
bool, leak_check_at_exit, true,
"Invoke leak checking in an atexit handler. Has no effect if "
Expand Down
65 changes: 65 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_linux.cc
Expand Up @@ -1175,6 +1175,71 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
"r0", "r29", "r27", "r28");
return res;
}
#elif defined(__i386__) && SANITIZER_LINUX
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
int *parent_tidptr, void *newtls, int *child_tidptr) {
int res;
if (!fn || !child_stack)
return -EINVAL;
CHECK_EQ(0, (uptr)child_stack % 16);
child_stack = (char *)child_stack - 7 * sizeof(unsigned int);
((unsigned int *)child_stack)[0] = (uptr)flags;
((unsigned int *)child_stack)[1] = (uptr)0;
((unsigned int *)child_stack)[2] = (uptr)fn;
((unsigned int *)child_stack)[3] = (uptr)arg;
__asm__ __volatile__(
/* %eax = syscall(%eax = SYSCALL(clone),
* %ebx = flags,
* %ecx = child_stack,
* %edx = parent_tidptr,
* %esi = new_tls,
* %edi = child_tidptr)
*/

/* Obtain flags */
"movl (%%ecx), %%ebx\n"
/* Do the system call */
"pushl %%ebx\n"
"pushl %%esi\n"
"pushl %%edi\n"
/* Remember the flag value. */
"movl %%ebx, (%%ecx)\n"
"int $0x80\n"
"popl %%edi\n"
"popl %%esi\n"
"popl %%ebx\n"

/* if (%eax != 0)
* return;
*/

"test %%eax,%%eax\n"
"jnz 1f\n"

/* terminate the stack frame */
"xorl %%ebp,%%ebp\n"
/* Call FN. */
"call *%%ebx\n"
#ifdef PIC
"call here\n"
"here:\n"
"popl %%ebx\n"
"addl $_GLOBAL_OFFSET_TABLE_+[.-here], %%ebx\n"
#endif
/* Call exit */
"movl %%eax, %%ebx\n"
"movl %2, %%eax\n"
"int $0x80\n"
"1:\n"
: "=a" (res)
: "a"(SYSCALL(clone)), "i"(SYSCALL(exit)),
"c"(child_stack),
"d"(parent_tidptr),
"S"(newtls),
"D"(child_tidptr)
: "memory");
return res;
}
#endif // defined(__x86_64__) && SANITIZER_LINUX

#if SANITIZER_ANDROID
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/sanitizer_common/sanitizer_linux.h
Expand Up @@ -48,7 +48,7 @@ int internal_sigaction_syscall(int signum, const void *act, void *oldact);
#endif
void internal_sigdelset(__sanitizer_sigset_t *set, int signum);
#if defined(__x86_64__) || defined(__mips__) || defined(__aarch64__) \
|| defined(__powerpc64__) || defined(__s390__)
|| defined(__powerpc64__) || defined(__s390__) || defined(__i386__)
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
int *parent_tidptr, void *newtls, int *child_tidptr);
#endif
Expand Down
Expand Up @@ -16,7 +16,7 @@

#if SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__) || \
defined(__aarch64__) || defined(__powerpc64__) || \
defined(__s390__))
defined(__s390__) || defined(__i386__))

#include "sanitizer_stoptheworld.h"

Expand Down Expand Up @@ -528,4 +528,4 @@ uptr SuspendedThreadsList::RegisterCount() {

#endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__)
// || defined(__aarch64__) || defined(__powerpc64__)
// || defined(__s390__)
// || defined(__s390__) || defined(__i386__)
2 changes: 1 addition & 1 deletion compiler-rt/test/asan/lit.cfg
Expand Up @@ -205,7 +205,7 @@ if config.target_arch != 'arm' and config.target_arch != 'armhf' and config.targ
config.available_features.add('stable-runtime')

# Turn on leak detection on 64-bit Linux.
if config.host_os == 'Linux' and config.target_arch == 'x86_64':
if config.host_os == 'Linux' and (config.target_arch == 'x86_64' or config.target_arch == 'i386'):
config.available_features.add('leak-detection')

# Set LD_LIBRARY_PATH to pick dynamic runtime up properly.
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/lsan/TestCases/disabler.cc
@@ -1,5 +1,5 @@
// Test for ScopedDisabler.
// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=0:use_globals=0:use_tls=0"
// RUN: LSAN_BASE="detect_leaks=1: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

Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/lsan/TestCases/do_leak_check_override.cc
@@ -1,7 +1,7 @@
// 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: LSAN_BASE="detect_leaks=1: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
Expand Down
@@ -1,6 +1,6 @@
// A benchmark that executes malloc/free pairs in parallel.
// Usage: ./a.out number_of_threads total_number_of_allocations
// RUN: LSAN_BASE="use_ld_allocations=0"
// RUN: LSAN_BASE="detect_leaks=1:use_ld_allocations=0"
// RUN: %clangxx_lsan %s -o %t
// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t 5 1000000 2>&1
#include <assert.h>
Expand Down
6 changes: 5 additions & 1 deletion compiler-rt/test/lsan/TestCases/large_allocation_leak.cc
@@ -1,8 +1,12 @@
// 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: LSAN_BASE="detect_leaks=1: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

// For 32 bit LSan it's pretty likely that large chunks are "reachable" from some
// internal data structures (e.g. Glibc global data).
// UNSUPPORTED: x86

#include <stdio.h>
#include <stdlib.h>
#include "sanitizer_common/print_address.h"
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/lsan/TestCases/leak_check_at_exit.cc
@@ -1,5 +1,5 @@
// Test for the leak_check_at_exit flag.
// RUN: LSAN_BASE="use_stacks=0:use_registers=0"
// RUN: LSAN_BASE="detect_leaks=1: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
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/lsan/TestCases/link_turned_off.cc
@@ -1,5 +1,5 @@
// Test for disabling LSan at link-time.
// RUN: LSAN_BASE="use_stacks=0:use_registers=0"
// RUN: LSAN_BASE="detect_leaks=1: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
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/lsan/TestCases/pointer_to_self.cc
@@ -1,6 +1,6 @@
// 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: LSAN_BASE="detect_leaks=1: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

Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/lsan/TestCases/print_suppressions.cc
@@ -1,6 +1,6 @@
// 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: LSAN_BASE="detect_leaks=1: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
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/lsan/TestCases/recoverable_leak_check.cc
@@ -1,5 +1,5 @@
// Test for on-demand leak checking.
// RUN: LSAN_BASE="use_stacks=0:use_registers=0"
// RUN: LSAN_BASE="detect_leaks=1:use_stacks=0:use_registers=0"
// RUN: %clangxx_lsan %s -o %t
// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t foo 2>&1 | FileCheck %s
// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t 2>&1 | FileCheck %s
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/lsan/TestCases/register_root_region.cc
@@ -1,5 +1,5 @@
// Test for __lsan_(un)register_root_region().
// RUN: LSAN_BASE="use_stacks=0:use_registers=0"
// RUN: LSAN_BASE="detect_leaks=1: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
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/lsan/TestCases/stale_stack_leak.cc
@@ -1,5 +1,5 @@
// Test that out-of-scope local variables are ignored by LSan.
// RUN: LSAN_BASE="report_objects=1:use_registers=0:use_stacks=1"
// RUN: LSAN_BASE="detect_leaks=1: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
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/lsan/TestCases/suppressions_default.cc
@@ -1,4 +1,4 @@
// RUN: LSAN_BASE="use_registers=0:use_stacks=0"
// RUN: LSAN_BASE="detect_leaks=1:use_registers=0:use_stacks=0"
// RUN: %clangxx_lsan %s -o %t
// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t 2>&1 | FileCheck %s

Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/lsan/TestCases/suppressions_file.cc
@@ -1,4 +1,4 @@
// RUN: LSAN_BASE="use_registers=0:use_stacks=0"
// RUN: LSAN_BASE="detect_leaks=1:use_registers=0:use_stacks=0"
// RUN: %clangxx_lsan %s -o %t

// RUN: rm -f %t.supp
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/lsan/TestCases/use_after_return.cc
@@ -1,6 +1,6 @@
// 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: LSAN_BASE="detect_leaks=1: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
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/lsan/TestCases/use_globals_initialized.cc
@@ -1,5 +1,5 @@
// Test that initialized globals are included in the root set.
// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
// RUN: LSAN_BASE="detect_leaks=1: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
Expand Down
@@ -1,5 +1,5 @@
// Test that uninitialized globals are included in the root set.
// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
// RUN: LSAN_BASE="detect_leaks=1: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
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/lsan/TestCases/use_poisoned_asan.cc
@@ -1,6 +1,6 @@
// 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: LSAN_BASE="detect_leaks=1: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
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/lsan/TestCases/use_registers.cc
@@ -1,5 +1,5 @@
// Test that registers of running threads are included in the root set.
// RUN: LSAN_BASE="report_objects=1:use_stacks=0"
// RUN: LSAN_BASE="detect_leaks=1: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
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/lsan/TestCases/use_stacks.cc
@@ -1,5 +1,5 @@
// Test that stack of main thread is included in the root set.
// RUN: LSAN_BASE="report_objects=1:use_registers=0"
// RUN: LSAN_BASE="detect_leaks=1: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
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/lsan/TestCases/use_stacks_threaded.cc
@@ -1,5 +1,5 @@
// Test that stacks of non-main threads are included in the root set.
// RUN: LSAN_BASE="report_objects=1:use_registers=0"
// RUN: LSAN_BASE="detect_leaks=1: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
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/lsan/TestCases/use_tls_dynamic.cc
@@ -1,5 +1,5 @@
// Test that dynamically allocated TLS space is included in the root set.
// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0:use_ld_allocations=0"
// RUN: LSAN_BASE="detect_leaks=1:report_objects=1:use_stacks=0:use_registers=0:use_ld_allocations=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
Expand Down
@@ -1,5 +1,5 @@
// 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: LSAN_BASE="detect_leaks=1: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
Expand Down
@@ -1,5 +1,5 @@
// 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: LSAN_BASE="detect_leaks=1: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
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/lsan/TestCases/use_tls_static.cc
@@ -1,5 +1,5 @@
// 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: LSAN_BASE="detect_leaks=1: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
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/lsan/TestCases/use_unaligned.cc
@@ -1,5 +1,5 @@
// Test that unaligned pointers are detected correctly.
// RUN: LSAN_BASE="report_objects=1:use_stacks=0:use_registers=0"
// RUN: LSAN_BASE="detect_leaks=1: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
Expand Down
Expand Up @@ -2,6 +2,13 @@

// REQUIRES: stable-runtime

// For standalone LSan on x86 we have a problem: compiler spills the address
// of allocated at line 42 memory thus memory block allocated in Leak() function
// ends up to be classified as reachable despite the fact we zero out 'sink' at
// the last line of main function. The problem doesn't reproduce with ASan because
// quarantine prohibits memory block reuse for different allocations.
// XFAIL: lsan-x86

#include <sanitizer/common_interface_defs.h>
#include <stdio.h>

Expand Down

0 comments on commit 2523faf

Please sign in to comment.