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 @@ -680,7 +680,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/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,13 @@ // 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) && \ - (SANITIZER_WORDSIZE == 64) && \ +#if (SANITIZER_LINUX || 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_MAC) #define CAN_SANITIZE_LEAKS 1 -#elif defined(__arm__) && \ - SANITIZER_LINUX && !SANITIZER_ANDROID +#elif defined(__arm__) && SANITIZER_LINUX #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 @@ -16,6 +16,7 @@ #include "sanitizer_common/sanitizer_common.h" #include "sanitizer_common/sanitizer_flag_parser.h" #include "sanitizer_common/sanitizer_flags.h" +#include "sanitizer_common/sanitizer_linux.h" #include "sanitizer_common/sanitizer_placement_new.h" #include "sanitizer_common/sanitizer_procmaps.h" #include "sanitizer_common/sanitizer_report_decorator.h" @@ -28,6 +29,7 @@ extern "C" const char *__lsan_current_stage = "unknown"; #if CAN_SANITIZE_LEAKS + namespace __lsan { // This mutex is used to prevent races between DoLeakCheck and IgnoreObject, and @@ -299,6 +301,22 @@ kReachable); } } +#if SANITIZER_ANDROID + if (HAS_ANDROID_THREAD_PROPERTIES_API) { + 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 is a potential race-condition here 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; @@ -314,6 +332,7 @@ // this and continue. LOG_THREADS("Thread %d has DTLS under destruction.\n", os_id); } +#endif } } } @@ -585,8 +604,17 @@ } static bool CheckForLeaks() { +#if SANITIZER_ANDROID + // Presence of the ThreadProperties API implies the presence of + // TLS support, which is required for calling __lsan_is_turned_off(). + // Therefore, this check must preceed that. + if (!HAS_ANDROID_THREAD_PROPERTIES_API) + return false; +#endif + 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 @@ -41,9 +41,28 @@ __attribute__((tls_model("initial-exec"))) THREADLOCAL int disable_counter; -bool DisabledInThisThread() { return disable_counter > 0; } -void DisableInThisThread() { disable_counter++; } +bool DisabledInThisThread() { +#if SANITIZER_ANDROID + // LSAN is only enabled with Android-S and up. + if (!HAS_ANDROID_THREAD_PROPERTIES_API) + return true; +#endif + return disable_counter > 0; +} +void DisableInThisThread() { +#if SANITIZER_ANDROID + // LSAN is only enabled with Android-S and up. + if (!HAS_ANDROID_THREAD_PROPERTIES_API) + return; +#endif + disable_counter++; +} void EnableInThisThread() { +#if SANITIZER_ANDROID + // LSAN is only enabled with Android-S and up. + if (!HAS_ANDROID_THREAD_PROPERTIES_API) + return; +#endif if (disable_counter == 0) { DisableCounterUnderflow(); } 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 31. +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 @@ -427,7 +427,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(); @@ -471,9 +483,6 @@ #elif SANITIZER_OPENBSD *addr = 0; *size = 0; -#elif SANITIZER_ANDROID - *addr = 0; - *size = 0; #elif SANITIZER_SOLARIS // FIXME *addr = 0;