Skip to content

[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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open

[TSan] Add support for Android #147580

wants to merge 1 commit into from

Conversation

airpfei
Copy link

@airpfei airpfei commented Jul 8, 2025

This PR fixes some bugs to enable TSan support on Android.

It will resolve the issue from NDK android/ndk#1041.

Test project: https://github.com/bytedance/android_tsan_sample/

Copy link

github-actions bot commented Jul 8, 2025

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot
Copy link
Member

llvmbot commented Jul 8, 2025

@llvm/pr-subscribers-compiler-rt-sanitizer

Author: Peng Fei (airpfei)

Changes

This PR fixs some bugs to enable TSan support on Android.

It will resolve the issue from NDK android/ndk#1041.


Full diff: https://github.com/llvm/llvm-project/pull/147580.diff

6 Files Affected:

  • (modified) compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc (+8)
  • (modified) compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp (+1-1)
  • (modified) compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp (+2-2)
  • (modified) compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp (+55-31)
  • (modified) compiler-rt/lib/tsan/rtl/tsan_rtl.cpp (+4-1)
  • (modified) compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp (+1-1)
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
index 2d6cf7fc3282f..6ad7c854f8d50 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors.inc
@@ -1287,6 +1287,14 @@ INTERCEPTOR(int, puts, char *s) {
 #if SANITIZER_INTERCEPT_PRCTL
 INTERCEPTOR(int, prctl, int option, unsigned long arg2, unsigned long arg3,
             unsigned long arg4, unsigned long arg5) {
+#  if SANITIZER_ANDROID
+  static const int PR_PAC_RESET_KEYS = 54;
+  // workaround to avoid crash
+  if (option == PR_PAC_RESET_KEYS) {
+    return REAL(prctl)(option, arg2, arg3, arg4, arg5);
+  }
+#  endif
+
   void *ctx;
   COMMON_INTERCEPTOR_ENTER(ctx, prctl, option, arg2, arg3, arg4, arg5);
   static const int PR_SET_NAME = 15;
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp
index 351e00db6fb2d..855c9923292c5 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp
@@ -89,7 +89,7 @@ static inline bool ReportSupportsColors() { return true; }
 bool ColorizeReports() {
   // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color
   // printing on Windows.
-  if (SANITIZER_WINDOWS)
+  if (SANITIZER_WINDOWS || SANITIZER_ANDROID)
     return false;
 
   const char *flag = common_flags()->color;
diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
index 14b25a8995dab..fdbfc0c4e5220 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
@@ -2411,7 +2411,7 @@ TSAN_INTERCEPTOR(int, vfork, int fake) {
 }
 #endif
 
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
 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,
@@ -3120,7 +3120,7 @@ void InitializeInterceptors() {
 
   TSAN_INTERCEPT(fork);
   TSAN_INTERCEPT(vfork);
-#if SANITIZER_LINUX
+#if SANITIZER_LINUX && !SANITIZER_ANDROID
   TSAN_INTERCEPT(clone);
 #endif
 #if !SANITIZER_ANDROID
diff --git a/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp b/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp
index 2c55645a15479..cd48eadfa7af9 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp
@@ -66,15 +66,16 @@ extern "C" void *__libc_stack_end;
 void *__libc_stack_end = 0;
 #endif
 
-#if SANITIZER_LINUX && (defined(__aarch64__) || defined(__loongarch_lp64)) && \
-    !SANITIZER_GO
-# define INIT_LONGJMP_XOR_KEY 1
-#else
-# define INIT_LONGJMP_XOR_KEY 0
-#endif
+#  if SANITIZER_LINUX &&                                                      \
+      (defined(__aarch64__) || defined(__loongarch_lp64)) && !SANITIZER_GO && \
+      !SANITIZER_ANDROID
+#    define INIT_LONGJMP_XOR_KEY 1
+#  else
+#    define INIT_LONGJMP_XOR_KEY 0
+#  endif
 
-#if INIT_LONGJMP_XOR_KEY
-#include "interception/interception.h"
+#  if INIT_LONGJMP_XOR_KEY
+#    include "interception/interception.h"
 // Must be declared outside of other namespaces.
 DECLARE_REAL(int, _setjmp, void *env)
 #endif
@@ -415,7 +416,7 @@ void InitializePlatform() {
   // is not compiled with -pie.
 #if !SANITIZER_GO
   {
-#    if SANITIZER_LINUX && (defined(__aarch64__) || defined(__loongarch_lp64))
+#    if INIT_LONGJMP_XOR_KEY
     // Initialize the xor key used in {sig}{set,long}jump.
     InitializeLongjmpXorKey();
 #    endif
@@ -484,6 +485,7 @@ int ExtractRecvmsgFDs(void *msgp, int *fds, int nfd) {
   return res;
 }
 
+#    if !SANITIZER_ANDROID
 // Reverse operation of libc stack pointer mangling
 static uptr UnmangleLongJmpSp(uptr mangled_sp) {
 #if defined(__x86_64__)
@@ -527,28 +529,29 @@ static uptr UnmangleLongJmpSp(uptr mangled_sp) {
 #      error "Unknown platform"
 #    endif
 }
+#    endif  // !SANITIZER_ANDROID
 
-#if SANITIZER_NETBSD
-# ifdef __x86_64__
-#  define LONG_JMP_SP_ENV_SLOT 6
-# else
-#  error unsupported
-# endif
-#elif defined(__powerpc__)
-# define LONG_JMP_SP_ENV_SLOT 0
-#elif SANITIZER_FREEBSD
-# ifdef __aarch64__
-#  define LONG_JMP_SP_ENV_SLOT 1
-# 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
+#    if SANITIZER_NETBSD
+#      ifdef __x86_64__
+#        define LONG_JMP_SP_ENV_SLOT 6
+#      else
+#        error unsupported
+#      endif
+#    elif defined(__powerpc__)
+#      define LONG_JMP_SP_ENV_SLOT 0
+#    elif SANITIZER_FREEBSD
+#      ifdef __aarch64__
+#        define LONG_JMP_SP_ENV_SLOT 1
+#      else
+#        define LONG_JMP_SP_ENV_SLOT 2
+#      endif
+#    elif SANITIZER_LINUX && !SANITIZER_ANDROID
+#      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__)
@@ -556,11 +559,24 @@ static uptr UnmangleLongJmpSp(uptr mangled_sp) {
 #      else
 #        define LONG_JMP_SP_ENV_SLOT 6
 #      endif
-#endif
+#    elif SANITIZER_ANDROID
+#      ifdef __aarch64__
+#        define LONG_JMP_SP_ENV_SLOT 3
+#        define LONG_JMP_COOKIE_ENV_SLOT 0
+#      else
+#        error unsupported
+#      endif
+#    endif
 
 uptr ExtractLongJmpSp(uptr *env) {
   uptr mangled_sp = env[LONG_JMP_SP_ENV_SLOT];
+#    if SANITIZER_ANDROID
+  // This only works for Android arm64
+  // https://android.googlesource.com/platform/bionic/+/refs/heads/android16-release/libc/arch-arm64/bionic/setjmp.S#46
+  return mangled_sp ^ (env[LONG_JMP_COOKIE_ENV_SLOT] & ~1ULL);
+#    else
   return UnmangleLongJmpSp(mangled_sp);
+#    endif
 }
 
 #if INIT_LONGJMP_XOR_KEY
@@ -653,6 +669,14 @@ ThreadState *cur_thread() {
     }
     CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &oldset, nullptr));
   }
+
+  // This is a temporary workaround.
+  // Somewhere wrote get_android_tls_ptr unexpected.
+  uptr addr = reinterpret_cast<uptr>(thr);
+  if (addr % 2 != 0) {
+    return reinterpret_cast<ThreadState *>(addr & ~1ULL);
+  }
+
   return thr;
 }
 
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
index 0d7247a56a4c2..dec85d71d9ba3 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
@@ -662,7 +662,7 @@ void MapShadow(uptr addr, uptr size) {
           addr + size, meta_begin, meta_end);
 }
 
-#if !SANITIZER_GO
+#if !SANITIZER_GO && !SANITIZER_ANDROID
 static void OnStackUnwind(const SignalContext &sig, const void *,
                           BufferedStackTrace *stack) {
   stack->Unwind(StackTrace::GetNextInstructionPc(sig.pc), sig.bp, sig.context,
@@ -733,6 +733,9 @@ void Initialize(ThreadState *thr) {
 #if !SANITIZER_GO
   InitializeShadowMemory();
   InitializeAllocatorLate();
+#endif
+
+#if !SANITIZER_GO && !SANITIZER_ANDROID
   InstallDeadlySignalHandlers(TsanOnDeadlySignal);
 #endif
   // Setup correct file descriptor for error reports.
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp
index 8d29e25a6dd20..5283cc595569b 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_thread.cpp
@@ -188,7 +188,7 @@ void ThreadStart(ThreadState *thr, Tid tid, tid_t os_id,
   }
 #endif
 
-#if !SANITIZER_GO
+#if !SANITIZER_GO && !SANITIZER_ANDROID
   // Don't imitate stack/TLS writes for the main thread,
   // because its initialization is synchronized with all
   // subsequent threads anyway.

@fmayer fmayer requested a review from enh-google July 15, 2025 23:52
@@ -1287,6 +1287,14 @@ INTERCEPTOR(int, puts, char *s) {
#if SANITIZER_INTERCEPT_PRCTL
INTERCEPTOR(int, prctl, int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5) {
# if SANITIZER_ANDROID
static const int PR_PAC_RESET_KEYS = 54;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this shouldn't be needed because it's defined in the ndk?

@@ -1287,6 +1287,14 @@ INTERCEPTOR(int, puts, char *s) {
#if SANITIZER_INTERCEPT_PRCTL
INTERCEPTOR(int, prctl, int option, unsigned long arg2, unsigned long arg3,
unsigned long arg4, unsigned long arg5) {
# if SANITIZER_ANDROID
static const int PR_PAC_RESET_KEYS = 54;
// workaround to avoid crash
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the crash? doesn't the COMMON_INTERCEPTOR_ENTER() line just call the real one with all the arguments anyway?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

COMMON_INTERCEPTOR_ENTER will expand like this, I think the root cause is after executing prctl(PR_PAC_RESET_KEYS, ...) it will continue execute ScopedInterceptor destructor which triggers a pointer authentication failure. Finally I got an Illegal instruction error.

ThreadState *thr = cur_thread_init();
ScopedInterceptor si(thr, #func, GET_CALLER_PC(), option);
UNUSED const uptr pc = GET_CURRENT_PC();

return REAL(prctl)(PR_PAC_RESET_KEYS, arg2, arg3, arg4, arg5);

Copy link
Author

@airpfei airpfei Jul 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think I found the root cause: the Pointer Authentication key changes during the function, but the return address is still verified using the old key. The compiler optimizes the current PR’s code as a tail call, so no PAC instructions are emitted, and the crash no longer occurs. However, I believe it will still crash with debug flags. This function might need to be implemented in assembly.

That’s where this function is called. https://android.googlesource.com/platform/bionic/+/refs/heads/android16-release/libc/bionic/pthread_create.cpp#386

Assembly of the origin code

0000000000093fb4 <__interceptor_prctl>:
   93fb4: d503233f     	paciasp  // sign LR
   ...
   // call real prctl with PR_PAC_RESET_KEYS, so the pac key changed
   94034: 54000501     	b.ne	0x940d4 <__interceptor_prctl+0x120>
   ...
   autiasp // verify LR, oops. Because pac is reset

Assembly of this PR's code

0000000000093e68 <__interceptor_prctl>:
   93e68: d503245f     	bti	c
   93e6c: 7100d81f     	cmp	w0, #0x36 // PR_PAC_RESET_KEYS
   93e70: 54000081     	b.ne	0x93e80 <__interceptor_prctl+0x18>
   93e74: 90001148     	adrp	x8, 0x2bb000 <_ZN14__interception22real_pthread_spin_initE>
   93e78: f9418510     	ldr	x16, [x8, #0x308]
   93e7c: d61f0200     	br	x16

   93e80: d503233f     	paciasp
   93e84: d101c3ff     	sub	sp, sp, #0x70
   93e88: f90013fe     	str	x30, [sp, #0x20]

Copy link
Author

@airpfei airpfei Aug 4, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

This crash also happens in ASan of NDK 28. I am going to fix it by the following method. __interceptor_prctl will call real_prctl when the option is PR_PAC_RESET_KEYS. @enh-google do you have any comments on this?

[wrapper "prctl": weak] ---> [TRAMPOLINE(prctl)] --> [__interceptor_prctl] ---> [WRAP(prctl)]

.comm _ZN14__interception10real_prctlE,8,8
.global __interceptor_prctl
ASM_TYPE_FUNCTION(__interceptor_prctl)
__interceptor_prctl:
  CFI_STARTPROC
  BTI_C

  cmp      w0, #54
  bne      .L_wrap_prctl
  adrp     x6, :got:_ZN14__interception10real_prctlE
  ldr      x6, [x6, #:got_lo12:_ZN14__interception10real_prctlE]
  ldr      x6, [x6]
  br       x6

.L_wrap_prctl:
  b        ASM_WRAPPER_NAME(prctl)
  CFI_ENDPROC
ASM_SIZE(__interceptor_prctl)

@@ -89,7 +89,7 @@ static inline bool ReportSupportsColors() { return true; }
bool ColorizeReports() {
// FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color
// printing on Windows.
if (SANITIZER_WINDOWS)
if (SANITIZER_WINDOWS || SANITIZER_ANDROID)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

color printing should work fine on Android. we haven't had any complaints with any of the other sanitizers (and this is shared code).

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, you are right

@@ -2411,7 +2411,7 @@ TSAN_INTERCEPTOR(int, vfork, int fake) {
}
#endif

#if SANITIZER_LINUX
#if SANITIZER_LINUX && !SANITIZER_ANDROID
Copy link
Contributor

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?

Copy link
Author

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's pthread_create calls clone. 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#L1062

I'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

@@ -484,6 +485,7 @@ int ExtractRecvmsgFDs(void *msgp, int *fds, int nfd) {
return res;
}

# if !SANITIZER_ANDROID
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it seems like you should probably add the android case inside this function, rather than adding a special case just for Android on line 573?

# 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
# elif SANITIZER_ANDROID
# ifdef __aarch64__
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we should add x86-64 and riscv64 at the same time. (the former so we can test this in CI, the latter just so we don't forget.)


uptr ExtractLongJmpSp(uptr *env) {
uptr mangled_sp = env[LONG_JMP_SP_ENV_SLOT];
# if SANITIZER_ANDROID
// This only works for Android arm64
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we use the same trick for x86-64 and riscv64 too, no?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but currently I don't have this kind of device, so maybe I can't test if it works on these devices

@@ -653,6 +669,14 @@ ThreadState *cur_thread() {
}
CHECK_EQ(0, internal_sigprocmask(SIG_SETMASK, &oldset, nullptr));
}

// This is a temporary workaround.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this should probably abort if it gets a bad thread pointer, so we can track down what the actual problem is?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think calling abort is a good way to track down the actual problem, because by the time it happens, something has already gone wrong elsewhere. Now I am sure the problem is cause by android framework, that means if calling abort here, TSan can't work for all currently released Android.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can't reproduce this bug, so revert this change

@@ -662,7 +662,7 @@ void MapShadow(uptr addr, uptr size) {
addr + size, meta_begin, meta_end);
}

#if !SANITIZER_GO
#if !SANITIZER_GO && !SANITIZER_ANDROID
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the changes in this file make sense to me, but you should probably add a comment saying something like "Android has its own crash reporting unwinder"?

that said ... we don't have the equivalent changes in the other sanitizers, do we? all the sanitizers should probably behave the same?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

InstallDeadlySignalHandlers(TsanOnDeadlySignal) will cause the following crash, I have no idea about it now.

--------- beginning of crash
07-16 17:21:01.956 17619 17619 F libc    : Fatal signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0 in tid 17619 (app_process64), pid 17619 (app_process64)
07-16 17:21:01.971 17622 17622 E crash_dump64: failed to get the guest state header for thread 17619: Bad address
07-16 17:21:01.975 17622 17622 I crash_dump64: obtaining output fd from tombstoned, type: kDebuggerdTombstoneProto
07-16 17:21:01.977   986   986 I tombstoned: received crash request for pid 17619
07-16 17:21:01.978 17622 17622 I crash_dump64: performing dump of process 17619 (target tid = 17619)
07-16 17:21:01.984 17622 17622 W libc    : Access denied finding property "ro.lineage.version"
07-16 17:21:01.994   658   658 I logd    : logdr: UID=10287 GID=10287 PID=17622 n tail=500 logMask=8 pid=17619 start=0ns deadline=0ns
07-16 17:21:01.995   658   658 I logd    : logdr: UID=10287 GID=10287 PID=17622 n tail=500 logMask=1 pid=17619 start=0ns deadline=0ns
07-16 17:21:02.021 17622 17622 F DEBUG   : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***
07-16 17:21:02.021 17622 17622 F DEBUG   : LineageOS Version: 'unknown'
07-16 17:21:02.021 17622 17622 F DEBUG   : Build fingerprint: 'OnePlus/CPH2449EEA/OP594DL1:15/TP1A.220905.001/T.R4T3.1c97c78-1_1:user/release-keys'
07-16 17:21:02.021 17622 17622 F DEBUG   : Revision: '0'
07-16 17:21:02.021 17622 17622 F DEBUG   : ABI: 'arm64'
07-16 17:21:02.021 17622 17622 F DEBUG   : Timestamp: 2025-07-16 17:21:01.984140766-0700
07-16 17:21:02.021 17622 17622 F DEBUG   : Process uptime: 1s
07-16 17:21:02.021 17622 17622 F DEBUG   : Cmdline: /system/bin/app_process64 -Xcompiler-option --generate-mini-debug-info /system/bin --application --nice-name=com.example.tsan com.android.internal.os.WrapperInit 82 34 android.app.ActivityThread seq=490
07-16 17:21:02.021 17622 17622 F DEBUG   : pid: 17619, tid: 17619, name: app_process64  >>> /system/bin/app_process64 <<<
07-16 17:21:02.021 17622 17622 F DEBUG   : uid: 10287
07-16 17:21:02.021 17622 17622 F DEBUG   : tagged_addr_ctrl: 0000000000000001 (PR_TAGGED_ADDR_ENABLE)
07-16 17:21:02.021 17622 17622 F DEBUG   : pac_enabled_keys: 000000000000000f (PR_PAC_APIAKEY, PR_PAC_APIBKEY, PR_PAC_APDAKEY, PR_PAC_APDBKEY)
07-16 17:21:02.021 17622 17622 F DEBUG   : signal 11 (SIGSEGV), code 1 (SEGV_MAPERR), fault addr 0x0000000000000000
07-16 17:21:02.021 17622 17622 F DEBUG   : Cause: null pointer dereference
07-16 17:21:02.021 17622 17622 F DEBUG   :     x0  0000007ff7e7e000  x1  0000007fe6cc5ff0  x2  0000007ff271d698  x3  0000007ff271a790
07-16 17:21:02.021 17622 17622 F DEBUG   :     x4  0000007ff6e70230  x5  0000000001414d4c  x6  0000000001414d4c  x7  0000007ff6e70004
07-16 17:21:02.021 17622 17622 F DEBUG   :     x8  0000000000000000  x9  0000000000000000  x10 00000000000044d3  x11 00000000000044d3
07-16 17:21:02.021 17622 17622 F DEBUG   :     x12 0000007fc914e2a8  x13 0000007ff2715998  x14 0000007ff27152c0  x15 0000000000000000
07-16 17:21:02.021 17622 17622 F DEBUG   :     x16 0000007ff271b320  x17 0000007fe6cc5fa4  x18 0000007ff7e48000  x19 0000007ff7e7e000
07-16 17:21:02.021 17622 17622 F DEBUG   :     x20 0000000000000000  x21 0000007fe6cc5ff0  x22 0000000000000000  x23 10000000000fffff
07-16 17:21:02.021 17622 17622 F DEBUG   :     x24 0000000000000005  x25 ffffffffffffffff  x26 0000000000000005  x27 0000007ff7ff6000
07-16 17:21:02.021 17622 17622 F DEBUG   :     x28 0000007ff7ff6000  x29 0000007fffffce40
07-16 17:21:02.021 17622 17622 F DEBUG   :     lr  000c147fe6d28c14  sp  0000007fffffcd90  pc  0000007fe6d1593c  pst 0000000080001000
07-16 17:21:02.021 17622 17622 F DEBUG   : 21 total frames
07-16 17:21:02.021 17622 17622 F DEBUG   : backtrace:
07-16 17:21:02.021 17622 17622 F DEBUG   :       #00 pc 00000000000d593c  /data/app/~~S8cXpZ-XqfWMriurLevxGw==/com.example.tsan-aEVJ47gb45Zl4snALIsS4Q==/lib/arm64/libclang_rt.tsan-aarch64-android.so (BuildId: 0817fadebda5f37c2f8da3290095fb4ed34e2d00)
07-16 17:21:02.021 17622 17622 F DEBUG   :       #01 pc 00000000000e8c10  /data/app/~~S8cXpZ-XqfWMriurLevxGw==/com.example.tsan-aEVJ47gb45Zl4snALIsS4Q==/lib/arm64/libclang_rt.tsan-aarch64-android.so (BuildId: 0817fadebda5f37c2f8da3290095fb4ed34e2d00)
07-16 17:21:02.021 17622 17622 F DEBUG   :       #02 pc 0000000000086038  /data/app/~~S8cXpZ-XqfWMriurLevxGw==/com.example.tsan-aEVJ47gb45Zl4snALIsS4Q==/lib/arm64/libclang_rt.tsan-aarch64-android.so (__cxa_guard_release+148) (BuildId: 0817fadebda5f37c2f8da3290095fb4ed34e2d00)
07-16 17:21:02.021 17622 17622 F DEBUG   :       #03 pc 000000000000578c  /apex/com.android.art/lib64/libsigchain.so (void std::__1::__call_once_proxy[abi:nn190000]<std::__1::tuple<art::InitializeSignalChain()::$_0&&>>(void*)+292) (BuildId: bb55558278aefa712a5246c50cad59b0)
07-16 17:21:02.021 17622 17622 F DEBUG   :       #04 pc 000000000008dc70  /apex/com.android.art/lib64/libc++.so (std::__1::__call_once(unsigned long volatile&, void*, void (*)(void*))+180) (BuildId: 94744eed32fba2eb636a9d2e5365a00614c1b4ae)
07-16 17:21:02.021 17622 17622 F DEBUG   :       #05 pc 0000000000004cb8  /apex/com.android.art/lib64/libsigchain.so (sigaction+100) (BuildId: bb55558278aefa712a5246c50cad59b0)
07-16 17:21:02.021 17622 17622 F DEBUG   :       #06 pc 000000000006da78  /data/app/~~S8cXpZ-XqfWMriurLevxGw==/com.example.tsan-aEVJ47gb45Zl4snALIsS4Q==/lib/arm64/libclang_rt.tsan-aarch64-android.so (BuildId: 0817fadebda5f37c2f8da3290095fb4ed34e2d00)
07-16 17:21:02.021 17622 17622 F DEBUG   :       #07 pc 000000000006ec2c  /data/app/~~S8cXpZ-XqfWMriurLevxGw==/com.example.tsan-aEVJ47gb45Zl4snALIsS4Q==/lib/arm64/libclang_rt.tsan-aarch64-android.so (BuildId: 0817fadebda5f37c2f8da3290095fb4ed34e2d00)
07-16 17:21:02.021 17622 17622 F DEBUG   :       #08 pc 000000000006eb60  /data/app/~~S8cXpZ-XqfWMriurLevxGw==/com.example.tsan-aEVJ47gb45Zl4snALIsS4Q==/lib/arm64/libclang_rt.tsan-aarch64-android.so (BuildId: 0817fadebda5f37c2f8da3290095fb4ed34e2d00)
07-16 17:21:02.021 17622 17622 F DEBUG   :       #09 pc 00000000000d6454  /data/app/~~S8cXpZ-XqfWMriurLevxGw==/com.example.tsan-aEVJ47gb45Zl4snALIsS4Q==/lib/arm64/libclang_rt.tsan-aarch64-android.so (BuildId: 0817fadebda5f37c2f8da3290095fb4ed34e2d00)
07-16 17:21:02.021 17622 17622 F DEBUG   :       #10 pc 00000000000827cc  /data/app/~~S8cXpZ-XqfWMriurLevxGw==/com.example.tsan-aEVJ47gb45Zl4snALIsS4Q==/lib/arm64/libclang_rt.tsan-aarch64-android.so (BuildId: 0817fadebda5f37c2f8da3290095fb4ed34e2d00)
07-16 17:21:02.021 17622 17622 F DEBUG   :       #11 pc 00000000000910c4  /data/app/~~S8cXpZ-XqfWMriurLevxGw==/com.example.tsan-aEVJ47gb45Zl4snALIsS4Q==/lib/arm64/libclang_rt.tsan-aarch64-android.so (__interceptor_strcmp+88) (BuildId: 0817fadebda5f37c2f8da3290095fb4ed34e2d00)
07-16 17:21:02.021 17622 17622 F DEBUG   :       #12 pc 00000000000762e0  /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init_vdso(libc_globals*)+388) (BuildId: feb3b73f26ea498949b9d90af6a0dc93)
07-16 17:21:02.021 17622 17622 F DEBUG   :       #13 pc 0000000000066724  /apex/com.android.runtime/lib64/bionic/libc.so (__libc_init_globals()+64) (BuildId: feb3b73f26ea498949b9d90af6a0dc93)
07-16 17:21:02.021 17622 17622 F DEBUG   :       #14 pc 000000000005516c  /apex/com.android.runtime/lib64/bionic/libc.so (__libc_preinit_impl()+44) (BuildId: feb3b73f26ea498949b9d90af6a0dc93)
07-16 17:21:02.021 17622 17622 F DEBUG   :       #15 pc 0000000000064344  /apex/com.android.runtime/bin/linker64 (__dl__ZN6soinfo17call_constructorsEv+596) (BuildId: cb3d74aac29310f620300f43e44eaa07)
07-16 17:21:02.021 17622 17622 F DEBUG   :       #16 pc 0000000000064170  /apex/com.android.runtime/bin/linker64 (__dl__ZN6soinfo17call_constructorsEv+128) (BuildId: cb3d74aac29310f620300f43e44eaa07)
07-16 17:21:02.022 17622 17622 F DEBUG   :       #17 pc 0000000000064170  /apex/com.android.runtime/bin/linker64 (__dl__ZN6soinfo17call_constructorsEv+128) (BuildId: cb3d74aac29310f620300f43e44eaa07)
07-16 17:21:02.022 17622 17622 F DEBUG   :       #18 pc 0000000000158fcc  /apex/com.android.runtime/bin/linker64 (__dl__ZL29__linker_init_post_relocationR19KernelArgumentBlockR6soinfo+4504) (BuildId: cb3d74aac29310f620300f43e44eaa07)
07-16 17:21:02.022 17622 17622 F DEBUG   :       #19 pc 0000000000157da4  /apex/com.android.runtime/bin/linker64 (__dl___linker_init+948) (BuildId: cb3d74aac29310f620300f43e44eaa07)
07-16 17:21:02.022 17622 17622 F DEBUG   :       #20 pc 0000000000078498  /apex/com.android.runtime/bin/linker64 (__dl__start+8) (BuildId: cb3d74aac29310f620300f43e44eaa07)
07-16 17:21:02.019  1307  1307 W LightningLaunc: type=1400 audit(0.0:10154): avc:  denied  { search } for  name="17622" dev="proc" ino=421914 scontext=u:r:vendor_hal_perf_default:s0 tcontext=u:r:crash_dump:s0:c31,c257,c512,c768 tclass=dir permissive=0

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here is a workaround to avoid crashes, by adding the following flags: handle_segv=0,handle_sigbus=0,handle_sigfpe=0. So I will reset this change.

@@ -188,7 +188,7 @@ void ThreadStart(ThreadState *thr, Tid tid, tid_t os_id,
}
#endif

#if !SANITIZER_GO
#if !SANITIZER_GO && !SANITIZER_ANDROID
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why don't we need this for android?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because ThreadState is created by MmapOrDie, so the thr object is not in tls, the pointer of thr object is in TLS_SLOT_SANITIZER slot. The check in ImitateTlsWrite will fail.

https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp#L640

      thr = reinterpret_cast<ThreadState*>(MmapOrDie(sizeof(ThreadState),
                                                     "ThreadState"));
      *get_android_tls_ptr() = reinterpret_cast<uptr>(thr);

https://github.com/llvm/llvm-project/blob/main/compiler-rt/lib/tsan/rtl/tsan_platform_linux.cpp#L592

void ImitateTlsWrite(ThreadState *thr, uptr tls_addr, uptr tls_size) {
  // Check that the thr object is in tls;
  const uptr thr_beg = (uptr)thr;
  const uptr thr_end = (uptr)thr + sizeof(*thr);
  CHECK_GE(thr_beg, tls_addr);
  CHECK_LE(thr_beg, tls_addr + tls_size);
  CHECK_GE(thr_end, tls_addr);
  CHECK_LE(thr_end, tls_addr + tls_size);
  // Since the thr object is huge, skip it.
  const uptr pc = StackTrace::GetNextInstructionPc(
      reinterpret_cast<uptr>(__tsan_tls_initialization));
  MemoryRangeImitateWrite(thr, pc, tls_addr, thr_beg - tls_addr);
  MemoryRangeImitateWrite(thr, pc, thr_end, tls_addr + tls_size - thr_end);
}
// The Android Bionic team has allocated a TLS slot for sanitizers starting
// with Q, given that Android currently doesn't support ELF TLS. It is used to
// store sanitizer thread specific data.
static const int TLS_SLOT_SANITIZER = 6;

ALWAYS_INLINE uptr *get_android_tls_ptr() {
  return reinterpret_cast<uptr *>(&__get_tls()[TLS_SLOT_SANITIZER]);
}

Copy link
Contributor

@enh-google enh-google left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for looking at this!

@airpfei
Copy link
Author

airpfei commented Jul 29, 2025

Hi @enh-google,
I've updated the code and added explanations for the changes. Please take a look when you have time. Thanks!

@airpfei airpfei force-pushed the main branch 3 times, most recently from 22a8e79 to 8b4d79e Compare August 5, 2025 02:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants