Skip to content

Conversation

@thurstond
Copy link
Contributor

When a CHECK() fails during TSan initialization, it may segfault (e.g., google/sanitizers#837 (comment)). 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.

thurstond added 2 commits June 6, 2025 20:19
…eady

When a CHECK() fails before TSan is fully initialized, it may segfault
(e.g., google/sanitizers#837 (comment)). 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.
@llvmbot
Copy link
Member

llvmbot commented Jun 6, 2025

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

Author: Thurston Dang (thurstond)

Changes

When a CHECK() fails during TSan initialization, it may segfault (e.g., google/sanitizers#837 (comment)). 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.


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

4 Files Affected:

  • (modified) compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp (+4)
  • (modified) compiler-rt/lib/tsan/rtl/tsan_rtl.cpp (+6)
  • (modified) compiler-rt/lib/tsan/rtl/tsan_rtl.h (+2)
  • (modified) compiler-rt/lib/tsan/rtl/tsan_rtl_report.cpp (+10-1)
diff --git a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
index 7c4d23a6a0d74..a4bc3d6cff91a 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_interceptors_posix.cpp
@@ -3085,6 +3085,10 @@ void InitializeInterceptors() {
 #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..d8be21284b934 100644
--- a/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
+++ b/compiler-rt/lib/tsan/rtl/tsan_rtl.cpp
@@ -679,6 +679,12 @@ void CheckUnwind() {
 
 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
 }
 

@thurstond thurstond merged commit a178c06 into llvm:main Jun 9, 2025
11 checks passed
tomtor pushed a commit to tomtor/llvm-project that referenced this pull request Jun 14, 2025
…lvm#143199)

When a CHECK() fails during TSan initialization, it may segfault (e.g., google/sanitizers#837 (comment)). This is because a failed CHECK() will attempt to print a symbolized stack trace, which requires dl_iterate_phdr, but 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.
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.

4 participants