-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[compiler-rt][TSan] Add support for Android #147580
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 2 commits
98b8be2
e0e8666
e316d29
b35d234
98929e0
eceee1f
0abdf7d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2412,7 +2412,11 @@ TSAN_INTERCEPTOR(int, vfork, int fake) { | |
} | ||
#endif | ||
|
||
#if SANITIZER_LINUX | ||
#if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
// Bionic's pthread_create internally calls clone. When the CLONE_THREAD flag is | ||
// set, clone does not create a new process but a new thread. This is a | ||
// workaround for Android. Disabling the interception of clone solves the | ||
// problem in most scenarios. | ||
TSAN_INTERCEPTOR(int, clone, int (*fn)(void *), void *stack, int flags, | ||
void *arg, int *parent_tid, void *tls, pid_t *child_tid) { | ||
SCOPED_INTERCEPTOR_RAW(clone, fn, stack, flags, arg, parent_tid, tls, | ||
|
@@ -3135,7 +3139,7 @@ void InitializeInterceptors() { | |
|
||
TSAN_INTERCEPT(fork); | ||
TSAN_INTERCEPT(vfork); | ||
#if SANITIZER_LINUX | ||
#if SANITIZER_LINUX && !SANITIZER_ANDROID | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @fmayer --- what's the compatibility expectation for compiler-rt? i'm wondering whether i should make pthread_create() and fork() call clone() via a hidden alias so they don't get intercepted ... but but then there's nothing to do here other than wait a decade? |
||
TSAN_INTERCEPT(clone); | ||
#endif | ||
#if !SANITIZER_ANDROID | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -486,8 +486,20 @@ int ExtractRecvmsgFDs(void *msgp, int *fds, int nfd) { | |
|
||
// Reverse operation of libc stack pointer mangling | ||
static uptr UnmangleLongJmpSp(uptr mangled_sp) { | ||
#if defined(__x86_64__) | ||
# if SANITIZER_LINUX | ||
# if SANITIZER_ANDROID | ||
if (longjmp_xor_key == 0) { | ||
// bionic libc initialization process: __libc_init_globals -> | ||
// __libc_init_vdso (calls strcmp) -> __libc_init_setjmp_cookie. strcmp is | ||
// intercepted by TSan, so during TSan initialization the setjmp_cookie | ||
// remains uninitialized. On Android, longjmp_xor_key must be set on first | ||
// use. | ||
InitializeLongjmpXorKey(); | ||
CHECK_NE(longjmp_xor_key, 0); | ||
} | ||
# endif | ||
|
||
# if defined(__x86_64__) | ||
# if SANITIZER_LINUX | ||
// Reverse of: | ||
// xor %fs:0x30, %rsi | ||
// rol $0x11, %rsi | ||
|
@@ -542,21 +554,31 @@ static uptr UnmangleLongJmpSp(uptr mangled_sp) { | |
# else | ||
# define LONG_JMP_SP_ENV_SLOT 2 | ||
# endif | ||
#elif SANITIZER_LINUX | ||
# ifdef __aarch64__ | ||
# define LONG_JMP_SP_ENV_SLOT 13 | ||
# elif defined(__loongarch__) | ||
# define LONG_JMP_SP_ENV_SLOT 1 | ||
# elif defined(__mips64) | ||
# define LONG_JMP_SP_ENV_SLOT 1 | ||
# elif SANITIZER_ANDROID | ||
# ifdef __aarch64__ | ||
# define LONG_JMP_SP_ENV_SLOT 3 | ||
# elif SANITIZER_RISCV64 | ||
# define LONG_JMP_SP_ENV_SLOT 3 | ||
# elif defined(__x86_64__) | ||
# define LONG_JMP_SP_ENV_SLOT 6 | ||
# else | ||
# error unsupported | ||
# endif | ||
# elif SANITIZER_LINUX | ||
# ifdef __aarch64__ | ||
# define LONG_JMP_SP_ENV_SLOT 13 | ||
# elif defined(__loongarch__) | ||
# define LONG_JMP_SP_ENV_SLOT 1 | ||
# elif defined(__mips64) | ||
# define LONG_JMP_SP_ENV_SLOT 1 | ||
# elif SANITIZER_RISCV64 | ||
# define LONG_JMP_SP_ENV_SLOT 13 | ||
# elif defined(__s390x__) | ||
# define LONG_JMP_SP_ENV_SLOT 9 | ||
# else | ||
# define LONG_JMP_SP_ENV_SLOT 6 | ||
# endif | ||
#endif | ||
# endif | ||
|
||
uptr ExtractLongJmpSp(uptr *env) { | ||
uptr mangled_sp = env[LONG_JMP_SP_ENV_SLOT]; | ||
|
@@ -653,6 +675,16 @@ ThreadState *cur_thread() { | |
} | ||
CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &oldset, nullptr)); | ||
} | ||
|
||
// https://android.googlesource.com/platform/external/skia/+/refs/tags/android-15.0.0_r36/src/ports/SkMemory_malloc.cpp#105 | ||
|
||
// https://android.googlesource.com/platform/external/scudo/+/refs/tags/android-15.0.0_r36/standalone/tsd_shared.h#198 | ||
|
||
// Workaround to get the correct ThreadState pointer. Scudo allocator uses the | ||
// last bit of TLS_SLOT_SANITIZER as a flag of disable memory initialization. | ||
|
||
// getPlatformAllocatorTlsSlot should not use TLS_SLOT_SANITIZER slot. | ||
|
||
uptr addr = reinterpret_cast<uptr>(thr); | ||
if (addr % 2 != 0) { | ||
|
||
return reinterpret_cast<ThreadState*>(addr & ~1ULL); | ||
} | ||
return thr; | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -206,10 +206,14 @@ void ThreadStart(ThreadState *thr, Tid tid, ThreadID os_id, | |
} | ||
#endif | ||
|
||
#if !SANITIZER_GO | ||
#if !SANITIZER_GO && !SANITIZER_ANDROID | ||
enh-google marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
// Don't imitate stack/TLS writes for the main thread, | ||
// because its initialization is synchronized with all | ||
// subsequent threads anyway. | ||
// Because thr is created by MmapOrDie, the thr object | ||
// is not in tls, the pointer of thr object is in | ||
|
||
// TLS_SLOT_SANITIZER slot. So skip this check on | ||
// Android platform. | ||
if (tid != kMainTid) { | ||
if (stk_addr && stk_size) { | ||
const uptr pc = StackTrace::GetNextInstructionPc( | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
why?
seems like we need to intercept clone() for tsan especially?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
glibc's
pthread_create
calls__clone_internal
, however bionic'spthread_create
callsclone
. When enabling incept clone on Android, this check failed. https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp#L1062I'm not sure if this is the best way
https://codebrowser.dev/glibc/glibc/nptl/pthread_create.c.html#297
https://android.googlesource.com/platform/bionic/+/refs/heads/android16-release/libc/bionic/pthread_create.cpp#466
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
that's an interesting argument for adding an equivalent of glibc's
__clone_internal()
, though we'd have to work with the ndk-translation folks, who deliberately intercept clone().this is probably the "least worst" option until/unless someone comes complaining that they can't use tsan with clone()...