https://github.com/kenballus updated 
https://github.com/llvm/llvm-project/pull/172086

>From 92afc2af6c11b89425c038a2e722cbd496fb80d6 Mon Sep 17 00:00:00 2001
From: Ben Kallus <[email protected]>
Date: Thu, 11 Dec 2025 23:17:53 -0500
Subject: [PATCH 1/5] Add SigSan

---
 clang/include/clang/Basic/Sanitizers.def   |   2 +
 clang/include/clang/Driver/SanitizerArgs.h |   1 +
 clang/lib/Driver/ToolChains/CommonArgs.cpp |   7 +
 clang/lib/Driver/ToolChains/Linux.cpp      |   1 +
 compiler-rt/lib/CMakeLists.txt             |   1 +
 compiler-rt/lib/sigsan/CMakeLists.txt      |  18 ++
 compiler-rt/lib/sigsan/sigsan.cpp          | 200 +++++++++++++++++++++
 7 files changed, 230 insertions(+)
 create mode 100644 compiler-rt/lib/sigsan/CMakeLists.txt
 create mode 100644 compiler-rt/lib/sigsan/sigsan.cpp

diff --git a/clang/include/clang/Basic/Sanitizers.def 
b/clang/include/clang/Basic/Sanitizers.def
index da85431625026..9594e0166c780 100644
--- a/clang/include/clang/Basic/Sanitizers.def
+++ b/clang/include/clang/Basic/Sanitizers.def
@@ -88,6 +88,8 @@ SANITIZER("realtime", Realtime)
 // LeakSanitizer
 SANITIZER("leak", Leak)
 
+SANITIZER("signal", Signal)
+
 // UndefinedBehaviorSanitizer
 SANITIZER("alignment", Alignment)
 SANITIZER("array-bounds", ArrayBounds)
