xref: /freebsd-src/contrib/llvm-project/compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp (revision bdd1243df58e60e85101c09001d9812a789b6bc4)
168d75effSDimitry Andric #include "sanitizer_common/sanitizer_atomic.h"
268d75effSDimitry Andric 
368d75effSDimitry Andric #include <stdlib.h>
468d75effSDimitry Andric #include <stdint.h>
568d75effSDimitry Andric #include <string.h>
668d75effSDimitry Andric #include <unistd.h>
768d75effSDimitry Andric 
868d75effSDimitry Andric #ifdef KERNEL_USE
968d75effSDimitry Andric extern "C" void ubsan_message(const char *msg);
message(const char * msg)1068d75effSDimitry Andric static void message(const char *msg) { ubsan_message(msg); }
1168d75effSDimitry Andric #else
message(const char * msg)1268d75effSDimitry Andric static void message(const char *msg) {
13e8d8bef9SDimitry Andric   (void)write(2, msg, strlen(msg));
1468d75effSDimitry Andric }
1568d75effSDimitry Andric #endif
1668d75effSDimitry Andric 
1768d75effSDimitry Andric static const int kMaxCallerPcs = 20;
1868d75effSDimitry Andric static __sanitizer::atomic_uintptr_t caller_pcs[kMaxCallerPcs];
1968d75effSDimitry Andric // Number of elements in caller_pcs. A special value of kMaxCallerPcs + 1 means
2068d75effSDimitry Andric // that "too many errors" has already been reported.
2168d75effSDimitry Andric static __sanitizer::atomic_uint32_t caller_pcs_sz;
2268d75effSDimitry Andric 
report_this_error(uintptr_t caller)23*bdd1243dSDimitry Andric __attribute__((noinline)) static bool report_this_error(uintptr_t caller) {
24*bdd1243dSDimitry Andric   if (caller == 0)
25*bdd1243dSDimitry Andric     return false;
2668d75effSDimitry Andric   while (true) {
2768d75effSDimitry Andric     unsigned sz = __sanitizer::atomic_load_relaxed(&caller_pcs_sz);
2868d75effSDimitry Andric     if (sz > kMaxCallerPcs) return false;  // early exit
2968d75effSDimitry Andric     // when sz==kMaxCallerPcs print "too many errors", but only when cmpxchg
3068d75effSDimitry Andric     // succeeds in order to not print it multiple times.
3168d75effSDimitry Andric     if (sz > 0 && sz < kMaxCallerPcs) {
3268d75effSDimitry Andric       uintptr_t p;
3368d75effSDimitry Andric       for (unsigned i = 0; i < sz; ++i) {
3468d75effSDimitry Andric         p = __sanitizer::atomic_load_relaxed(&caller_pcs[i]);
3568d75effSDimitry Andric         if (p == 0) break;  // Concurrent update.
3668d75effSDimitry Andric         if (p == caller) return false;
3768d75effSDimitry Andric       }
3868d75effSDimitry Andric       if (p == 0) continue;  // FIXME: yield?
3968d75effSDimitry Andric     }
4068d75effSDimitry Andric 
4168d75effSDimitry Andric     if (!__sanitizer::atomic_compare_exchange_strong(
4268d75effSDimitry Andric             &caller_pcs_sz, &sz, sz + 1, __sanitizer::memory_order_seq_cst))
4368d75effSDimitry Andric       continue;  // Concurrent update! Try again from the start.
4468d75effSDimitry Andric 
4568d75effSDimitry Andric     if (sz == kMaxCallerPcs) {
4668d75effSDimitry Andric       message("ubsan: too many errors\n");
4768d75effSDimitry Andric       return false;
4868d75effSDimitry Andric     }
4968d75effSDimitry Andric     __sanitizer::atomic_store_relaxed(&caller_pcs[sz], caller);
5068d75effSDimitry Andric     return true;
5168d75effSDimitry Andric   }
5268d75effSDimitry Andric }
5368d75effSDimitry Andric 
decorate_msg(char * buf,uintptr_t caller)54*bdd1243dSDimitry Andric __attribute__((noinline)) static void decorate_msg(char *buf,
55*bdd1243dSDimitry Andric                                                    uintptr_t caller) {
56*bdd1243dSDimitry Andric   // print the address by nibbles
57*bdd1243dSDimitry Andric   for (unsigned shift = sizeof(uintptr_t) * 8; shift;) {
58*bdd1243dSDimitry Andric     shift -= 4;
59*bdd1243dSDimitry Andric     unsigned nibble = (caller >> shift) & 0xf;
60*bdd1243dSDimitry Andric     *(buf++) = nibble < 10 ? nibble + '0' : nibble - 10 + 'a';
61*bdd1243dSDimitry Andric   }
62*bdd1243dSDimitry Andric   // finish the message
63*bdd1243dSDimitry Andric   buf[0] = '\n';
64*bdd1243dSDimitry Andric   buf[1] = '\0';
65*bdd1243dSDimitry Andric }
66*bdd1243dSDimitry Andric 
6768d75effSDimitry Andric #if defined(__ANDROID__)
6868d75effSDimitry Andric extern "C" __attribute__((weak)) void android_set_abort_message(const char *);
abort_with_message(const char * msg)6968d75effSDimitry Andric static void abort_with_message(const char *msg) {
7068d75effSDimitry Andric   if (&android_set_abort_message) android_set_abort_message(msg);
7168d75effSDimitry Andric   abort();
7268d75effSDimitry Andric }
7368d75effSDimitry Andric #else
abort_with_message(const char *)7468d75effSDimitry Andric static void abort_with_message(const char *) { abort(); }
7568d75effSDimitry Andric #endif
7668d75effSDimitry Andric 
7768d75effSDimitry Andric #if SANITIZER_DEBUG
7868d75effSDimitry Andric namespace __sanitizer {
7968d75effSDimitry Andric // The DCHECK macro needs this symbol to be defined.
CheckFailed(const char * file,int,const char * cond,u64,u64)8068d75effSDimitry Andric void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) {
8168d75effSDimitry Andric   message("Sanitizer CHECK failed: ");
8268d75effSDimitry Andric   message(file);
8368d75effSDimitry Andric   message(":?? : "); // FIXME: Show line number.
8468d75effSDimitry Andric   message(cond);
8568d75effSDimitry Andric   abort();
8668d75effSDimitry Andric }
8768d75effSDimitry Andric } // namespace __sanitizer
8868d75effSDimitry Andric #endif
8968d75effSDimitry Andric 
9068d75effSDimitry Andric #define INTERFACE extern "C" __attribute__((visibility("default")))
9168d75effSDimitry Andric 
92*bdd1243dSDimitry Andric // How many chars we need to reserve to print an address.
93*bdd1243dSDimitry Andric constexpr unsigned kAddrBuf = SANITIZER_WORDSIZE / 4;
94*bdd1243dSDimitry Andric #define MSG_TMPL(msg) "ubsan: " msg " by 0x"
95*bdd1243dSDimitry Andric #define MSG_TMPL_END(buf, msg) (buf + sizeof(MSG_TMPL(msg)) - 1)
96*bdd1243dSDimitry Andric // Reserve an additional byte for '\n'.
97*bdd1243dSDimitry Andric #define MSG_BUF_LEN(msg) (sizeof(MSG_TMPL(msg)) + kAddrBuf + 1)
98*bdd1243dSDimitry Andric 
9968d75effSDimitry Andric #define HANDLER_RECOVER(name, msg)                               \
10068d75effSDimitry Andric   INTERFACE void __ubsan_handle_##name##_minimal() {             \
101*bdd1243dSDimitry Andric     uintptr_t caller = GET_CALLER_PC();                  \
102*bdd1243dSDimitry Andric     if (!report_this_error(caller)) return;                      \
103*bdd1243dSDimitry Andric     char msg_buf[MSG_BUF_LEN(msg)] = MSG_TMPL(msg);              \
104*bdd1243dSDimitry Andric     decorate_msg(MSG_TMPL_END(msg_buf, msg), caller);            \
105*bdd1243dSDimitry Andric     message(msg_buf);                                            \
10668d75effSDimitry Andric   }
10768d75effSDimitry Andric 
10868d75effSDimitry Andric #define HANDLER_NORECOVER(name, msg)                             \
10968d75effSDimitry Andric   INTERFACE void __ubsan_handle_##name##_minimal_abort() {       \
110*bdd1243dSDimitry Andric     char msg_buf[MSG_BUF_LEN(msg)] = MSG_TMPL(msg);              \
111*bdd1243dSDimitry Andric     decorate_msg(MSG_TMPL_END(msg_buf, msg), GET_CALLER_PC());   \
112*bdd1243dSDimitry Andric     message(msg_buf);                                            \
113*bdd1243dSDimitry Andric     abort_with_message(msg_buf);                                 \
11468d75effSDimitry Andric   }
11568d75effSDimitry Andric 
11668d75effSDimitry Andric #define HANDLER(name, msg)                                       \
11768d75effSDimitry Andric   HANDLER_RECOVER(name, msg)                                     \
11868d75effSDimitry Andric   HANDLER_NORECOVER(name, msg)
11968d75effSDimitry Andric 
12068d75effSDimitry Andric HANDLER(type_mismatch, "type-mismatch")
12168d75effSDimitry Andric HANDLER(alignment_assumption, "alignment-assumption")
12268d75effSDimitry Andric HANDLER(add_overflow, "add-overflow")
12368d75effSDimitry Andric HANDLER(sub_overflow, "sub-overflow")
12468d75effSDimitry Andric HANDLER(mul_overflow, "mul-overflow")
12568d75effSDimitry Andric HANDLER(negate_overflow, "negate-overflow")
12668d75effSDimitry Andric HANDLER(divrem_overflow, "divrem-overflow")
12768d75effSDimitry Andric HANDLER(shift_out_of_bounds, "shift-out-of-bounds")
12868d75effSDimitry Andric HANDLER(out_of_bounds, "out-of-bounds")
12968d75effSDimitry Andric HANDLER_RECOVER(builtin_unreachable, "builtin-unreachable")
13068d75effSDimitry Andric HANDLER_RECOVER(missing_return, "missing-return")
13168d75effSDimitry Andric HANDLER(vla_bound_not_positive, "vla-bound-not-positive")
13268d75effSDimitry Andric HANDLER(float_cast_overflow, "float-cast-overflow")
13368d75effSDimitry Andric HANDLER(load_invalid_value, "load-invalid-value")
13468d75effSDimitry Andric HANDLER(invalid_builtin, "invalid-builtin")
1355ffd83dbSDimitry Andric HANDLER(invalid_objc_cast, "invalid-objc-cast")
13668d75effSDimitry Andric HANDLER(function_type_mismatch, "function-type-mismatch")
13768d75effSDimitry Andric HANDLER(implicit_conversion, "implicit-conversion")
13868d75effSDimitry Andric HANDLER(nonnull_arg, "nonnull-arg")
13968d75effSDimitry Andric HANDLER(nonnull_return, "nonnull-return")
14068d75effSDimitry Andric HANDLER(nullability_arg, "nullability-arg")
14168d75effSDimitry Andric HANDLER(nullability_return, "nullability-return")
14268d75effSDimitry Andric HANDLER(pointer_overflow, "pointer-overflow")
14368d75effSDimitry Andric HANDLER(cfi_check_fail, "cfi-check-fail")
144