[compiler-rt] Reapply "[UBSan] [compiler-rt] add preservecc variants of handlers" (#168973) (PR #169091)

via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 21 12:45:47 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

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

Author: Florian Mayer (fmayer)

<details>
<summary>Changes</summary>

This reverts commit 418204d9c108351340fe21194ace0e31157b7189.


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


2 Files Affected:

- (modified) compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp (+40-9) 
- (modified) compiler-rt/test/ubsan_minimal/TestCases/test-darwin-interface.c (+1) 


``````````diff
diff --git a/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp b/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp
index ebc36a8583e05..034071f527362 100644
--- a/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp
+++ b/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp
@@ -12,6 +12,22 @@ static void message(const char *msg) { ubsan_message(msg); }
 static void message(const char *msg) { (void)write(2, msg, strlen(msg)); }
 #endif
 
+// If for some reason we cannot build the runtime with preserve_all, don't
+// emit any symbol. Programs that need them will fail to link, but that is
+// better than randomly corrupted registers.
+// Some architectures don't support preserve_all (but clang still has the)
+// attribute. For now, only support x86-64 and aarch64.
+#if defined(__clang__) && defined(__has_cpp_attribute) &&                      \
+    (defined(__x86_64__) || defined(__aarch64__))
+#if __has_cpp_attribute(clang::preserve_all)
+#define PRESERVE_HANDLERS true
+#else
+#define PRESERVE_HANDLERS false
+#endif
+#else
+#define PRESERVE_HANDLERS false
+#endif
+
 static const int kMaxCallerPcs = 20;
 static __sanitizer::atomic_uintptr_t caller_pcs[kMaxCallerPcs];
 // Number of elements in caller_pcs. A special value of kMaxCallerPcs + 1 means
@@ -85,6 +101,18 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error, const char *kind,
   }
 }
 
+#if PRESERVE_HANDLERS
+SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error_preserve,
+                             const char *kind, uintptr_t caller)
+[[clang::preserve_all]] {
+  // Additional indirecton so the user can override this with their own
+  // preserve_all function. This would allow, e.g., a function that reports the
+  // first error only, so for all subsequent calls we can skip the register save
+  // / restore.
+  __ubsan_report_error(kind, caller);
+}
+#endif
+
 SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error_fatal, const char *kind,
                              uintptr_t caller) {
   // Use another handlers, in case it's already overriden.
@@ -119,6 +147,16 @@ void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) {
 
 #define INTERFACE extern "C" __attribute__((visibility("default")))
 
+#if PRESERVE_HANDLERS
+#define HANDLER_PRESERVE(name, kind)                                           \
+  INTERFACE void __ubsan_handle_##name##_minimal_preserve()                    \
+      [[clang::preserve_all]] {                                                \
+    __ubsan_report_error_preserve(kind, GET_CALLER_PC());                      \
+  }
+#else
+#define HANDLER_PRESERVE(name, kind)
+#endif
+
 #define HANDLER_RECOVER(name, kind)                                            \
   INTERFACE void __ubsan_handle_##name##_minimal() {                           \
     __ubsan_report_error(kind, GET_CALLER_PC());                               \
@@ -133,17 +171,10 @@ void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) {
 
 #define HANDLER(name, kind)                                                    \
   HANDLER_RECOVER(name, kind)                                                  \
-  HANDLER_NORECOVER(name, kind)
+  HANDLER_NORECOVER(name, kind)                                                \
+  HANDLER_PRESERVE(name, kind)
 
 HANDLER(type_mismatch, "type-mismatch")
-HANDLER(alignment_assumption, "alignment-assumption")
-HANDLER(add_overflow, "add-overflow")
-HANDLER(sub_overflow, "sub-overflow")
-HANDLER(mul_overflow, "mul-overflow")
-HANDLER(negate_overflow, "negate-overflow")
-HANDLER(divrem_overflow, "divrem-overflow")
-HANDLER(shift_out_of_bounds, "shift-out-of-bounds")
-HANDLER(out_of_bounds, "out-of-bounds")
 HANDLER(local_out_of_bounds, "local-out-of-bounds")
 HANDLER_RECOVER(builtin_unreachable, "builtin-unreachable")
 HANDLER_RECOVER(missing_return, "missing-return")
diff --git a/compiler-rt/test/ubsan_minimal/TestCases/test-darwin-interface.c b/compiler-rt/test/ubsan_minimal/TestCases/test-darwin-interface.c
index abc1073e02073..3c76e5aadc087 100644
--- a/compiler-rt/test/ubsan_minimal/TestCases/test-darwin-interface.c
+++ b/compiler-rt/test/ubsan_minimal/TestCases/test-darwin-interface.c
@@ -4,6 +4,7 @@
 // REQUIRES: x86_64-darwin
 
 // RUN: nm -jgU `%clangxx_min_runtime -fsanitize-minimal-runtime -fsanitize=undefined %s -o %t '-###' 2>&1 | grep "libclang_rt.ubsan_minimal_osx_dynamic.dylib" | sed -e 's/.*"\(.*libclang_rt.ubsan_minimal_osx_dynamic.dylib\)".*/\1/'` | grep "^___ubsan_handle" \
+// RUN:  | grep -vE "_minimal_preserve" \
 // RUN:  | sed 's/_minimal//g' \
 // RUN:  > %t.minimal.symlist
 //

``````````

</details>


https://github.com/llvm/llvm-project/pull/169091


More information about the llvm-commits mailing list