xref: /llvm-project/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp (revision c2aee5062087f193cb5756f378c248c7d91b7245)
1a9aa8137SNico Weber #include "sanitizer_common/sanitizer_atomic.h"
2a9aa8137SNico Weber 
3a9aa8137SNico Weber #include <stdlib.h>
4a9aa8137SNico Weber #include <stdint.h>
5a9aa8137SNico Weber #include <string.h>
6a9aa8137SNico Weber #include <unistd.h>
7a9aa8137SNico Weber 
8a9aa8137SNico Weber #ifdef KERNEL_USE
9a9aa8137SNico Weber extern "C" void ubsan_message(const char *msg);
10a9aa8137SNico Weber static void message(const char *msg) { ubsan_message(msg); }
11a9aa8137SNico Weber #else
12a9aa8137SNico Weber static void message(const char *msg) {
131ef0e94dSFangrui Song   (void)write(2, msg, strlen(msg));
14a9aa8137SNico Weber }
15a9aa8137SNico Weber #endif
16a9aa8137SNico Weber 
17a9aa8137SNico Weber static const int kMaxCallerPcs = 20;
18a9aa8137SNico Weber static __sanitizer::atomic_uintptr_t caller_pcs[kMaxCallerPcs];
19a9aa8137SNico Weber // Number of elements in caller_pcs. A special value of kMaxCallerPcs + 1 means
20a9aa8137SNico Weber // that "too many errors" has already been reported.
21a9aa8137SNico Weber static __sanitizer::atomic_uint32_t caller_pcs_sz;
22a9aa8137SNico Weber 
23e5e0f23aSKirill Stoimenov static char *append_str(const char *s, char *buf, const char *end) {
24e5e0f23aSKirill Stoimenov   for (const char *p = s; (buf < end) && (*p != '\0'); ++p, ++buf)
25e5e0f23aSKirill Stoimenov     *buf = *p;
26e5e0f23aSKirill Stoimenov   return buf;
27e5e0f23aSKirill Stoimenov }
28e5e0f23aSKirill Stoimenov 
29e5e0f23aSKirill Stoimenov static char *append_hex(uintptr_t d, char *buf, const char *end) {
30e5e0f23aSKirill Stoimenov   // Print the address by nibbles.
31e5e0f23aSKirill Stoimenov   for (unsigned shift = sizeof(uintptr_t) * 8; shift && buf < end;) {
32e5e0f23aSKirill Stoimenov     shift -= 4;
33e5e0f23aSKirill Stoimenov     unsigned nibble = (d >> shift) & 0xf;
34e5e0f23aSKirill Stoimenov     *(buf++) = nibble < 10 ? nibble + '0' : nibble - 10 + 'a';
35e5e0f23aSKirill Stoimenov   }
36e5e0f23aSKirill Stoimenov   return buf;
37e5e0f23aSKirill Stoimenov }
38e5e0f23aSKirill Stoimenov 
39e5e0f23aSKirill Stoimenov static void format_msg(const char *kind, uintptr_t caller, char *buf,
40e5e0f23aSKirill Stoimenov                        const char *end) {
41e5e0f23aSKirill Stoimenov   buf = append_str("ubsan: ", buf, end);
42e5e0f23aSKirill Stoimenov   buf = append_str(kind, buf, end);
43e5e0f23aSKirill Stoimenov   buf = append_str(" by 0x", buf, end);
44e5e0f23aSKirill Stoimenov   buf = append_hex(caller, buf, end);
45e5e0f23aSKirill Stoimenov   buf = append_str("\n", buf, end);
46e5e0f23aSKirill Stoimenov   if (buf == end)
47e5e0f23aSKirill Stoimenov     --buf; // Make sure we don't cause a buffer overflow.
48e5e0f23aSKirill Stoimenov   *buf = '\0';
49e5e0f23aSKirill Stoimenov }
50e5e0f23aSKirill Stoimenov 
5171d2fa79SKirill Stoimenov SANITIZER_INTERFACE_WEAK_DEF(void, __ubsan_report_error, const char *kind,
5271d2fa79SKirill Stoimenov                              uintptr_t caller) {
531959a555SIgor Kudrin   if (caller == 0)
54e5e0f23aSKirill Stoimenov     return;
55a9aa8137SNico Weber   while (true) {
56a9aa8137SNico Weber     unsigned sz = __sanitizer::atomic_load_relaxed(&caller_pcs_sz);
57e5e0f23aSKirill Stoimenov     if (sz > kMaxCallerPcs)
58e5e0f23aSKirill Stoimenov       return; // early exit
59a9aa8137SNico Weber     // when sz==kMaxCallerPcs print "too many errors", but only when cmpxchg
60a9aa8137SNico Weber     // succeeds in order to not print it multiple times.
61a9aa8137SNico Weber     if (sz > 0 && sz < kMaxCallerPcs) {
62a9aa8137SNico Weber       uintptr_t p;
63a9aa8137SNico Weber       for (unsigned i = 0; i < sz; ++i) {
64a9aa8137SNico Weber         p = __sanitizer::atomic_load_relaxed(&caller_pcs[i]);
65a9aa8137SNico Weber         if (p == 0) break;  // Concurrent update.
66e5e0f23aSKirill Stoimenov         if (p == caller)
67e5e0f23aSKirill Stoimenov           return;
68a9aa8137SNico Weber       }
69a9aa8137SNico Weber       if (p == 0) continue;  // FIXME: yield?
70a9aa8137SNico Weber     }
71a9aa8137SNico Weber 
72a9aa8137SNico Weber     if (!__sanitizer::atomic_compare_exchange_strong(
73a9aa8137SNico Weber             &caller_pcs_sz, &sz, sz + 1, __sanitizer::memory_order_seq_cst))
74a9aa8137SNico Weber       continue;  // Concurrent update! Try again from the start.
75a9aa8137SNico Weber 
76a9aa8137SNico Weber     if (sz == kMaxCallerPcs) {
77a9aa8137SNico Weber       message("ubsan: too many errors\n");
78e5e0f23aSKirill Stoimenov       return;
79a9aa8137SNico Weber     }
80a9aa8137SNico Weber     __sanitizer::atomic_store_relaxed(&caller_pcs[sz], caller);
81a9aa8137SNico Weber 
82e5e0f23aSKirill Stoimenov     char msg_buf[128];
83e5e0f23aSKirill Stoimenov     format_msg(kind, caller, msg_buf, msg_buf + sizeof(msg_buf));
84e5e0f23aSKirill Stoimenov     message(msg_buf);
8584c4efbcSIgor Kudrin   }
8684c4efbcSIgor Kudrin }
8784c4efbcSIgor Kudrin 
88a9aa8137SNico Weber #if defined(__ANDROID__)
89a9aa8137SNico Weber extern "C" __attribute__((weak)) void android_set_abort_message(const char *);
90e5e0f23aSKirill Stoimenov static void abort_with_message(const char *kind, uintptr_t caller) {
91e5e0f23aSKirill Stoimenov   char msg_buf[128];
92e5e0f23aSKirill Stoimenov   format_msg(kind, caller, msg_buf, msg_buf + sizeof(msg_buf));
93e5e0f23aSKirill Stoimenov   if (&android_set_abort_message)
94e5e0f23aSKirill Stoimenov     android_set_abort_message(msg_buf);
95a9aa8137SNico Weber   abort();
96a9aa8137SNico Weber }
97a9aa8137SNico Weber #else
98e5e0f23aSKirill Stoimenov static void abort_with_message(const char *kind, uintptr_t caller) { abort(); }
99a9aa8137SNico Weber #endif
100a9aa8137SNico Weber 
101a9aa8137SNico Weber #if SANITIZER_DEBUG
102a9aa8137SNico Weber namespace __sanitizer {
103a9aa8137SNico Weber // The DCHECK macro needs this symbol to be defined.
104a9aa8137SNico Weber void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) {
105a9aa8137SNico Weber   message("Sanitizer CHECK failed: ");
106a9aa8137SNico Weber   message(file);
107a9aa8137SNico Weber   message(":?? : "); // FIXME: Show line number.
108a9aa8137SNico Weber   message(cond);
109a9aa8137SNico Weber   abort();
110a9aa8137SNico Weber }
111a9aa8137SNico Weber } // namespace __sanitizer
112a9aa8137SNico Weber #endif
113a9aa8137SNico Weber 
114a9aa8137SNico Weber #define INTERFACE extern "C" __attribute__((visibility("default")))
115a9aa8137SNico Weber 
116e5e0f23aSKirill Stoimenov #define HANDLER_RECOVER(name, kind)                                            \
117a9aa8137SNico Weber   INTERFACE void __ubsan_handle_##name##_minimal() {                           \
11871d2fa79SKirill Stoimenov     __ubsan_report_error(kind, GET_CALLER_PC());                               \
119a9aa8137SNico Weber   }
120a9aa8137SNico Weber 
121e5e0f23aSKirill Stoimenov #define HANDLER_NORECOVER(name, kind)                                          \
122a9aa8137SNico Weber   INTERFACE void __ubsan_handle_##name##_minimal_abort() {                     \
123e5e0f23aSKirill Stoimenov     uintptr_t caller = GET_CALLER_PC();                                        \
12471d2fa79SKirill Stoimenov     __ubsan_report_error(kind, caller);                                        \
125e5e0f23aSKirill Stoimenov     abort_with_message(kind, caller);                                          \
126a9aa8137SNico Weber   }
127a9aa8137SNico Weber 
128e5e0f23aSKirill Stoimenov #define HANDLER(name, kind)                                                    \
129e5e0f23aSKirill Stoimenov   HANDLER_RECOVER(name, kind)                                                  \
130e5e0f23aSKirill Stoimenov   HANDLER_NORECOVER(name, kind)
131a9aa8137SNico Weber 
132a9aa8137SNico Weber HANDLER(type_mismatch, "type-mismatch")
133a9aa8137SNico Weber HANDLER(alignment_assumption, "alignment-assumption")
134a9aa8137SNico Weber HANDLER(add_overflow, "add-overflow")
135a9aa8137SNico Weber HANDLER(sub_overflow, "sub-overflow")
136a9aa8137SNico Weber HANDLER(mul_overflow, "mul-overflow")
137a9aa8137SNico Weber HANDLER(negate_overflow, "negate-overflow")
138a9aa8137SNico Weber HANDLER(divrem_overflow, "divrem-overflow")
139a9aa8137SNico Weber HANDLER(shift_out_of_bounds, "shift-out-of-bounds")
140a9aa8137SNico Weber HANDLER(out_of_bounds, "out-of-bounds")
141*c2aee506SVitaly Buka HANDLER(local_out_of_bounds, "local-out-of-bounds")
142a9aa8137SNico Weber HANDLER_RECOVER(builtin_unreachable, "builtin-unreachable")
143a9aa8137SNico Weber HANDLER_RECOVER(missing_return, "missing-return")
144a9aa8137SNico Weber HANDLER(vla_bound_not_positive, "vla-bound-not-positive")
145a9aa8137SNico Weber HANDLER(float_cast_overflow, "float-cast-overflow")
146a9aa8137SNico Weber HANDLER(load_invalid_value, "load-invalid-value")
147a9aa8137SNico Weber HANDLER(invalid_builtin, "invalid-builtin")
1488c4a65b9SVedant Kumar HANDLER(invalid_objc_cast, "invalid-objc-cast")
149a9aa8137SNico Weber HANDLER(function_type_mismatch, "function-type-mismatch")
150a9aa8137SNico Weber HANDLER(implicit_conversion, "implicit-conversion")
151a9aa8137SNico Weber HANDLER(nonnull_arg, "nonnull-arg")
152a9aa8137SNico Weber HANDLER(nonnull_return, "nonnull-return")
153a9aa8137SNico Weber HANDLER(nullability_arg, "nullability-arg")
154a9aa8137SNico Weber HANDLER(nullability_return, "nullability-return")
155a9aa8137SNico Weber HANDLER(pointer_overflow, "pointer-overflow")
156a9aa8137SNico Weber HANDLER(cfi_check_fail, "cfi-check-fail")
157