[compiler-rt] [tsan] Don't symbolize stack traces if dl_iterate_phdr is not ready (PR #143199)

Thurston Dang via llvm-commits llvm-commits at lists.llvm.org
Fri Jun 6 13:22:40 PDT 2025


https://github.com/thurstond created https://github.com/llvm/llvm-project/pull/143199

When a CHECK() fails during TSan initialization, it may segfault (e.g., https://github.com/google/sanitizers/issues/837#issuecomment-2939267531). This is because a failed CHECK() will attempt to print a symbolized stack trace, which requires dl_iterate_phdr, for which the interceptor may not yet be set up.

This patch fixes the issue by not symbolizing the stack trace if the dl_iterate_phdr interceptor is not ready.

>From 6eaf4632a21aa8ad8ba526b3810a360f0811bcba Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Fri, 6 Jun 2025 20:06:29 +0000
Subject: [PATCH 1/2] [NFCI][tsan] Don't symbolize stack traces if
 dl_iterate_phdr is not ready

When a CHECK() fails before TSan is fully initialized, it may segfault
(e.g., https://github.com/google/sanitizers/issues/837#issuecomment-2939267531). This is because a failed CHECK() will attempt to print a symbolized stack trace, which requires dl_iterate_phdr, for which the interceptor is not yet set up.

This patch fixes the issue by not symbolizing the stack trace if
the dl_iterate_phdr interceptor is not ready.
---
 compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp |  5 +++++
 compiler-rt/lib/tsan/rtl/tsan_rtl.cpp                |  7 +++++++
 compiler-rt/lib/tsan/rtl/tsan_rtl.h                  |  2 ++
 compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp         | 11 ++++++++++-
 4 files changed, 24 insertions(+), 1 deletion(-)

diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
index 7c4d23a6a0d74..3565e50892ecf 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
@@ -3082,9 +3082,14 @@ void InitializeInterceptors() {
 #if SANITIZER_LINUX
   TSAN_INTERCEPT(clone);
 #endif
+
 #if !SANITIZER_ANDROID
   TSAN_INTERCEPT(dl_iterate_phdr);
 #endif
+
+  // Symbolization indirectly calls dl_iterate_phdr
+  ready_to_symbolize = true;
+
   TSAN_MAYBE_INTERCEPT_ON_EXIT;
   TSAN_INTERCEPT(__cxa_atexit);
   TSAN_INTERCEPT(_exit);
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
index c83efec8eaca2..00f113834b4af 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
@@ -673,12 +673,19 @@ void CheckUnwind() {
   thr->ignore_reads_and_writes++;
   atomic_store_relaxed(&thr->in_signal_handler, 0);
 #endif
+
   PrintCurrentStack(StackTrace::GetCurrentPc(),
                     common_flags()->fast_unwind_on_fatal);
 }
 
 bool is_initialized;
 
+// Symbolization indirectly calls dl_iterate_phdr. If a CHECK() fails early on
+// (prior to the dl_iterate_phdr interceptor setup), resulting in an attempted
+// symbolization, it will segfault.
+// dl_iterate_phdr is not intercepted for Android.
+bool ready_to_symbolize = SANITIZER_ANDROID;
+
 void Initialize(ThreadState *thr) {
   // Thread safe because done before all threads exist.
   if (is_initialized)
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.h b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
index 4dc5e630c5249..0be53599b6a49 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.h
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.h
@@ -54,6 +54,8 @@
 
 namespace __tsan {
 
+extern bool ready_to_symbolize;
+
 #if !SANITIZER_GO
 struct MapUnmapCallback;
 #  if defined(__mips64) || defined(__aarch64__) || defined(__loongarch__) || \
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp
index 51a98e2f2d5e7..0820bf1adee43 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp
@@ -846,7 +846,16 @@ ALWAYS_INLINE USED void PrintCurrentStack(uptr pc, bool fast) {
     ptrace->trace_buffer[i] = ptrace->trace_buffer[ptrace->size - i - 1];
     ptrace->trace_buffer[ptrace->size - i - 1] = tmp;
   }
-  PrintStack(SymbolizeStack(*ptrace));
+
+  if (ready_to_symbolize) {
+    PrintStack(SymbolizeStack(*ptrace));
+  } else {
+    Printf(
+        "WARNING: PrintCurrentStack() has been called too early, before "
+        "symbolization is possible. Printing unsymbolized stack trace:\n");
+    for (unsigned int i = 0; i < ptrace->size; i++)
+      Printf("    #%u: 0x%zx\n", i, ptrace->trace[i]);
+  }
 #endif
 }
 

>From 8c705231b843274dd99e7f14255fac9c4dff46a6 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Fri, 6 Jun 2025 20:21:15 +0000
Subject: [PATCH 2/2] Revert newlines

---
 compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp | 1 -
 compiler-rt/lib/tsan/rtl/tsan_rtl.cpp                | 1 -
 2 files changed, 2 deletions(-)

diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
index 3565e50892ecf..a4bc3d6cff91a 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
@@ -3082,7 +3082,6 @@ void InitializeInterceptors() {
 #if SANITIZER_LINUX
   TSAN_INTERCEPT(clone);
 #endif
-
 #if !SANITIZER_ANDROID
   TSAN_INTERCEPT(dl_iterate_phdr);
 #endif
diff --git a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
index 00f113834b4af..d8be21284b934 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
@@ -673,7 +673,6 @@ void CheckUnwind() {
   thr->ignore_reads_and_writes++;
   atomic_store_relaxed(&thr->in_signal_handler, 0);
 #endif
-
   PrintCurrentStack(StackTrace::GetCurrentPc(),
                     common_flags()->fast_unwind_on_fatal);
 }



More information about the llvm-commits mailing list