Skip to content

Commit

Permalink
Reapply "Enable LSan for arm Linux"
Browse files Browse the repository at this point in the history
This patch reapplies r299923 with typo fixed in BLX macros.

llvm-svn: 299948
  • Loading branch information
chefmax7 committed Apr 11, 2017
1 parent e1f12fa commit de3b9a2
Show file tree
Hide file tree
Showing 18 changed files with 160 additions and 25 deletions.
7 changes: 6 additions & 1 deletion compiler-rt/cmake/config-ix.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -164,7 +164,12 @@ 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} ${X86_64} ${MIPS64} ${ARM64})

if(APPLE)
set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64})
else()
set(ALL_LSAN_SUPPORTED_ARCH ${X86} ${X86_64} ${MIPS64} ${ARM64} ${ARM32})
endif()
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
8 changes: 8 additions & 0 deletions compiler-rt/lib/asan/tests/asan_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -685,13 +685,15 @@ void *ThreadStackReuseFunc2(void *unused) {
return 0;
}

#if !defined(__thumb__)
TEST(AddressSanitizer, ThreadStackReuseTest) {
pthread_t t;
PTHREAD_CREATE(&t, 0, ThreadStackReuseFunc1, 0);
PTHREAD_JOIN(t, 0);
PTHREAD_CREATE(&t, 0, ThreadStackReuseFunc2, 0);
PTHREAD_JOIN(t, 0);
}
#endif

#if defined(__SSE2__)
#include <emmintrin.h>
Expand Down Expand Up @@ -1091,6 +1093,11 @@ TEST(AddressSanitizer, ThreadedStressStackReuseTest) {
}
}

// pthread_exit tries to perform unwinding stuff that leads to dlopen'ing
// libgcc_s.so. dlopen in its turn calls malloc to store "libgcc_s.so" string
// that confuses LSan on Thumb because it fails to understand that this
// allocation happens in dynamic linker and should be ignored.
#if !defined(__thumb__)
static void *PthreadExit(void *a) {
pthread_exit(0);
return 0;
Expand All @@ -1103,6 +1110,7 @@ TEST(AddressSanitizer, PthreadExitTest) {
PTHREAD_JOIN(t, 0);
}
}
#endif

// FIXME: Why does clang-cl define __EXCEPTIONS?
#if defined(__EXCEPTIONS) && !defined(_WIN32)
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/lib/lsan/lsan_allocator.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
extern "C" void *memset(void *ptr, int value, uptr num);