diff --git a/clang/include/clang/Driver/SanitizerArgs.h 
b/clang/include/clang/Driver/SanitizerArgs.h
index eea7897e96afd..7ae1f202eb41d 100644
--- a/clang/include/clang/Driver/SanitizerArgs.h
+++ b/clang/include/clang/Driver/SanitizerArgs.h
@@ -83,6 +83,7 @@ class SanitizerArgs {
   SanitizerArgs(const ToolChain &TC, const llvm::opt::ArgList &Args,
                 bool DiagnoseErrors = true);
 
+  bool needsSigsanRt() const { return Sanitizers.has(SanitizerKind::Signal); }
   bool needsSharedRt() const { return SharedRuntime; }
   bool needsStableAbi() const { return StableABI; }
 
diff --git a/clang/lib/Driver/ToolChains/CommonArgs.cpp 
b/clang/lib/Driver/ToolChains/CommonArgs.cpp
index ec8dcdc81db56..605a4a32aa276 100644
--- a/clang/lib/Driver/ToolChains/CommonArgs.cpp
+++ b/clang/lib/Driver/ToolChains/CommonArgs.cpp
@@ -1574,6 +1574,9 @@ collectSanitizerRuntimes(const ToolChain &TC, const 
ArgList &Args,
   const SanitizerArgs &SanArgs = TC.getSanitizerArgs(Args);
   // Collect shared runtimes.
   if (SanArgs.needsSharedRt()) {
+    if (SanArgs.needsSigsanRt()) {
+      SharedRuntimes.push_back("sigsan");
+    }
     if (SanArgs.needsAsanRt()) {
       SharedRuntimes.push_back("asan");
       if (!Args.hasArg(options::OPT_shared) && !TC.getTriple().isAndroid())
@@ -1628,6 +1631,10 @@ collectSanitizerRuntimes(const ToolChain &TC, const 
ArgList &Args,
   // Each static runtime that has a DSO counterpart above is excluded below,
   // but runtimes that exist only as static are not affected by needsSharedRt.
 
+  if (!SanArgs.needsSharedRt() && SanArgs.needsSigsanRt()) {
+    StaticRuntimes.push_back("sigsan");
+  }
+
   if (!SanArgs.needsSharedRt() && SanArgs.needsAsanRt()) {
     StaticRuntimes.push_back("asan");
     if (SanArgs.linkCXXRuntimes())
diff --git a/clang/lib/Driver/ToolChains/Linux.cpp 
b/clang/lib/Driver/ToolChains/Linux.cpp
index 94a9fe8b1a63f..745a005aed286 100644
--- a/clang/lib/Driver/ToolChains/Linux.cpp
+++ b/clang/lib/Driver/ToolChains/Linux.cpp
@@ -914,6 +914,7 @@ SanitizerMask Linux::getSupportedSanitizers() const {
   Res |= SanitizerKind::KernelAddress;
   Res |= SanitizerKind::Vptr;
   Res |= SanitizerKind::SafeStack;
+  Res |= SanitizerKind::Signal;
   if (IsX86_64 || IsMIPS64 || IsAArch64 || IsLoongArch64)
     Res |= SanitizerKind::DataFlow;
   if (IsX86_64 || IsMIPS64 || IsAArch64 || IsX86 || IsArmArch || IsPowerPC64 ||
diff --git a/compiler-rt/lib/CMakeLists.txt b/compiler-rt/lib/CMakeLists.txt
index e6158ec408895..e9960bb237fe1 100644
--- a/compiler-rt/lib/CMakeLists.txt
+++ b/compiler-rt/lib/CMakeLists.txt
@@ -42,6 +42,7 @@ if(COMPILER_RT_BUILD_SANITIZERS)
     add_subdirectory(lsan)
     # Contains RTUbsan used even without COMPILER_RT_HAS_UBSAN.
     add_subdirectory(ubsan)
+    add_subdirectory(sigsan)
   endif()
 
   foreach(sanitizer ${COMPILER_RT_SANITIZERS_TO_BUILD})
diff --git a/compiler-rt/lib/sigsan/CMakeLists.txt 
b/compiler-rt/lib/sigsan/CMakeLists.txt
new file mode 100644
index 0000000000000..1168e0fcc9973
--- /dev/null
+++ b/compiler-rt/lib/sigsan/CMakeLists.txt
@@ -0,0 +1,18 @@
+include_directories(..)
+
+# Runtime library sources and build flags.
+set(SIGSAN_SOURCES
+  sigsan.cpp
+)
+
+add_compiler_rt_component(sigsan)
+add_compiler_rt_runtime(clang_rt.sigsan
+    STATIC
+    ARCHS x86_64
+    SOURCES ${SIGSAN_SOURCES}
+    OBJECT_LIBS RTInterception
+                RTSanitizerCommon
+                RTSanitizerCommonLibc
+                RTSanitizerCommonSymbolizer
+    PARENT_TARGET sigsan
+)
diff --git a/compiler-rt/lib/sigsan/sigsan.cpp 
b/compiler-rt/lib/sigsan/sigsan.cpp
new file mode 100644
index 0000000000000..34099dcdbd405
--- /dev/null
+++ b/compiler-rt/lib/sigsan/sigsan.cpp
@@ -0,0 +1,200 @@
+#include "interception/interception.h" // for INTERCEPTOR, INTERCEPT_FUNCTION, 
REAL
+#include "sanitizer_common/sanitizer_stacktrace.h" // for 
GET_CURRENT_PC_BP_SP, BufferedStackTrace
+#include "sanitizer_common/sanitizer_report_decorator.h" // for 
SanitizerCommonDecorator
+#include "sanitizer_common/sanitizer_common.h" // for Printf, Die
+// TODO: figure out the include for Report
+
+#include <signal.h> // for siginfo_t, NSIG, struct sigaction, SIG_IGN, SIG_DFL
+#include <cstdint> // for uintptr_t
+#include <cstdarg> // for va_list, va_start, va_end
+#include <stdio.h> // for FILE
+
+using namespace __sanitizer;
+
+using signal_handler = void (*)(int);
+using extended_signal_handler = void (*)(int, siginfo_t *, void *);
+
+thread_local unsigned int __sigsan_signal_depth = 0;
+
+// TODO: handle sigvec and the other deprecated sighandler installation 
functions
+
+// TODO: Make these atomic so concurrent calls to signal for the same signum 
don't cause problems
+static uintptr_t __sigsan_handlers[NSIG];
+
+void __sigsan_handler(int signum) {
+  __sigsan_signal_depth++;
+  ((signal_handler)(__sigsan_handlers[signum]))(signum);
+  __sigsan_signal_depth--;
+}
+
+void __sigsan_extended_handler(int signum, siginfo_t *si, void *arg) {
+    __sigsan_signal_depth++;
+    ((extended_signal_handler)(__sigsan_handlers[signum]))(signum, si, arg);
+    __sigsan_signal_depth--;
+}
+
+INTERCEPTOR(signal_handler, signal, int signum, signal_handler handler) {
+  // Adapted from llvm-project/libc/src/signal/linux/signal.cpp
+  struct sigaction action, old;
+  action.sa_handler = handler;
+  action.sa_flags = SA_RESTART;
+  return sigaction(signum, &action, &old) < 0 ? SIG_ERR : old.sa_handler;
+}
+
+INTERCEPTOR(int, sigaction, int sig, struct sigaction const *__restrict act, 
struct sigaction *oldact) {
+    auto old_handler = __sigsan_handlers[sig];
+
+    int result;
+    if (!act || act->sa_handler == SIG_IGN || act->sa_handler == SIG_DFL) {
+        result = REAL(sigaction)(sig, act, oldact);
+    } else {
+        // Pass in act, but replace the sa_handler with our middleman
+        struct sigaction act_copy = *act;
+        act_copy.sa_handler = act_copy.sa_flags & SA_SIGINFO ? 
(signal_handler)(uintptr_t)__sigsan_extended_handler : __sigsan_handler;
+        result = REAL(sigaction)(sig, &act_copy, oldact);
+    }
+
+    if (result == 0) {
+        if (act) {
+            // TODO: Fix race condition.
+            // (sig gets delievered right here, causing old sighandler to be 
called)
+            __sigsan_handlers[sig] = (uintptr_t)act->sa_handler;
+        }
+
+        if (oldact) {
+            // TODO: figure out if oldact gets written to even when result != 0
+
+            // Stick in the handler from __sigsan_handlers, so the caller 
isn't aware of our trickery :)
+            oldact->sa_handler = (signal_handler)old_handler;
+        }
+    }
+
+    return result;
+}
+
+void __sanitizer::BufferedStackTrace::UnwindImpl(uptr pc, uptr bp, void 
*context, bool request_fast, u32 max_depth) {
+    uptr top = 0;
+    uptr bottom = 0;
+    GetThreadStackTopAndBottom(false, &top, &bottom);
+    Unwind(max_depth, pc, bp, context, top, bottom, request_fast);
+}
+
+#define SIGSAN_INTERCEPTOR(ret_type, func, args, ...) \
+    INTERCEPTOR(ret_type, func, ##__VA_ARGS__) { \
+        if (__sigsan_signal_depth > 0) { \
+            __sigsan_signal_depth = 0; /* To avoid having to make this 
function async-signal-safe :) */ \
+            SanitizerCommonDecorator d; \
+            Printf("%s", d.Warning()); \
+            Report("ERROR: SignalSanitizer: Async-signal unsafe function " 
#func " called from a signal handler.\n"); \
+            Printf("%s", d.Default()); \
+            BufferedStackTrace stack; \
+            GET_CURRENT_PC_BP_SP; \
+            (void)sp; \
+            stack.Unwind(pc, bp, nullptr, false); \
+            stack.Print(); \
+            Die(); \
+        } \
+        return REAL(func)args; \
+    }
+
+SIGSAN_INTERCEPTOR(void *, malloc, (size), size_t size)
+SIGSAN_INTERCEPTOR(void *, calloc, (n, size), size_t n, size_t size)
+SIGSAN_INTERCEPTOR(void *, realloc, (p, size), void *p, size_t size)
+SIGSAN_INTERCEPTOR(void *, reallocarray, (p, n, size), void *p, size_t n, 
size_t size)
+SIGSAN_INTERCEPTOR(void, free, (p), void *p)
+
+SIGSAN_INTERCEPTOR(int, fputc, (c, stream), int c, FILE *stream)
+SIGSAN_INTERCEPTOR(int, putc, (c, stream), int c, FILE *stream)
+SIGSAN_INTERCEPTOR(int, putchar, (c), int c);
+SIGSAN_INTERCEPTOR(int, fputs, (s, stream), const char *s, FILE *stream)
+SIGSAN_INTERCEPTOR(int, puts, (s), const char *s)
+
+SIGSAN_INTERCEPTOR(int, vprintf, (format, ap), const char *format, va_list ap)
+SIGSAN_INTERCEPTOR(int, vfprintf, (stream, format, ap), FILE *stream, const 
char *format, va_list ap)
+SIGSAN_INTERCEPTOR(int, vdprintf, (fd, format, ap), int fd, const char 
*format, va_list ap)
+SIGSAN_INTERCEPTOR(int, vsprintf, (str, format, ap), char *str, const char 
*format, va_list ap)
+SIGSAN_INTERCEPTOR(int, vsnprintf, (str, size, format, ap), char *str, size_t 
size, const char *format, va_list ap)
+
+INTERCEPTOR(int, printf, const char *format, ...) {
+    va_list ap;
+    va_start(ap, format);
+    auto result = REAL(vprintf)(format, ap);
+    va_end(ap);
+    return result;
+}
+INTERCEPTOR(int, fprintf, FILE *stream, const char *format, ...) {
+    va_list ap;
+    va_start(ap, format);
+    auto result = REAL(vfprintf)(stream, format, ap);
+    va_end(ap);
+    return result;
+}
+INTERCEPTOR(int, dprintf, int fd, const char *format, ...) {
+    va_list ap;
+    va_start(ap, format);
+    auto result = REAL(vdprintf)(fd, format, ap);
+    va_end(ap);
+    return result;
+}
+INTERCEPTOR(int, sprintf, char *str, const char *format, ...) {
+    va_list ap;
+    va_start(ap, format);
+    auto result = REAL(vsprintf)(str, format, ap);
+    va_end(ap);
+    return result;
+}
+INTERCEPTOR(int, snprintf, char *str, size_t size, const char *format, ...) {
+    va_list ap;
+    va_start(ap, format);
+    auto result = REAL(vsnprintf)(str, size, format, ap);
+    va_end(ap);
+    return result;
+}
+
+__attribute__((constructor)) void __sigsan_init() {
+    SetCommonFlagsDefaults();
+    InitializeCommonFlags();
+
+    INTERCEPT_FUNCTION(signal);
+    INTERCEPT_FUNCTION(sigaction);
+
+    INTERCEPT_FUNCTION(malloc);
+    INTERCEPT_FUNCTION(calloc);
+    INTERCEPT_FUNCTION(realloc);
+    INTERCEPT_FUNCTION(reallocarray);
+    INTERCEPT_FUNCTION(free);
+    INTERCEPT_FUNCTION(fputc);
+    INTERCEPT_FUNCTION(putc);
+    INTERCEPT_FUNCTION(putchar);
+    INTERCEPT_FUNCTION(fputs);
+    INTERCEPT_FUNCTION(puts);
+
+    INTERCEPT_FUNCTION(vprintf);
+    INTERCEPT_FUNCTION(vfprintf);
+    INTERCEPT_FUNCTION(vdprintf);
+    INTERCEPT_FUNCTION(vsprintf);
+    INTERCEPT_FUNCTION(vsnprintf);
+
+    INTERCEPT_FUNCTION(printf);
+    INTERCEPT_FUNCTION(fprintf);
+    INTERCEPT_FUNCTION(dprintf);
+    INTERCEPT_FUNCTION(sprintf);
+    INTERCEPT_FUNCTION(snprintf);
+
+    // TODO: Fix race conditions.
+    // (signal/sigaction called while this loop is running)
+    for (int i = 0; i < NSIG; i++) {
+        struct sigaction existing_sa;
+        if (REAL(sigaction)(i, NULL, &existing_sa) == 0) {
+            auto const existing_handler = existing_sa.sa_handler;
+            if (existing_handler != SIG_IGN && existing_handler != SIG_DFL) {
+                __sigsan_handlers[i] = (uintptr_t)existing_handler;
+                if (existing_sa.sa_flags & SA_SIGINFO) {
+                    existing_sa.sa_handler = __sigsan_handler;
+                } else {
+                    existing_sa.sa_handler = 
(signal_handler)(uintptr_t)__sigsan_extended_handler;
+                }
+            }
+        }
+    }
+}

>From 8d4d9f9bd7cebb3e24da28b5aed52a4f8e3bf6c8 Mon Sep 17 00:00:00 2001
From: Ben Kallus <[email protected]>
Date: Fri, 12 Dec 2025 09:25:33 -0500
Subject: [PATCH 2/5] format and add a few more functions

---
 compiler-rt/lib/sigsan/sigsan.cpp | 339 ++++++++++++++++++------------
 1 file changed, 208 insertions(+), 131 deletions(-)

diff --git a/compiler-rt/lib/sigsan/sigsan.cpp 
b/compiler-rt/lib/sigsan/sigsan.cpp
index 34099dcdbd405..b48583740e2b2 100644
--- a/compiler-rt/lib/sigsan/sigsan.cpp
+++ b/compiler-rt/lib/sigsan/sigsan.cpp
@@ -1,13 +1,14 @@
 #include "interception/interception.h" // for INTERCEPTOR, INTERCEPT_FUNCTION, 
REAL
-#include "sanitizer_common/sanitizer_stacktrace.h" // for 
GET_CURRENT_PC_BP_SP, BufferedStackTrace
+#include "sanitizer_common/sanitizer_common.h"           // for Printf, Die
 #include "sanitizer_common/sanitizer_report_decorator.h" // for 
SanitizerCommonDecorator
-#include "sanitizer_common/sanitizer_common.h" // for Printf, Die
+#include "sanitizer_common/sanitizer_stacktrace.h" // for 
GET_CURRENT_PC_BP_SP, BufferedStackTrace
 // TODO: figure out the include for Report
 
+#include <cstdarg>  // for va_list, va_start, va_end
+#include <cstdint>  // for uintptr_t
+#include <errno.h>  // for errno
 #include <signal.h> // for siginfo_t, NSIG, struct sigaction, SIG_IGN, SIG_DFL
-#include <cstdint> // for uintptr_t
-#include <cstdarg> // for va_list, va_start, va_end
-#include <stdio.h> // for FILE
+#include <stdio.h>  // for FILE
 
 using namespace __sanitizer;
 
@@ -16,21 +17,63 @@ using extended_signal_handler = void (*)(int, siginfo_t *, 
void *);
 
 thread_local unsigned int __sigsan_signal_depth = 0;
 
-// TODO: handle sigvec and the other deprecated sighandler installation 
functions
+// TODO: handle sigvec and the other deprecated sighandler installation
+// functions
 
-// TODO: Make these atomic so concurrent calls to signal for the same signum 
don't cause problems
+// TODO: Make these atomic so concurrent calls to signal for the same signum
+// don't cause problems
 static uintptr_t __sigsan_handlers[NSIG];
 
+[[noreturn]] void __sigsan_print_backtrace_and_die() {
+  BufferedStackTrace stack;
+  GET_CURRENT_PC_BP_SP;
+  (void)sp;
+  stack.Unwind(pc, bp, nullptr, false);
+  stack.Print();
+  Die();
+}
+
+[[noreturn]] void
+__sigsan_die_from_unsafe_function_call(char const *func_name) {
+  __sigsan_signal_depth =
+      0; /* To avoid having to make this function async-signal-safe :) */
+  SanitizerCommonDecorator d;
+  Printf("%s", d.Warning());
+  Report("ERROR: SignalSanitizer: async-signal-unsafe function %s called from "
+         "a signal handler.\n",
+         func_name);
+  Printf("%s", d.Default());
+  __sigsan_print_backtrace_and_die();
+}
+
+[[noreturn]] void __sigsan_die_from_modified_errno() {
+  __sigsan_signal_depth =
+      0; /* To avoid having to make this function async-signal-safe :) */
+  SanitizerCommonDecorator d;
+  Printf("%s", d.Warning());
+  Report("ERROR: SignalSanitizer: errno modified from a signal handler.\n");
+  Printf("%s", d.Default());
+  __sigsan_print_backtrace_and_die();
+}
+
 void __sigsan_handler(int signum) {
   __sigsan_signal_depth++;
+  int saved_errno = errno;
   ((signal_handler)(__sigsan_handlers[signum]))(signum);
+  if (errno != saved_errno) {
+    __sigsan_die_from_modified_errno();
+  }
   __sigsan_signal_depth--;
 }
 
 void __sigsan_extended_handler(int signum, siginfo_t *si, void *arg) {
-    __sigsan_signal_depth++;
-    ((extended_signal_handler)(__sigsan_handlers[signum]))(signum, si, arg);
-    __sigsan_signal_depth--;
+  __sigsan_signal_depth++;
+  int saved_errno = errno;
+  ((extended_signal_handler)(__sigsan_handlers[signum]))(signum, si, arg);
+  if (errno != saved_errno) {
+    __sigsan_die_from_modified_errno();
+  }
+  __sigsan_signal_depth--;
 }
 
 INTERCEPTOR(signal_handler, signal, int signum, signal_handler handler) {
@@ -41,160 +84,194 @@ INTERCEPTOR(signal_handler, signal, int signum, 
signal_handler handler) {
   return sigaction(signum, &action, &old) < 0 ? SIG_ERR : old.sa_handler;
 }
 
-INTERCEPTOR(int, sigaction, int sig, struct sigaction const *__restrict act, 
struct sigaction *oldact) {
-    auto old_handler = __sigsan_handlers[sig];
-
-    int result;
-    if (!act || act->sa_handler == SIG_IGN || act->sa_handler == SIG_DFL) {
-        result = REAL(sigaction)(sig, act, oldact);
-    } else {
-        // Pass in act, but replace the sa_handler with our middleman
-        struct sigaction act_copy = *act;
-        act_copy.sa_handler = act_copy.sa_flags & SA_SIGINFO ? 
(signal_handler)(uintptr_t)__sigsan_extended_handler : __sigsan_handler;
-        result = REAL(sigaction)(sig, &act_copy, oldact);
-    }
+INTERCEPTOR(int, sigaction, int sig, struct sigaction const *__restrict act,
+            struct sigaction *oldact) {
+  auto old_handler = __sigsan_handlers[sig];
 
-    if (result == 0) {
-        if (act) {
-            // TODO: Fix race condition.
-            // (sig gets delievered right here, causing old sighandler to be 
called)
-            __sigsan_handlers[sig] = (uintptr_t)act->sa_handler;
-        }
+  int result;
+  if (!act || act->sa_handler == SIG_IGN || act->sa_handler == SIG_DFL) {
+    result = REAL(sigaction)(sig, act, oldact);
+  } else {
+    // Pass in act, but replace the sa_handler with our middleman
+    struct sigaction act_copy = *act;
+    act_copy.sa_handler =
+        act_copy.sa_flags & SA_SIGINFO
+            ? (signal_handler)(uintptr_t)__sigsan_extended_handler
+            : __sigsan_handler;
+    result = REAL(sigaction)(sig, &act_copy, oldact);
+  }
 
-        if (oldact) {
-            // TODO: figure out if oldact gets written to even when result != 0
+  if (result == 0) {
+    if (act) {
+      // TODO: Fix race condition.
+      // (sig gets delievered right here, causing old sighandler to be called)
+      __sigsan_handlers[sig] = (uintptr_t)act->sa_handler;
+    }
 
-            // Stick in the handler from __sigsan_handlers, so the caller 
isn't aware of our trickery :)
-            oldact->sa_handler = (signal_handler)old_handler;
-        }
+    if (oldact) {
+      // TODO: figure out if oldact gets written to even when result != 0
+
+      // Stick in the handler from __sigsan_handlers, so the caller isn't aware
+      // of our trickery :)
+      oldact->sa_handler = (signal_handler)old_handler;
     }
+  }
 
-    return result;
+  return result;
 }
 
-void __sanitizer::BufferedStackTrace::UnwindImpl(uptr pc, uptr bp, void 
*context, bool request_fast, u32 max_depth) {
-    uptr top = 0;
-    uptr bottom = 0;
-    GetThreadStackTopAndBottom(false, &top, &bottom);
-    Unwind(max_depth, pc, bp, context, top, bottom, request_fast);
+void __sanitizer::BufferedStackTrace::UnwindImpl(uptr pc, uptr bp,
+                                                 void *context,
+                                                 bool request_fast,
+                                                 u32 max_depth) {
+  uptr top = 0;
+  uptr bottom = 0;
+  GetThreadStackTopAndBottom(false, &top, &bottom);
+  Unwind(max_depth, pc, bp, context, top, bottom, request_fast);
 }
 
-#define SIGSAN_INTERCEPTOR(ret_type, func, args, ...) \
-    INTERCEPTOR(ret_type, func, ##__VA_ARGS__) { \
-        if (__sigsan_signal_depth > 0) { \
-            __sigsan_signal_depth = 0; /* To avoid having to make this 
function async-signal-safe :) */ \
-            SanitizerCommonDecorator d; \
-            Printf("%s", d.Warning()); \
-            Report("ERROR: SignalSanitizer: Async-signal unsafe function " 
#func " called from a signal handler.\n"); \
-            Printf("%s", d.Default()); \
-            BufferedStackTrace stack; \
-            GET_CURRENT_PC_BP_SP; \
-            (void)sp; \
-            stack.Unwind(pc, bp, nullptr, false); \
-            stack.Print(); \
-            Die(); \
-        } \
-        return REAL(func)args; \
-    }
+#define SIGSAN_INTERCEPTOR(ret_type, func, args, ...)                          
\
+  INTERCEPTOR(ret_type, func, ##__VA_ARGS__) {                                 
\
+    if (__sigsan_signal_depth > 0) {                                           
\
+      __sigsan_die_from_unsafe_function_call(#func);                           
\
+    }                                                                          
\
+    return REAL(func) args;                                                    
\
+  }
 
+// malloc
 SIGSAN_INTERCEPTOR(void *, malloc, (size), size_t size)
 SIGSAN_INTERCEPTOR(void *, calloc, (n, size), size_t n, size_t size)
 SIGSAN_INTERCEPTOR(void *, realloc, (p, size), void *p, size_t size)
-SIGSAN_INTERCEPTOR(void *, reallocarray, (p, n, size), void *p, size_t n, 
size_t size)
+SIGSAN_INTERCEPTOR(void *, reallocarray, (p, n, size), void *p, size_t n,
+                   size_t size)
 SIGSAN_INTERCEPTOR(void, free, (p), void *p)
 
+// stdio
 SIGSAN_INTERCEPTOR(int, fputc, (c, stream), int c, FILE *stream)
 SIGSAN_INTERCEPTOR(int, putc, (c, stream), int c, FILE *stream)
 SIGSAN_INTERCEPTOR(int, putchar, (c), int c);
 SIGSAN_INTERCEPTOR(int, fputs, (s, stream), const char *s, FILE *stream)
 SIGSAN_INTERCEPTOR(int, puts, (s), const char *s)
-
+SIGSAN_INTERCEPTOR(int, fflush, (stream), FILE *stream)
 SIGSAN_INTERCEPTOR(int, vprintf, (format, ap), const char *format, va_list ap)
-SIGSAN_INTERCEPTOR(int, vfprintf, (stream, format, ap), FILE *stream, const 
char *format, va_list ap)
-SIGSAN_INTERCEPTOR(int, vdprintf, (fd, format, ap), int fd, const char 
*format, va_list ap)
-SIGSAN_INTERCEPTOR(int, vsprintf, (str, format, ap), char *str, const char 
*format, va_list ap)
-SIGSAN_INTERCEPTOR(int, vsnprintf, (str, size, format, ap), char *str, size_t 
size, const char *format, va_list ap)
-
+SIGSAN_INTERCEPTOR(int, vfprintf, (stream, format, ap), FILE *stream,
+                   const char *format, va_list ap)
+SIGSAN_INTERCEPTOR(int, vdprintf, (fd, format, ap), int fd, const char *format,
+                   va_list ap)
+SIGSAN_INTERCEPTOR(int, vsprintf, (str, format, ap), char *str,
+                   const char *format, va_list ap)
+SIGSAN_INTERCEPTOR(int, vsnprintf, (str, size, format, ap), char *str,
+                   size_t size, const char *format, va_list ap)
 INTERCEPTOR(int, printf, const char *format, ...) {
-    va_list ap;
-    va_start(ap, format);
-    auto result = REAL(vprintf)(format, ap);
-    va_end(ap);
-    return result;
+  va_list ap;
+  va_start(ap, format);
+  auto const result = REAL(vprintf)(format, ap);
+  va_end(ap);
+  return result;
 }
 INTERCEPTOR(int, fprintf, FILE *stream, const char *format, ...) {
-    va_list ap;
-    va_start(ap, format);
-    auto result = REAL(vfprintf)(stream, format, ap);
-    va_end(ap);
-    return result;
+  va_list ap;
+  va_start(ap, format);
+  auto const result = REAL(vfprintf)(stream, format, ap);
+  va_end(ap);
+  return result;
 }
 INTERCEPTOR(int, dprintf, int fd, const char *format, ...) {
-    va_list ap;
-    va_start(ap, format);
-    auto result = REAL(vdprintf)(fd, format, ap);
-    va_end(ap);
-    return result;
+  va_list ap;
+  va_start(ap, format);
+  auto const result = REAL(vdprintf)(fd, format, ap);
+  va_end(ap);
+  return result;
 }
 INTERCEPTOR(int, sprintf, char *str, const char *format, ...) {
-    va_list ap;
-    va_start(ap, format);
-    auto result = REAL(vsprintf)(str, format, ap);
-    va_end(ap);
-    return result;
+  va_list ap;
+  va_start(ap, format);
+  auto const result = REAL(vsprintf)(str, format, ap);
+  va_end(ap);
+  return result;
 }
 INTERCEPTOR(int, snprintf, char *str, size_t size, const char *format, ...) {
-    va_list ap;
-    va_start(ap, format);
-    auto result = REAL(vsnprintf)(str, size, format, ap);
-    va_end(ap);
-    return result;
+  va_list ap;
+  va_start(ap, format);
+  auto const result = REAL(vsnprintf)(str, size, format, ap);
+  va_end(ap);
+  return result;
+}
+SIGSAN_INTERCEPTOR(FILE *, fopen, (path, mode), const char *path,
+                   const char *mode)
+SIGSAN_INTERCEPTOR(FILE *, fdopen, (fd, mode), int fd, const char *mode)
+SIGSAN_INTERCEPTOR(FILE *, freopen, (path, mode, stream), const char *path,
+                   const char *mode, FILE *stream)
+
+// syslog
+SIGSAN_INTERCEPTOR(void, openlog, (ident, option, facility), const char *ident,
+                   int option, int facility)
+SIGSAN_INTERCEPTOR(void, closelog, ())
+SIGSAN_INTERCEPTOR(void, vsyslog, (priority, format, ap), int priority,
+                   const char *format, va_list ap)
+INTERCEPTOR(void, syslog, int priority, const char *format, ...) {
+  va_list ap;
+  va_start(ap, format);
+  REAL(vsyslog)(priority, format, ap);
+  va_end(ap);
 }
 
 __attribute__((constructor)) void __sigsan_init() {
-    SetCommonFlagsDefaults();
-    InitializeCommonFlags();
-
-    INTERCEPT_FUNCTION(signal);
-    INTERCEPT_FUNCTION(sigaction);
-
-    INTERCEPT_FUNCTION(malloc);
-    INTERCEPT_FUNCTION(calloc);
-    INTERCEPT_FUNCTION(realloc);
-    INTERCEPT_FUNCTION(reallocarray);
-    INTERCEPT_FUNCTION(free);
-    INTERCEPT_FUNCTION(fputc);
-    INTERCEPT_FUNCTION(putc);
-    INTERCEPT_FUNCTION(putchar);
-    INTERCEPT_FUNCTION(fputs);
-    INTERCEPT_FUNCTION(puts);
-
-    INTERCEPT_FUNCTION(vprintf);
-    INTERCEPT_FUNCTION(vfprintf);
-    INTERCEPT_FUNCTION(vdprintf);
-    INTERCEPT_FUNCTION(vsprintf);
-    INTERCEPT_FUNCTION(vsnprintf);
-
-    INTERCEPT_FUNCTION(printf);
-    INTERCEPT_FUNCTION(fprintf);
-    INTERCEPT_FUNCTION(dprintf);
-    INTERCEPT_FUNCTION(sprintf);
-    INTERCEPT_FUNCTION(snprintf);
-
-    // TODO: Fix race conditions.
-    // (signal/sigaction called while this loop is running)
-    for (int i = 0; i < NSIG; i++) {
-        struct sigaction existing_sa;
-        if (REAL(sigaction)(i, NULL, &existing_sa) == 0) {
-            auto const existing_handler = existing_sa.sa_handler;
-            if (existing_handler != SIG_IGN && existing_handler != SIG_DFL) {
-                __sigsan_handlers[i] = (uintptr_t)existing_handler;
-                if (existing_sa.sa_flags & SA_SIGINFO) {
-                    existing_sa.sa_handler = __sigsan_handler;
-                } else {
-                    existing_sa.sa_handler = 
(signal_handler)(uintptr_t)__sigsan_extended_handler;
-                }
-            }
+  SetCommonFlagsDefaults();
+  InitializeCommonFlags();
+
+  INTERCEPT_FUNCTION(signal);
+  INTERCEPT_FUNCTION(sigaction);
+
+  // malloc
+  INTERCEPT_FUNCTION(malloc);
+  INTERCEPT_FUNCTION(calloc);
+  INTERCEPT_FUNCTION(realloc);
+  INTERCEPT_FUNCTION(reallocarray);
+  INTERCEPT_FUNCTION(free);
+
+  // stdio
+  INTERCEPT_FUNCTION(fputc);
+  INTERCEPT_FUNCTION(putc);
+  INTERCEPT_FUNCTION(putchar);
+  INTERCEPT_FUNCTION(fputs);
+  INTERCEPT_FUNCTION(puts);
+  INTERCEPT_FUNCTION(fflush);
+  INTERCEPT_FUNCTION(vprintf);
+  INTERCEPT_FUNCTION(vfprintf);
+  INTERCEPT_FUNCTION(vdprintf);
+  INTERCEPT_FUNCTION(vsprintf);
+  INTERCEPT_FUNCTION(vsnprintf);
+  INTERCEPT_FUNCTION(printf);
+  INTERCEPT_FUNCTION(fprintf);
+  INTERCEPT_FUNCTION(dprintf);
+  INTERCEPT_FUNCTION(sprintf);
+  INTERCEPT_FUNCTION(snprintf);
+  INTERCEPT_FUNCTION(fopen);
+  INTERCEPT_FUNCTION(fdopen);
+  INTERCEPT_FUNCTION(freopen);
+
+  // syslog
+  INTERCEPT_FUNCTION(openlog);
+  INTERCEPT_FUNCTION(closelog);
+  INTERCEPT_FUNCTION(vsyslog);
+  INTERCEPT_FUNCTION(syslog);
+
+  // TODO: Fix race conditions.
+  // (signal/sigaction called while this loop is running)
+  for (int i = 0; i < NSIG; i++) {
+    struct sigaction existing_sa;
+    if (REAL(sigaction)(i, NULL, &existing_sa) == 0) {
+      auto const existing_handler = existing_sa.sa_handler;
+      if (existing_handler != SIG_IGN && existing_handler != SIG_DFL) {
+        __sigsan_handlers[i] = (uintptr_t)existing_handler;
+        if (existing_sa.sa_flags & SA_SIGINFO) {
+          existing_sa.sa_handler = __sigsan_handler;
+        } else {
+          existing_sa.sa_handler =
+              (signal_handler)(uintptr_t)__sigsan_extended_handler;
         }
+      }
     }
+  }
 }

>From c5db568b858ea325042238942a322c7e7b7c4a03 Mon Sep 17 00:00:00 2001
From: Ben Kallus <[email protected]>
Date: Fri, 12 Dec 2025 09:32:35 -0500
Subject: [PATCH 3/5] add pthread_mutex_whatever

---
 compiler-rt/lib/sigsan/sigsan.cpp | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/compiler-rt/lib/sigsan/sigsan.cpp 
b/compiler-rt/lib/sigsan/sigsan.cpp
index b48583740e2b2..39d4bd44e8ea7 100644
--- a/compiler-rt/lib/sigsan/sigsan.cpp
+++ b/compiler-rt/lib/sigsan/sigsan.cpp
@@ -216,6 +216,12 @@ INTERCEPTOR(void, syslog, int priority, const char 
*format, ...) {
   va_end(ap);
 }
 
+SIGSAN_INTERCEPTOR(int, pthread_mutex_init, (mutex, mutexattr), 
pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
+SIGSAN_INTERCEPTOR(int, pthread_mutex_lock, (mutex), pthread_mutex_t *mutex)
+SIGSAN_INTERCEPTOR(int, pthread_mutex_trylock, (mutex), pthread_mutex_t *mutex)
+SIGSAN_INTERCEPTOR(int, pthread_mutex_unlock, (mutex), pthread_mutex_t *mutex)
+SIGSAN_INTERCEPTOR(int, pthread_mutex_destroy, (mutex), pthread_mutex_t *mutex)
+
 __attribute__((constructor)) void __sigsan_init() {
   SetCommonFlagsDefaults();
   InitializeCommonFlags();
@@ -257,6 +263,13 @@ __attribute__((constructor)) void __sigsan_init() {
   INTERCEPT_FUNCTION(vsyslog);
   INTERCEPT_FUNCTION(syslog);
 
+  // pthreads
+  INTERCEPT_FUNCTION(pthread_mutex_init);
+  INTERCEPT_FUNCTION(pthread_mutex_lock);
+  INTERCEPT_FUNCTION(pthread_mutex_trylock);
+  INTERCEPT_FUNCTION(pthread_mutex_unlock);
+  INTERCEPT_FUNCTION(pthread_mutex_destroy);
+
   // TODO: Fix race conditions.
   // (signal/sigaction called while this loop is running)
   for (int i = 0; i < NSIG; i++) {

>From 174017af9ab3ce563f402b71d244f6c09d30194a Mon Sep 17 00:00:00 2001
From: Ben Kallus <[email protected]>
Date: Fri, 12 Dec 2025 16:29:00 -0500
Subject: [PATCH 4/5] Add vasprintf and saprintf checks

---
 compiler-rt/lib/sigsan/CMakeLists.txt |  2 +-
 compiler-rt/lib/sigsan/sigsan.cpp     | 14 ++++++++++++++
 2 files changed, 15 insertions(+), 1 deletion(-)

diff --git a/compiler-rt/lib/sigsan/CMakeLists.txt 
b/compiler-rt/lib/sigsan/CMakeLists.txt
index 1168e0fcc9973..9c446ae5227db 100644
--- a/compiler-rt/lib/sigsan/CMakeLists.txt
+++ b/compiler-rt/lib/sigsan/CMakeLists.txt
@@ -1,10 +1,10 @@
 include_directories(..)
 
-# Runtime library sources and build flags.
 set(SIGSAN_SOURCES
   sigsan.cpp
 )
 
+# TODO: support other architectures
 add_compiler_rt_component(sigsan)
 add_compiler_rt_runtime(clang_rt.sigsan
     STATIC
diff --git a/compiler-rt/lib/sigsan/sigsan.cpp 
b/compiler-rt/lib/sigsan/sigsan.cpp
index 39d4bd44e8ea7..f14ed9357636c 100644
--- a/compiler-rt/lib/sigsan/sigsan.cpp
+++ b/compiler-rt/lib/sigsan/sigsan.cpp
@@ -203,6 +203,16 @@ SIGSAN_INTERCEPTOR(FILE *, fdopen, (fd, mode), int fd, 
const char *mode)
 SIGSAN_INTERCEPTOR(FILE *, freopen, (path, mode, stream), const char *path,
                    const char *mode, FILE *stream)
 
+// GNU stdio
+SIGSAN_INTERCEPTOR(int, vasprintf, (strp, fmt, ap), char **strp, const char 
*fmt, va_list ap)
+INTERCEPTOR(int, asprintf, char **strp, const char *fmt, ...) {
+  va_list ap;
+  va_start(ap, fmt);
+  auto const result = REAL(vasprintf)(strp, fmt, ap);
+  va_end(ap);
+  return result;
+}
+
 // syslog
 SIGSAN_INTERCEPTOR(void, openlog, (ident, option, facility), const char *ident,
                    int option, int facility)
@@ -257,6 +267,10 @@ __attribute__((constructor)) void __sigsan_init() {
   INTERCEPT_FUNCTION(fdopen);
   INTERCEPT_FUNCTION(freopen);
 
+  // GNU stdio
+  INTERCEPT_FUNCTION(vasprintf);
+  INTERCEPT_FUNCTION(asprintf);
+
   // syslog
   INTERCEPT_FUNCTION(openlog);
   INTERCEPT_FUNCTION(closelog);

>From 062745b7a861ef7e2dd8509733ef4b8b0e24bf76 Mon Sep 17 00:00:00 2001
From: Ben Kallus <[email protected]>
Date: Fri, 12 Dec 2025 16:35:26 -0500
Subject: [PATCH 5/5] format

---
 compiler-rt/lib/sigsan/sigsan.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/compiler-rt/lib/sigsan/sigsan.cpp 
b/compiler-rt/lib/sigsan/sigsan.cpp
index f14ed9357636c..939562f52faaa 100644
--- a/compiler-rt/lib/sigsan/sigsan.cpp
+++ b/compiler-rt/lib/sigsan/sigsan.cpp
@@ -204,7 +204,8 @@ SIGSAN_INTERCEPTOR(FILE *, freopen, (path, mode, stream), 
const char *path,
                    const char *mode, FILE *stream)
 
 // GNU stdio
-SIGSAN_INTERCEPTOR(int, vasprintf, (strp, fmt, ap), char **strp, const char 
*fmt, va_list ap)
+SIGSAN_INTERCEPTOR(int, vasprintf, (strp, fmt, ap), char **strp,
+                   const char *fmt, va_list ap)
 INTERCEPTOR(int, asprintf, char **strp, const char *fmt, ...) {
   va_list ap;
   va_start(ap, fmt);
@@ -226,7 +227,8 @@ INTERCEPTOR(void, syslog, int priority, const char *format, 
...) {
   va_end(ap);
 }
 
-SIGSAN_INTERCEPTOR(int, pthread_mutex_init, (mutex, mutexattr), 
pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
+SIGSAN_INTERCEPTOR(int, pthread_mutex_init, (mutex, mutexattr),
+                   pthread_mutex_t *mutex, const pthread_mutexattr_t 
*mutexattr)
 SIGSAN_INTERCEPTOR(int, pthread_mutex_lock, (mutex), pthread_mutex_t *mutex)
 SIGSAN_INTERCEPTOR(int, pthread_mutex_trylock, (mutex), pthread_mutex_t *mutex)
 SIGSAN_INTERCEPTOR(int, pthread_mutex_unlock, (mutex), pthread_mutex_t *mutex)

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to