diff --git a/compiler-rt/cmake/config-ix.cmake b/compiler-rt/cmake/config-ix.cmake --- a/compiler-rt/cmake/config-ix.cmake +++ b/compiler-rt/cmake/config-ix.cmake @@ -682,7 +682,7 @@ endif() if (COMPILER_RT_HAS_SANITIZER_COMMON AND LSAN_SUPPORTED_ARCH AND - OS_NAME MATCHES "Darwin|Linux|NetBSD|Fuchsia") + OS_NAME MATCHES "Android|Darwin|Linux|NetBSD|Fuchsia") set(COMPILER_RT_HAS_LSAN TRUE) else() set(COMPILER_RT_HAS_LSAN FALSE) diff --git a/compiler-rt/lib/asan/tests/CMakeLists.txt b/compiler-rt/lib/asan/tests/CMakeLists.txt --- a/compiler-rt/lib/asan/tests/CMakeLists.txt +++ b/compiler-rt/lib/asan/tests/CMakeLists.txt @@ -288,6 +288,7 @@ $ $ $ + $ $ $ ${COMPILER_RT_GTEST_SOURCE} diff --git a/compiler-rt/lib/lsan/lsan.cpp b/compiler-rt/lib/lsan/lsan.cpp --- a/compiler-rt/lib/lsan/lsan.cpp +++ b/compiler-rt/lib/lsan/lsan.cpp @@ -60,7 +60,10 @@ cf.external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH"); cf.malloc_context_size = 30; cf.intercept_tls_get_addr = true; - cf.detect_leaks = true; + if (SANITIZER_ANDROID && !HAS_ANDROID_THREAD_PROPERTIES_API) + cf.detect_leaks = false; + else + cf.detect_leaks = CAN_SANITIZE_LEAKS; cf.exitcode = 23; OverrideCommonFlags(cf); } diff --git a/compiler-rt/lib/lsan/lsan_common.h b/compiler-rt/lib/lsan/lsan_common.h --- a/compiler-rt/lib/lsan/lsan_common.h +++ b/compiler-rt/lib/lsan/lsan_common.h @@ -29,16 +29,21 @@ // To enable LeakSanitizer on a new architecture, one needs to implement the // internal_clone function as well as (probably) adjust the TLS machinery for // the new architecture inside the sanitizer library. -#if (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) && \ +#if (SANITIZER_LINUX && \ + (!SANITIZER_ANDROID || defined(ANDROID_HAS_ELF_TLS)) || \ + SANITIZER_MAC) && \ (SANITIZER_WORDSIZE == 64) && \ (defined(__x86_64__) || defined(__mips64) || defined(__aarch64__) || \ defined(__powerpc64__) || defined(__s390x__)) #define CAN_SANITIZE_LEAKS 1 -#elif defined(__i386__) && \ - (SANITIZER_LINUX && !SANITIZER_ANDROID || SANITIZER_MAC) +#elif defined(__i386__) && \ + (SANITIZER_LINUX && \ + (!SANITIZER_ANDROID || defined(ANDROID_HAS_ELF_TLS)) || \ + SANITIZER_MAC) #define CAN_SANITIZE_LEAKS 1 -#elif defined(__arm__) && \ - SANITIZER_LINUX && !SANITIZER_ANDROID +// Exclude leak-detection on arm32 for Android because `__aeabi_read_tp` +// is missing. This caused a link error. +#elif defined(__arm__) && (SANITIZER_LINUX && !SANITIZER_ANDROID) #define CAN_SANITIZE_LEAKS 1 #elif SANITIZER_NETBSD || SANITIZER_FUCHSIA #define CAN_SANITIZE_LEAKS 1 diff --git a/compiler-rt/lib/lsan/lsan_common.cpp b/compiler-rt/lib/lsan/lsan_common.cpp --- a/compiler-rt/lib/lsan/lsan_common.cpp +++ b/compiler-rt/lib/lsan/lsan_common.cpp @@ -71,17 +71,17 @@ static const char *kSuppressionTypes[] = { kSuppressionLeak }; static const char kStdSuppressions[] = #if SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT - // For more details refer to the SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT - // definition. - "leak:*pthread_exit*\n" + // For more details refer to the SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT + // definition. + "leak:*pthread_exit*\n" #endif // SANITIZER_SUPPRESS_LEAK_ON_PTHREAD_EXIT #if SANITIZER_MAC - // For Darwin and os_log/os_trace: https://reviews.llvm.org/D35173 - "leak:*_os_trace*\n" + // For Darwin and os_log/os_trace: https://reviews.llvm.org/D35173 + "leak:*_os_trace*\n" #endif - // TLS leak in some glibc versions, described in - // https://sourceware.org/bugzilla/show_bug.cgi?id=12650. - "leak:*tls_get_addr*\n"; + // TLS leak in some glibc versions, described in + // https://sourceware.org/bugzilla/show_bug.cgi?id=12650. + "leak:*tls_get_addr*\n"; void InitializeSuppressions() { CHECK_EQ(nullptr, suppression_ctx); @@ -294,6 +294,20 @@ kReachable); } } +#if SANITIZER_ANDROID + auto *cb = +[](void *dtls_begin, void *dtls_end, uptr /*dso_idd*/, + void *arg) -> void { + ScanRangeForPointers(reinterpret_cast(dtls_begin), + reinterpret_cast(dtls_end), + reinterpret_cast(arg), "DTLS", + kReachable); + }; + + // FIXME: There might be a race-condition here (and in Bionic) if the + // thread is suspended in the middle of updating its DTLS. IOWs, we + // could scan already freed memory. (probably fine for now) + __libc_iterate_dynamic_tls(os_id, cb, frontier); +#else if (dtls && !DTLSInDestruction(dtls)) { for (uptr j = 0; j < dtls->dtv_size; ++j) { uptr dtls_beg = dtls->dtv[j].beg; @@ -309,6 +323,7 @@ // this and continue. LOG_THREADS("Thread %d has DTLS under destruction.\n", os_id); } +#endif } } } @@ -576,7 +591,7 @@ static bool CheckForLeaks() { if (&__lsan_is_turned_off && __lsan_is_turned_off()) - return false; + return false; EnsureMainThreadIDIsCorrect(); CheckForLeaksParam param; LockStuffAndStopTheWorld(CheckForLeaksCallback, ¶m); diff --git a/compiler-rt/lib/lsan/lsan_common_linux.cpp b/compiler-rt/lib/lsan/lsan_common_linux.cpp --- a/compiler-rt/lib/lsan/lsan_common_linux.cpp +++ b/compiler-rt/lib/lsan/lsan_common_linux.cpp @@ -31,6 +31,13 @@ static char linker_placeholder[sizeof(LoadedModule)] ALIGNED(64); static LoadedModule *linker = nullptr; +#if SANITIZER_ANDROID +#if __ANDROID_API__ < 21 +extern "C" __attribute__((weak)) int dl_iterate_phdr( + int (*)(struct dl_phdr_info *, size_t, void *), void *); +#endif +#endif + static bool IsLinker(const LoadedModule& module) { #if SANITIZER_USE_GETAUXVAL return module.base_address() == getauxval(AT_BASE); @@ -95,7 +102,14 @@ // Scans global variables for heap pointers. void ProcessGlobalRegions(Frontier *frontier) { - if (!flags()->use_globals) return; + if (!flags()->use_globals) { + if (SANITIZER_ANDROID) + // There are known malloc'ed global variables from libc[++] on Android. + // If use_globals is turned off, we could see leaks. + // Issue a warning in case users turn it off by accident. + Report("use_globals=0 on Android could lead to false reports."); + return; + } dl_iterate_phdr(ProcessGlobalRegionsCallback, frontier); } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_flags.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_flags.cpp --- a/compiler-rt/lib/sanitizer_common/sanitizer_flags.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_flags.cpp @@ -13,9 +13,10 @@ #include "sanitizer_flags.h" #include "sanitizer_common.h" +#include "sanitizer_flag_parser.h" #include "sanitizer_libc.h" +#include "sanitizer_linux.h" #include "sanitizer_list.h" -#include "sanitizer_flag_parser.h" namespace __sanitizer { @@ -124,6 +125,9 @@ // need to record coverage to generate coverage report. cf->coverage |= cf->html_cov_report; SetVerbosity(cf->verbosity); + + if (SANITIZER_ANDROID && !HAS_ANDROID_THREAD_PROPERTIES_API) + cf->detect_leaks = false; } } // namespace __sanitizer diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h b/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h --- a/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h @@ -104,8 +104,9 @@ // // FIXME: do we have anything like this on Mac? #ifndef SANITIZER_CAN_USE_PREINIT_ARRAY -#if ((SANITIZER_LINUX && !SANITIZER_ANDROID) || SANITIZER_OPENBSD || \ - SANITIZER_FUCHSIA || SANITIZER_NETBSD) && !defined(PIC) +#if (SANITIZER_LINUX || SANITIZER_OPENBSD || SANITIZER_FUCHSIA || \ + SANITIZER_NETBSD) && \ + !defined(PIC) #define SANITIZER_CAN_USE_PREINIT_ARRAY 1 // Before Solaris 11.4, .preinit_array is fully supported only with GNU ld. // FIXME: Check for those conditions. diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.h b/compiler-rt/lib/sanitizer_common/sanitizer_linux.h --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.h @@ -154,6 +154,16 @@ return reinterpret_cast(&__get_tls()[TLS_SLOT_SANITIZER]); } +// Bionic provides this API since S. +extern "C" SANITIZER_WEAK_ATTRIBUTE void __libc_get_static_tls_bounds(void **, + void **); +extern "C" SANITIZER_WEAK_ATTRIBUTE void __libc_iterate_dynamic_tls( + pid_t, void (*cb)(void *, void *, uptr, void *), void *); + +#define HAS_ANDROID_THREAD_PROPERTIES_API (&__libc_iterate_dynamic_tls != 0) + +#else +#define HAS_ANDROID_THREAD_PROPERTIES_API (0) #endif // SANITIZER_ANDROID } // namespace __sanitizer diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux_libcdep.cpp @@ -460,7 +460,19 @@ #if !SANITIZER_GO static void GetTls(uptr *addr, uptr *size) { -#if SANITIZER_LINUX && !SANITIZER_ANDROID +#if SANITIZER_ANDROID + if (HAS_ANDROID_THREAD_PROPERTIES_API) { + void *start_addr; + void *end_addr; + __libc_get_static_tls_bounds(&start_addr, &end_addr); + *addr = reinterpret_cast(start_addr); + *size = + reinterpret_cast(end_addr) - reinterpret_cast(start_addr); + } else { + *addr = 0; + *size = 0; + } +#elif SANITIZER_LINUX && !SANITIZER_ANDROID #if defined(__x86_64__) || defined(__i386__) || defined(__s390__) *addr = ThreadSelf(); *size = GetTlsSize(); @@ -504,9 +516,6 @@ #elif SANITIZER_OPENBSD *addr = 0; *size = 0; -#elif SANITIZER_ANDROID - *addr = 0; - *size = 0; #elif SANITIZER_SOLARIS // FIXME *addr = 0;