namespace __lsan {
#if defined(__i386__)
#if defined(__i386__) || defined(__arm__)
static const uptr kMaxAllowedMallocSize = 1UL << 30;
#elif defined(__mips64) || defined(__aarch64__)
static const uptr kMaxAllowedMallocSize = 4UL << 30;
Expand Down
3 changes: 2 additions & 1 deletion compiler-rt/lib/lsan/lsan_allocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ struct ChunkMetadata {
u32 stack_trace_id;
};

#if defined(__mips64) || defined(__aarch64__) || defined(__i386__)
#if defined(__mips64) || defined(__aarch64__) || defined(__i386__) || \
defined(__arm__)
static const uptr kRegionSizeLog = 20;
static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog;
typedef TwoLevelByteMap<(kNumRegions >> 12), 1 << 12> ByteMap;
Expand Down
34 changes: 30 additions & 4 deletions compiler-rt/lib/lsan/lsan_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,9 @@
#elif defined(__i386__) && \
(SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC)
#define CAN_SANITIZE_LEAKS 1
#elif defined(__arm__) && \
SANITIZER_LINUX && !SANITIZER_ANDROID
#define CAN_SANITIZE_LEAKS 1
#else
#define CAN_SANITIZE_LEAKS 0
#endif
Expand Down Expand Up @@ -144,13 +147,36 @@ struct ScopedInterceptorDisabler {
~ScopedInterceptorDisabler() { EnableInThisThread(); }
};

// According to Itanium C++ ABI array cookie is a one word containing
// size of allocated array.
static inline bool IsItaniumABIArrayCookie(uptr chunk_beg, uptr chunk_size,
uptr addr) {
return chunk_size == sizeof(uptr) && chunk_beg + chunk_size == addr &&
*reinterpret_cast<uptr *>(chunk_beg) == 0;
}

// According to ARM C++ ABI array cookie consists of two words:
// struct array_cookie {
// std::size_t element_size; // element_size != 0
// std::size_t element_count;
// };
static inline bool IsARMABIArrayCookie(uptr chunk_beg, uptr chunk_size,
uptr addr) {
return chunk_size == 2 * sizeof(uptr) && chunk_beg + chunk_size == addr &&
*reinterpret_cast<uptr *>(chunk_beg + sizeof(uptr)) == 0;
}

// Special case for "new T[0]" where T is a type with DTOR.
// new T[0] will allocate one word for the array size (0) and store a pointer
// to the end of allocated chunk.
// new T[0] will allocate a cookie (one or two words) for the array size (0)
// and store a pointer to the end of allocated chunk. The actual cookie layout
// varies between platforms according to their C++ ABI implementation.
inline bool IsSpecialCaseOfOperatorNew0(uptr chunk_beg, uptr chunk_size,
uptr addr) {
return chunk_size == sizeof(uptr) && chunk_beg + chunk_size == addr &&
*reinterpret_cast<uptr *>(chunk_beg) == 0;
#if defined(__arm__)
return IsARMABIArrayCookie(chunk_beg, chunk_size, addr);
#else
return IsItaniumABIArrayCookie(chunk_beg, chunk_size, addr);
#endif
}

// The following must be implemented in the parent tool.
Expand Down
66 changes: 66 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_linux.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1283,6 +1283,72 @@ uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
: "memory");
return res;
}
#elif defined(__arm__) && SANITIZER_LINUX
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
int *parent_tidptr, void *newtls, int *child_tidptr) {
unsigned int res;
if (!fn || !child_stack)
return -EINVAL;
child_stack = (char *)child_stack - 2 * sizeof(unsigned int);
((unsigned int *)child_stack)[0] = (uptr)fn;
((unsigned int *)child_stack)[1] = (uptr)arg;
register int r0 __asm__("r0") = flags;
register void *r1 __asm__("r1") = child_stack;
register int *r2 __asm__("r2") = parent_tidptr;
register void *r3 __asm__("r3") = newtls;
register int *r4 __asm__("r4") = child_tidptr;
register int r7 __asm__("r7") = __NR_clone;

#if __ARM_ARCH > 4 || defined (__ARM_ARCH_4T__)
# define ARCH_HAS_BX
#endif
#if __ARM_ARCH > 4
# define ARCH_HAS_BLX
#endif

#ifdef ARCH_HAS_BX
# ifdef ARCH_HAS_BLX
# define BLX(R) "blx " #R "\n"
# else
# define BLX(R) "mov lr, pc; bx " #R "\n"
# endif
#else
# define BLX(R) "mov lr, pc; mov pc," #R "\n"
#endif

__asm__ __volatile__(
/* %r0 = syscall(%r7 = SYSCALL(clone),
* %r0 = flags,
* %r1 = child_stack,
* %r2 = parent_tidptr,
* %r3 = new_tls,
* %r4 = child_tidptr)
*/

/* Do the system call */
"swi 0x0\n"

/* if (%r0 != 0)
* return %r0;
*/
"cmp r0, #0\n"
"bne 1f\n"

/* In the child, now. Call "fn(arg)". */
"ldr r0, [sp, #4]\n"
"ldr ip, [sp], #8\n"
BLX(ip)
/* Call _exit(%r0). */
"mov r7, %7\n"
"swi 0x0\n"
"1:\n"
"mov %0, r0\n"
: "=r"(res)
: "r"(r0), "r"(r1), "r"(r2), "r"(r3), "r"(r4), "r"(r7),
"i"(__NR_exit)
: "memory");
return res;
}
#endif // defined(__x86_64__) && SANITIZER_LINUX

