Fix thread ID getter on Android ARM/AArch64

Android's Bionic libc stores the thread ID in TLS slot 1 instead of 0
on 32-bit ARM and AArch64. Slot 0 contains a pointer to the ELF DTV
(Dynamic Thread Vector) instead, which is constant for each loaded DSO.

Because mimalloc uses the thread ID to determine whether operations are
thread-local or cross-thread (atomic), all threads having the same ID
causes internal data structures to get corrupted quickly when multiple
threads are using the allocator:

mimalloc: assertion failed: at "external/mimalloc/src/page.c":563, mi_page_extend_free
  assertion: "page->local_free == NULL"
mimalloc: assertion failed: at "external/mimalloc/src/page.c":74, mi_page_is_valid_init
  assertion: "page->used <= page->capacity"
mimalloc: assertion failed: at "external/mimalloc/src/page.c":100, mi_page_is_valid_init
  assertion: "page->used + free_count == page->capacity"
mimalloc: assertion failed: at "external/mimalloc/src/page.c":74, mi_page_is_valid_init
  assertion: "page->used <= page->capacity"

Add support for Android's alternate TLS layout to fix the crashes in
multi-threaded use cases.

Fixes #376.
This commit is contained in:
Danny Lin 2021-04-07 01:32:19 -07:00
parent 985f313b35
commit ad2fa2bf6f
No known key found for this signature in database
GPG Key ID: 1988FAA1797EE5AC

View File

@ -751,6 +751,9 @@ static inline uintptr_t _mi_thread_id(void) mi_attr_noexcept {
#if defined(__aarch64__) && defined(__APPLE__) // M1
// on macOS on the M1, slot 0 does not seem to work, so we fall back to portable C for now. See issue #354
return (uintptr_t)&_mi_heap_default;
#elif defined(__BIONIC__) && (defined(__arm__) || defined(__aarch64__))
// on Android, slot 1 is the thread ID (pointer to pthread internal struct)
return (uintptr_t)mi_tls_slot(1);
#else
// in all our other targets, slot 0 is the pointer to the thread control block
return (uintptr_t)mi_tls_slot(0);