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/asan/CMakeLists.txt b/compiler-rt/lib/asan/CMakeLists.txt --- a/compiler-rt/lib/asan/CMakeLists.txt +++ b/compiler-rt/lib/asan/CMakeLists.txt @@ -86,6 +86,7 @@ set(ASAN_DYNAMIC_LINK_FLAGS ${SANITIZER_COMMON_LINK_FLAGS}) if(ANDROID) + list(APPEND ASAN_CFLAGS -fno-emulated-tls) # Put most Sanitizer shared libraries in the global group. For more details, see # android-changes-for-ndk-developers.md#changes-to-library-search-order if (COMPILER_RT_HAS_Z_GLOBAL) diff --git a/compiler-rt/lib/lsan/CMakeLists.txt b/compiler-rt/lib/lsan/CMakeLists.txt --- a/compiler-rt/lib/lsan/CMakeLists.txt +++ b/compiler-rt/lib/lsan/CMakeLists.txt @@ -33,6 +33,10 @@ set(LSAN_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}) +if(ANDROID) + list(APPEND LSAN_CFLAGS -fno-emulated-tls) +endif() + add_compiler_rt_object_libraries(RTLSanCommon OS ${SANITIZER_COMMON_SUPPORTED_OS} ARCHS ${LSAN_COMMON_SUPPORTED_ARCH} 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; diff --git a/compiler-rt/test/asan/lit.cfg.py b/compiler-rt/test/asan/lit.cfg.py --- a/compiler-rt/test/asan/lit.cfg.py +++ b/compiler-rt/test/asan/lit.cfg.py @@ -194,8 +194,8 @@ if re.search('mthumb', config.target_cflags) is None: config.available_features.add('fast-unwinder-works') -# Turn on leak detection on 64-bit Linux. -leak_detection_linux = (config.host_os == 'Linux') and (not config.android) and (config.target_arch == 'x86_64' or config.target_arch == 'i386') +# Turn on leak detection on Linux. +leak_detection_linux = (config.host_os == 'Linux') and (not config.android or 'android-31' in config.available_features) and (config.target_arch == 'x86_64' or config.target_arch == 'i386') leak_detection_mac = (config.host_os == 'Darwin') and (config.target_arch == 'x86_64') leak_detection_netbsd = (config.host_os == 'NetBSD') and (config.target_arch in ['x86_64', 'i386']) if leak_detection_linux or leak_detection_mac or leak_detection_netbsd: @@ -235,6 +235,10 @@ if config.host_os not in ['Linux', 'Darwin', 'FreeBSD', 'SunOS', 'Windows', 'NetBSD']: config.unsupported = True +# Only run the tests on Android, if required API level is present. +if config.android and 'android-31' not in config.available_features: + config.unsupported = True + if not config.parallelism_group: config.parallelism_group = 'shadow-memory' diff --git a/compiler-rt/test/lit.common.cfg.py b/compiler-rt/test/lit.common.cfg.py --- a/compiler-rt/test/lit.common.cfg.py +++ b/compiler-rt/test/lit.common.cfg.py @@ -386,6 +386,8 @@ config.available_features.add('android-26') if android_api_level >= 28: config.available_features.add('android-28') + if android_api_level >= 31: + config.available_features.add('android-31') # Prepare the device. android_tmpdir = '/data/local/tmp/Output' diff --git a/compiler-rt/test/lsan/lit.common.cfg.py b/compiler-rt/test/lsan/lit.common.cfg.py --- a/compiler-rt/test/lsan/lit.common.cfg.py +++ b/compiler-rt/test/lsan/lit.common.cfg.py @@ -76,6 +76,10 @@ if not (supported_linux or supported_darwin or supported_netbsd): config.unsupported = True +# Only run the tests on Android, if required API level is present. +if config.android and 'android-31' not in config.available_features: + config.unsupported = True + # Don't support Thumb due to broken fast unwinder if re.search('mthumb', config.target_cflags) is not None: config.unsupported = True