[compiler-rt] [sanitizer] Don't TestPTrace() if SPARC; don't give up if internal_fork() fails (PR #152072)

Thurston Dang via llvm-commits llvm-commits at lists.llvm.org
Tue Aug 5 11:00:45 PDT 2025


https://github.com/thurstond updated https://github.com/llvm/llvm-project/pull/152072

>From 890adf486cd16e531eeb6ac18c2522f2969364d7 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Tue, 5 Aug 2025 03:46:30 +0000
Subject: [PATCH 1/4] [sanitizer] Don't TestPTrace() if SPARC

Fixes corner case of https://github.com/llvm/llvm-project/pull/151406

internal_fork() on SPARC actually calls __fork(). We can't safely fork,
because it's possible seccomp has been configured to disallow fork() but
allow clone().

Also adds some comments/TODOs.
---
 .../sanitizer_stoptheworld_linux_libcdep.cpp  | 25 ++++++++++++++++---
 1 file changed, 21 insertions(+), 4 deletions(-)

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
index d5cf0f14dfeb8..00426de50a388 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
@@ -409,6 +409,12 @@ struct ScopedSetTracerPID {
 // process with a shared virtual address space and shared TLS, and therefore
 // cannot use waitpid() due to the shared errno.
 static void TestPTrace() {
+#  if SANITIZER_SPARC
+  // internal_fork() on SPARC actually calls __fork(). We can't safely fork,
+  // because it's possible seccomp has been configured to disallow fork() but
+  // allow clone().
+  Report("WARNING: skipping TestPTrace() because this is SPARC\n");
+#  else
   // Heuristic: only check the first time this is called. This is not always
   // correct (e.g., user manually triggers leak detection, then updates
   // seccomp, then leak detection is triggered again).
@@ -417,26 +423,36 @@ static void TestPTrace() {
     return;
   checked = true;
 
-  // We hope that fork() is not too expensive, because of copy-on-write.
+  // Hopefully internal_fork() is not too expensive, thanks to copy-on-write.
   // Besides, this is only called the first time.
+  // Note that internal_fork() on non-SPARC Linux actually calls
+  // SYSCALL(clone); thus, it is reasonable to use it because if seccomp kills
+  // TestPTrace(), it would have killed StopTheWorld() anyway.
   int pid = internal_fork();
 
   if (pid < 0) {
     int rverrno;
-    if (internal_iserror(pid, &rverrno)) {
+    if (internal_iserror(pid, &rverrno))
       Report("WARNING: TestPTrace() failed to fork (errno %d)\n", rverrno);
-    }
-    internal__exit(-1);
+
+    // We don't abort the sanitizer - it's still worth letting the sanitizer
+    // try.
+    return;
   }
 
   if (pid == 0) {
     // Child subprocess
+
+    // TODO: consider checking return value of internal_ptrace, to handle
+    //       SCMP_ACT_ERRNO. However, be careful not to consume too many
+    //       resources performing a proper ptrace.
     internal_ptrace(PTRACE_ATTACH, 0, nullptr, nullptr);
     internal__exit(0);
   } else {
     int wstatus;
     internal_waitpid(pid, &wstatus, 0);
 
+    // Handle SCMP_ACT_KILL
     if (WIFSIGNALED(wstatus)) {
       VReport(0,
               "Warning: ptrace appears to be blocked (is seccomp enabled?). "
@@ -446,6 +462,7 @@ static void TestPTrace() {
       // try.
     }
   }
+#  endif
 }
 
 void StopTheWorld(StopTheWorldCallback callback, void *argument) {

>From 2ec6558aa73c287fe9c21580ac5896646e2766bb Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Tue, 5 Aug 2025 04:23:18 +0000
Subject: [PATCH 2/4] Fix up "process" -> "thread"

---
 .../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
index 00426de50a388..f38e44cdc5960 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
@@ -405,8 +405,8 @@ struct ScopedSetTracerPID {
 
 // This detects whether ptrace is blocked (e.g., by seccomp), by forking and
 // then attempting ptrace.
-// This separate check is necessary because StopTheWorld() creates a child
-// process with a shared virtual address space and shared TLS, and therefore
+// This separate check is necessary because StopTheWorld() creates a thread
+// with a shared virtual address space and shared TLS, and therefore
 // cannot use waitpid() due to the shared errno.
 static void TestPTrace() {
 #  if SANITIZER_SPARC

>From 5a630c5684a14dd768c0456238086914fe33d458 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Tue, 5 Aug 2025 17:54:52 +0000
Subject: [PATCH 3/4] Elaborate on SPARC warning

---
 .../sanitizer_stoptheworld_linux_libcdep.cpp               | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
index f38e44cdc5960..0d1f21bad0944 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
@@ -413,7 +413,12 @@ static void TestPTrace() {
   // internal_fork() on SPARC actually calls __fork(). We can't safely fork,
   // because it's possible seccomp has been configured to disallow fork() but
   // allow clone().
-  Report("WARNING: skipping TestPTrace() because this is SPARC\n");
+  Report("Warning: skipping TestPTrace() because this is SPARC\n");
+  Report(
+      "If seccomp blocks ptrace, LeakSanitizer may hang without further "
+      "notice\n");
+  Report(
+      "If seccomp does not block ptrace, you can safely ignore this warning\n");
 #  else
   // Heuristic: only check the first time this is called. This is not always
   // correct (e.g., user manually triggers leak detection, then updates

>From 18d07e49aee94888f7578026d1e7993eb9946bf7 Mon Sep 17 00:00:00 2001
From: Thurston Dang <thurston at google.com>
Date: Tue, 5 Aug 2025 18:00:22 +0000
Subject: [PATCH 4/4] CAPITALIZE

---
 .../sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
index 0d1f21bad0944..5fde65ea48c42 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_stoptheworld_linux_libcdep.cpp
@@ -413,7 +413,7 @@ static void TestPTrace() {
   // internal_fork() on SPARC actually calls __fork(). We can't safely fork,
   // because it's possible seccomp has been configured to disallow fork() but
   // allow clone().
-  Report("Warning: skipping TestPTrace() because this is SPARC\n");
+  Report("WARNING: skipping TestPTrace() because this is SPARC\n");
   Report(
       "If seccomp blocks ptrace, LeakSanitizer may hang without further "
       "notice\n");
@@ -460,7 +460,7 @@ static void TestPTrace() {
     // Handle SCMP_ACT_KILL
     if (WIFSIGNALED(wstatus)) {
       VReport(0,
-              "Warning: ptrace appears to be blocked (is seccomp enabled?). "
+              "WARNING: ptrace appears to be blocked (is seccomp enabled?). "
               "LeakSanitizer may hang.\n");
       VReport(0, "Child exited with signal %d.\n", WTERMSIG(wstatus));
       // We don't abort the sanitizer - it's still worth letting the sanitizer



More information about the llvm-commits mailing list