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/6] 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/6] 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/6] 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/6] 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/6] 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) >From 48ea8e63b87ff86b9b1ee6b999d49020627216fe Mon Sep 17 00:00:00 2001 From: Ben Kallus <[email protected]> Date: Fri, 12 Dec 2025 16:39:12 -0500 Subject: [PATCH 6/6] clang-tidy --- compiler-rt/lib/sigsan/sigsan.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler-rt/lib/sigsan/sigsan.cpp b/compiler-rt/lib/sigsan/sigsan.cpp index 939562f52faaa..bc111c1785770 100644 --- a/compiler-rt/lib/sigsan/sigsan.cpp +++ b/compiler-rt/lib/sigsan/sigsan.cpp @@ -24,7 +24,7 @@ thread_local unsigned int __sigsan_signal_depth = 0; // don't cause problems static uintptr_t __sigsan_handlers[NSIG]; -[[noreturn]] void __sigsan_print_backtrace_and_die() { +[[noreturn]] static void __sigsan_print_backtrace_and_die() { BufferedStackTrace stack; GET_CURRENT_PC_BP_SP; (void)sp; @@ -33,7 +33,7 @@ static uintptr_t __sigsan_handlers[NSIG]; Die(); } -[[noreturn]] void +[[noreturn]] static 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 :) */ @@ -46,7 +46,7 @@ __sigsan_die_from_unsafe_function_call(char const *func_name) { __sigsan_print_backtrace_and_die(); } -[[noreturn]] void __sigsan_die_from_modified_errno() { +[[noreturn]] static void __sigsan_die_from_modified_errno() { __sigsan_signal_depth = 0; /* To avoid having to make this function async-signal-safe :) */ SanitizerCommonDecorator d; @@ -56,7 +56,7 @@ __sigsan_die_from_unsafe_function_call(char const *func_name) { __sigsan_print_backtrace_and_die(); } -void __sigsan_handler(int signum) { +static void __sigsan_handler(int signum) { __sigsan_signal_depth++; int saved_errno = errno; ((signal_handler)(__sigsan_handlers[signum]))(signum); @@ -66,7 +66,7 @@ void __sigsan_handler(int signum) { __sigsan_signal_depth--; } -void __sigsan_extended_handler(int signum, siginfo_t *si, void *arg) { +static void __sigsan_extended_handler(int signum, siginfo_t *si, void *arg) { __sigsan_signal_depth++; int saved_errno = errno; ((extended_signal_handler)(__sigsan_handlers[signum]))(signum, si, arg); @@ -234,7 +234,7 @@ 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() { +static __attribute__((constructor)) void __sigsan_init() { SetCommonFlagsDefaults(); InitializeCommonFlags(); _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
