[compiler-rt] [sanitizer_common] Add GNU/Linux main wrapper support (PR #196365)

Kunqiu Chen via llvm-commits llvm-commits at lists.llvm.org
Fri May 8 01:29:34 PDT 2026


https://github.com/Camsyn updated https://github.com/llvm/llvm-project/pull/196365

>From 986afc817019284c879d7c3b465c071e907ef90b Mon Sep 17 00:00:00 2001
From: Camsyn <camsyn at foxmail.com>
Date: Fri, 8 May 2026 00:47:37 +0800
Subject: [PATCH] Add sanitizer_common main wrapper support

---
 .../lib/sanitizer_common/CMakeLists.txt       |  1 +
 .../lib/sanitizer_common/sanitizer_common.h   |  3 ++
 .../sanitizer_common_interceptors_main.inc    | 52 +++++++++++++++++++
 3 files changed, 56 insertions(+)
 create mode 100644 compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_main.inc

diff --git a/compiler-rt/lib/sanitizer_common/CMakeLists.txt b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
index 96c23c6d8ab82..c7a6da2e0aab2 100644
--- a/compiler-rt/lib/sanitizer_common/CMakeLists.txt
+++ b/compiler-rt/lib/sanitizer_common/CMakeLists.txt
@@ -135,6 +135,7 @@ set(SANITIZER_IMPL_HEADERS
   sanitizer_common_interceptors.inc
   sanitizer_common_interceptors_format.inc
   sanitizer_common_interceptors_ioctl.inc
+  sanitizer_common_interceptors_main.inc
   sanitizer_common_interceptors_memintrinsics.inc
   sanitizer_common_interface.inc
   sanitizer_common_interface_posix.inc
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common.h b/compiler-rt/lib/sanitizer_common/sanitizer_common.h
index 4dd2187df2272..4ec27339be041 100644
--- a/compiler-rt/lib/sanitizer_common/sanitizer_common.h
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common.h
@@ -34,6 +34,9 @@ struct SignalContext;
 struct StackTrace;
 struct SymbolizedStack;
 
+// The full type of the function `main`.
+using MainFnTy = int (*)(int argc, char** argv, char** envp);
+
 // Constants.
 const uptr kWordSize = SANITIZER_WORDSIZE / 8;
 const uptr kWordSizeInBits = 8 * kWordSize;
diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_main.inc b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_main.inc
new file mode 100644
index 0000000000000..e3e0373b9e50d
--- /dev/null
+++ b/compiler-rt/lib/sanitizer_common/sanitizer_common_interceptors_main.inc
@@ -0,0 +1,52 @@
+//===-- sanitizer_common_interceptors_main.inc -----------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Opt-in Linux/glibc main wrapper via __libc_start_main interception.
+//
+// A sanitizer enables this file by defining:
+//   #define MAIN_WRAPPER(main, argc, argv, envp) \
+//     ToolMainWrapper(main, argc, argv, envp)
+// before including it. `main` is the real user main (__sanitizer::MainFnTy);
+// argc, argv, and envp are the startup arguments forwarded to the wrapper.
+// The wrapper returns the process exit code and decides when to call main.
+//
+//===----------------------------------------------------------------------===//
+
+#include "interception/interception.h"
+#include "sanitizer_common.h"
+#include "sanitizer_platform.h"
+
+// __libc_start_main is a dynamic symbol in glibc.
+#if SANITIZER_LINUX && SANITIZER_GLIBC && defined(MAIN_WRAPPER)
+namespace __sanitizer {
+namespace {
+
+MainFnTy real_main;
+
+int WrappedMain(int argc, char **argv, char **envp) {
+  return MAIN_WRAPPER(real_main, argc, argv, envp);
+}
+
+}  // namespace
+}  // namespace __sanitizer
+
+INTERCEPTOR(int, __libc_start_main, __sanitizer::MainFnTy main, int argc,
+            char **argv, void (*init)(), void (*fini)(), void (*rtld_fini)(),
+            void *stack_end) {
+  // Lazily obtain the address of real __libc_start_main.
+  // Equivalent to the single-threaded version of functionl local static
+  // initialization.
+  // This is thread-safe as __libc_start_main is expected to be called AT FIRST
+  // from _start (the entry point of ELF), which is single-threaded.
+  if (!REAL(__libc_start_main))
+    CHECK(INTERCEPT_FUNCTION(__libc_start_main));
+  __sanitizer::real_main = main;
+  return REAL(__libc_start_main)(__sanitizer::WrappedMain, argc, argv, init,
+                                 fini, rtld_fini, stack_end);
+}
+#endif



More information about the llvm-commits mailing list