#if SANITIZER_ANDROID
Expand Down
3 changes: 2 additions & 1 deletion compiler-rt/lib/sanitizer_common/sanitizer_linux.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ 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(__i386__)
|| defined(__powerpc64__) || defined(__s390__) || defined(__i386__) \
|| defined(__arm__)
uptr internal_clone(int (*fn)(void *), void *child_stack, int flags, void *arg,
int *parent_tidptr, void *newtls, int *child_tidptr);
#endif
Expand Down
16 changes: 10 additions & 6 deletions compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cc
Original file line number Diff line number Diff line change
Expand Up @@ -183,23 +183,23 @@ void InitTlsSize() { }
#endif // !SANITIZER_FREEBSD && !SANITIZER_ANDROID && !SANITIZER_GO

#if (defined(__x86_64__) || defined(__i386__) || defined(__mips__) \
|| defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__)) \
&& SANITIZER_LINUX && !SANITIZER_ANDROID
|| defined(__aarch64__) || defined(__powerpc64__) || defined(__s390__) \
|| defined(__arm__)) && SANITIZER_LINUX && !SANITIZER_ANDROID
// sizeof(struct pthread) from glibc.
static atomic_uintptr_t kThreadDescriptorSize;

uptr ThreadDescriptorSize() {
uptr val = atomic_load(&kThreadDescriptorSize, memory_order_relaxed);
if (val)
return val;
#if defined(__x86_64__) || defined(__i386__)
#if defined(__x86_64__) || defined(__i386__) || defined(__arm__)
#ifdef _CS_GNU_LIBC_VERSION
char buf[64];
uptr len = confstr(_CS_GNU_LIBC_VERSION, buf, sizeof(buf));
if (len < sizeof(buf) && internal_strncmp(buf, "glibc 2.", 8) == 0) {
char *end;
int minor = internal_simple_strtoll(buf + 8, &end, 10);
if (end != buf + 8 && (*end == '\0' || *end == '.')) {
if (end != buf + 8 && (*end == '\0' || *end == '.' || *end == '-')) {
int patch = 0;
if (*end == '.')
// strtoll will return 0 if no valid conversion could be performed
Expand All @@ -208,6 +208,9 @@ uptr ThreadDescriptorSize() {
/* sizeof(struct pthread) values from various glibc versions. */
if (SANITIZER_X32)
val = 1728; // Assume only one particular version for x32.
// For ARM sizeof(struct pthread) changed in Glibc 2.23.
else if (SANITIZER_ARM)
val = minor <= 22 ? 1120 : 1216;
else if (minor <= 3)
val = FIRST_32_SECOND_64(1104, 1696);
else if (minor == 4)
Expand Down Expand Up @@ -293,7 +296,7 @@ uptr ThreadSelf() {
rdhwr %0,$29;\
.set pop" : "=r" (thread_pointer));
descr_addr = thread_pointer - kTlsTcbOffset - TlsPreTcbSize();
# elif defined(__aarch64__)
# elif defined(__aarch64__) || defined(__arm__)
descr_addr = reinterpret_cast<uptr>(__builtin_thread_pointer()) -
ThreadDescriptorSize();
# elif defined(__s390__)
Expand Down Expand Up @@ -342,7 +345,8 @@ static void GetTls(uptr *addr, uptr *size) {
*size = GetTlsSize();
*addr -= *size;
*addr += ThreadDescriptorSize();
# elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__)
# elif defined(__mips__) || defined(__aarch64__) || defined(__powerpc64__) \
|| defined(__arm__)
*addr = ThreadSelf();
*size = GetTlsSize();
# else
Expand Down
6 changes: 6 additions & 0 deletions compiler-rt/lib/sanitizer_common/sanitizer_platform.h
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,12 @@
# define SANITIZER_PPC64V2 0
#endif

#if defined(__arm__)
# define SANITIZER_ARM 1
#else
# define SANITIZER_ARM 0
#endif

// By default we allow to use SizeClassAllocator64 on 64-bit platform.
// But in some cases (e.g. AArch64's 39-bit address space) SizeClassAllocator64
// does not work well and we need to fallback to SizeClassAllocator32.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@

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

#include "sanitizer_stoptheworld.h"

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

#endif // SANITIZER_LINUX && (defined(__x86_64__) || defined(__mips__)
// || defined(__aarch64__) || defined(__powerpc64__)
// || defined(__s390__) || defined(__i386__)
// || defined(__s390__) || defined(__i386__) || defined(__arm__)
2 changes: 1 addition & 1 deletion compiler-rt/test/asan/TestCases/Linux/clang_gcc_abi.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
// RUN: %clangxx_asan -O2 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s
// RUN: %clangxx_asan -O3 -x c %s -o %t && not %run %t 2>&1 | FileCheck %s

// REQUIRES: arm-target-arch
// REQUIRES: arm-target-arch, fast-unwinder-works
// XFAIL: armv7l-unknown-linux-gnueabihf

#include <stdlib.h>
Expand Down
5 changes: 5 additions & 0 deletions compiler-rt/test/asan/lit.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import os
import platform
import re

import lit.formats

Expand Down Expand Up @@ -211,6 +212,10 @@ config.substitutions.append( ("%xdynamiclib_namespec", '%basename_t.dynamic') )
if config.target_arch != 'arm' and config.target_arch != 'armhf' and config.target_arch != 'aarch64':
config.available_features.add('stable-runtime')

# Fast unwinder doesn't work with Thumb
if not re.match('-mthumb', config.target_cflags):
config.available_features.add('fast-unwinder-works')

# Turn on leak detection on 64-bit Linux.
if config.host_os == 'Linux' and (config.target_arch == 'x86_64' or config.target_arch == 'i386'):
config.available_features.add('leak-detection')
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/lsan/TestCases/large_allocation_leak.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

// 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
// UNSUPPORTED: x86, arm

#include <stdio.h>
#include <stdlib.h>
Expand Down
8 changes: 5 additions & 3 deletions compiler-rt/test/lsan/TestCases/swapcontext.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
// 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
// RUN: LSAN_BASE="detect_leaks=1"
// RUN: LSAN_OPTIONS=$LSAN_BASE %run %t 2>&1
// RUN: LSAN_OPTIONS=$LSAN_BASE not %run %t foo 2>&1 | FileCheck %s
// UNSUPPORTED: arm

#include <stdio.h>
#if defined(__APPLE__)
Expand All @@ -23,7 +25,7 @@ void Child() {
}

int main(int argc, char *argv[]) {
char stack_memory[kStackSize + 1];
char stack_memory[kStackSize + 1] __attribute__((aligned(16)));
char *heap_memory = new char[kStackSize + 1];
char *child_stack = (argc > 1) ? stack_memory : heap_memory;

Expand Down
5 changes: 5 additions & 0 deletions compiler-rt/test/lsan/TestCases/use_registers.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,11 @@ void *registers_thread_func(void *arg) {
:
: "r" (p)
);
#elif defined(__arm__)
asm ( "mov r5, %0"
:
: "r" (p)
);
#else
#error "Test is not supported on this architecture."
#endif
Expand Down
2 changes: 1 addition & 1 deletion compiler-rt/test/lsan/TestCases/use_tls_dynamic.cc
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// 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
// UNSUPPORTED: i386-linux,i686-linux
// UNSUPPORTED: i386-linux,i686-linux,arm

#ifndef BUILD_DSO
#include <assert.h>
Expand Down
9 changes: 7 additions & 2 deletions compiler-rt/test/lsan/lit.common.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
# Common configuration for running leak detection tests under LSan/ASan.

import os
import re

import lit.util

Expand Down Expand Up @@ -51,8 +52,12 @@ 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 and mips64 Linux only.
if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64']:
# LeakSanitizer tests are currently supported on x86-64 Linux, arm Linux and mips64 Linux only.
if config.host_os not in ['Linux'] or config.host_arch not in ['x86_64', 'mips64', 'arm', 'armhf', armv7l]:
config.unsupported = True

# Don't support Thumb due to broken fast unwinder
if re.match('-mthumb', config.target_cflags):
config.unsupported = True

config.suffixes = ['.c', '.cc', '.cpp']

0 comments on commit de3b9a2

Please sign in to comment.