diff --git a/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp b/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp index ebc36a8583e05..480c5917877a3 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,7 +171,8 @@ 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") 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 849401ef78741..f7702c99ee709 100644 --- a/compiler-rt/test/ubsan_minimal/TestCases/test-darwin-interface.c +++ b/compiler-rt/test/ubsan_minimal/TestCases/test-darwin-interface.c @@ -8,6 +8,7 @@ // RUN: sed -e 's/.*"\(.*libclang_rt.ubsan_minimal_osx_dynamic.dylib\)".*/\1/' | \ // RUN: tr -d '\n' > %t.dylib_path1 // RUN: nm -jgU %{readfile:%t.dylib_path1} | grep "^___ubsan_handle" \ +// RUN: | grep -vE "_minimal_preserve" \ // RUN: | sed 's/_minimal//g' \ // RUN: > %t.minimal.symlist //