@@ -12,6 +12,22 @@ static void message(const char *msg) { ubsan_message(msg); }
1212static void message (const char *msg) { (void )write (2 , msg, strlen (msg)); }
1313#endif
1414
15+ // If for some reason we cannot build the runtime with preserve_all, don't
16+ // emit any symbol. Programs that need them will fail to link, but that is
17+ // better than randomly corrupted registers.
18+ // Some architectures don't support preserve_all (but clang still has the)
19+ // attribute. For now, only support x86-64 and aarch64.
20+ #if defined(__clang__) && defined(__has_cpp_attribute) && \
21+ (defined (__x86_64__) || defined (__aarch64__))
22+ #if __has_cpp_attribute(clang::preserve_all)
23+ #define PRESERVE_HANDLERS true
24+ #else
25+ #define PRESERVE_HANDLERS false
26+ #endif
27+ #else
28+ #define PRESERVE_HANDLERS false
29+ #endif
30+
1531static const int kMaxCallerPcs = 20 ;
1632static __sanitizer::atomic_uintptr_t caller_pcs[kMaxCallerPcs ];
1733// 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,
85101 }
86102}
87103
104+ #if PRESERVE_HANDLERS
105+ SANITIZER_INTERFACE_WEAK_DEF (void , __ubsan_report_error_preserve,
106+ const char *kind, uintptr_t caller)
107+ [[clang::preserve_all]] {
108+ // Additional indirecton so the user can override this with their own
109+ // preserve_all function. This would allow, e.g., a function that reports the
110+ // first error only, so for all subsequent calls we can skip the register save
111+ // / restore.
112+ __ubsan_report_error (kind, caller);
113+ }
114+ #endif
115+
88116SANITIZER_INTERFACE_WEAK_DEF (void , __ubsan_report_error_fatal, const char *kind,
89117 uintptr_t caller) {
90118 // 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) {
119147
120148#define INTERFACE extern " C" __attribute__((visibility(" default" )))
121149
150+ #if PRESERVE_HANDLERS
151+ #define HANDLER_PRESERVE (name, kind ) \
152+ INTERFACE void __ubsan_handle_##name##_minimal_preserve() \
153+ [[clang::preserve_all]] { \
154+ __ubsan_report_error_preserve (kind, GET_CALLER_PC ()); \
155+ }
156+ #else
157+ #define HANDLER_PRESERVE (name, kind )
158+ #endif
159+
122160#define HANDLER_RECOVER (name, kind ) \
123161 INTERFACE void __ubsan_handle_##name##_minimal() { \
124162 __ubsan_report_error (kind, GET_CALLER_PC ()); \
@@ -133,7 +171,8 @@ void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) {
133171
134172#define HANDLER (name, kind ) \
135173 HANDLER_RECOVER (name, kind) \
136- HANDLER_NORECOVER(name, kind)
174+ HANDLER_NORECOVER(name, kind) \
175+ HANDLER_PRESERVE(name, kind)
137176
138177HANDLER(type_mismatch, " type-mismatch" )
139178HANDLER(alignment_assumption, " alignment-assumption" )
0 commit comments