forked from OSchip/llvm-project
Reapply "Enable LSan for arm Linux"
This patch reapplies r299923 with typo fixed in BLX macros. llvm-svn: 299948
This commit is contained in:
parent
e1f12fadc0
commit
de3b9a2ecc
|
@ -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})
|
||||
|
|
|
@ -685,6 +685,7 @@ void *ThreadStackReuseFunc2(void *unused) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
#if !defined(__thumb__)
|
||||
TEST(AddressSanitizer, ThreadStackReuseTest) {
|
||||
pthread_t t;
|
||||
PTHREAD_CREATE(&t, 0, ThreadStackReuseFunc1, 0);
|
||||
|
@ -692,6 +693,7 @@ TEST(AddressSanitizer, ThreadStackReuseTest) {
|
|||
PTHREAD_CREATE(&t, 0, ThreadStackReuseFunc2, 0);
|
||||
PTHREAD_JOIN(t, 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(__SSE2__)
|
||||
#include <emmintrin.h>
|
||||
|
@ -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;
|
||||
|
@ -1103,6 +1110,7 @@ TEST(AddressSanitizer, PthreadExitTest) {
|
|||
PTHREAD_JOIN(t, 0);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// FIXME: Why does clang-cl define __EXCEPTIONS?
|
||||
#if defined(__EXCEPTIONS) && !defined(_WIN32)
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
@ -144,15 +147,38 @@ struct ScopedInterceptorDisabler {
|
|||
~ScopedInterceptorDisabler() { EnableInThisThread(); }
|
||||
};
|
||||
|
||||
// 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.
|
||||
inline bool IsSpecialCaseOfOperatorNew0(uptr chunk_beg, uptr chunk_size,
|
||||
uptr addr) {
|
||||
// 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 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) {
|
||||
#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.
|
||||
|
||||
void ForEachChunk(ForEachChunkCallback callback, void *arg);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -183,8 +183,8 @@ 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;
|
||||
|
||||
|
@ -192,14 +192,14 @@ 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
|
||||
|
@ -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)
|
||||
|
@ -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__)
|
||||
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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"
|
||||
|
||||
|
@ -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__)
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
|
||||
import lit.formats
|
||||
|
||||
|
@ -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')
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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__)
|
||||
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
# Common configuration for running leak detection tests under LSan/ASan.
|
||||
|
||||
import os
|
||||
import re
|
||||
|
||||
import lit.util
|
||||
|
||||
|
@ -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']
|
||||
|
|
|
@ -11,7 +11,7 @@ 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__)
|
||||
#elif defined(__i386__) || defined(__arm__)
|
||||
fprintf(stderr, "0x%8lx ", (unsigned long) p);
|
||||
#elif defined(__mips64)
|
||||
fprintf(stderr, "0x%010lx ", (unsigned long) p);
|
||||
|
|
Loading…
Reference in New Issue