[lsan] Enable LSan for x86 Linux.

People keep asking LSan to be available on 32 bit targets (e.g. https://github.com/google/sanitizers/issues/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
This commit is contained in:
Maxim Ostapenko 2017-01-23 08:45:17 +00:00
parent d501b18990
commit 2523faf677
38 changed files with 140 additions and 37 deletions

View File

@ -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})

View File

@ -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;

View File

@ -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

View File

@ -26,6 +26,8 @@
#include "lsan_common.h"
#include "lsan_thread.h"
#include <stddef.h>
using namespace __lsan;
extern "C" {
@ -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; \

View File

@ -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 "

View File

@ -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

View File

@ -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

View File

@ -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"
@ -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__)

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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>

View File

@ -1,5 +1,5 @@
// RUN: %clangxx -O0 %s -o %t && %run %t
// XFAIL: lsan
// UNSUPPORTED: lsan
#include <assert.h>
#include <sys/time.h>

View File

@ -26,6 +26,9 @@ config.available_features.add(config.tool_name)
if config.target_arch not in ['arm', 'armhf', 'aarch64']:
config.available_features.add('stable-runtime')
if config.host_os == 'Linux' and config.target_arch == 'i386' and config.tool_name == "lsan":
config.available_features.add("lsan-x86")
if config.host_os == 'Darwin':
# On Darwin, we default to `abort_on_error=1`, which would make tests run
# much slower. Let's override this and run lit tests with 'abort_on_error=0'.

View File

@ -11,6 +11,8 @@ void print_address(const char *str, int n, ...) {
// On FreeBSD, the %p conversion specifier works as 0x%x and thus does not
// match to the format used in the diagnotic message.
fprintf(stderr, "0x%012lx ", (unsigned long) p);
#elif defined(__i386__)
fprintf(stderr, "0x%8lx ", (unsigned long) p);
#elif defined(__mips64)
fprintf(stderr, "0x%010lx ", (unsigned long) p);
#endif