From 1b3d75f8bf14148f9d02874c218550bd87d9878c Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Fri, 21 Nov 2025 12:44:59 -0800 Subject: [PATCH 1/2] =?UTF-8?q?[=F0=9D=98=80=F0=9D=97=BD=F0=9D=97=BF]=20in?= =?UTF-8?q?itial=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Created using spr 1.3.7 --- .../ubsan_minimal/ubsan_minimal_handlers.cpp | 49 +++++++++++++++---- .../TestCases/test-darwin-interface.c | 1 + 2 files changed, 41 insertions(+), 9 deletions(-) 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 // From 9a40b7905f03fcc4e9f5fa90a21c49fbcb33d0fd Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Fri, 21 Nov 2025 12:47:21 -0800 Subject: [PATCH 2/2] messed up merge Created using spr 1.3.7 --- compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp b/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp index 034071f527362..480c5917877a3 100644 --- a/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp +++ b/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp @@ -175,6 +175,14 @@ void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) { 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")