13cab2bb3Spatrick #include "sanitizer_common/sanitizer_atomic.h"
23cab2bb3Spatrick
33cab2bb3Spatrick #include <stdlib.h>
43cab2bb3Spatrick #include <stdint.h>
53cab2bb3Spatrick #include <string.h>
63cab2bb3Spatrick #include <unistd.h>
73cab2bb3Spatrick
83cab2bb3Spatrick #ifdef KERNEL_USE
93cab2bb3Spatrick extern "C" void ubsan_message(const char *msg);
message(const char * msg)103cab2bb3Spatrick static void message(const char *msg) { ubsan_message(msg); }
113cab2bb3Spatrick #else
message(const char * msg)123cab2bb3Spatrick static void message(const char *msg) {
13d89ec533Spatrick (void)write(2, msg, strlen(msg));
143cab2bb3Spatrick }
153cab2bb3Spatrick #endif
163cab2bb3Spatrick
173cab2bb3Spatrick static const int kMaxCallerPcs = 20;
183cab2bb3Spatrick static __sanitizer::atomic_uintptr_t caller_pcs[kMaxCallerPcs];
193cab2bb3Spatrick // Number of elements in caller_pcs. A special value of kMaxCallerPcs + 1 means
203cab2bb3Spatrick // that "too many errors" has already been reported.
213cab2bb3Spatrick static __sanitizer::atomic_uint32_t caller_pcs_sz;
223cab2bb3Spatrick
report_this_error(uintptr_t caller)23*810390e3Srobert __attribute__((noinline)) static bool report_this_error(uintptr_t caller) {
24*810390e3Srobert if (caller == 0)
25*810390e3Srobert return false;
263cab2bb3Spatrick while (true) {
273cab2bb3Spatrick unsigned sz = __sanitizer::atomic_load_relaxed(&caller_pcs_sz);
283cab2bb3Spatrick if (sz > kMaxCallerPcs) return false; // early exit
293cab2bb3Spatrick // when sz==kMaxCallerPcs print "too many errors", but only when cmpxchg
303cab2bb3Spatrick // succeeds in order to not print it multiple times.
313cab2bb3Spatrick if (sz > 0 && sz < kMaxCallerPcs) {
323cab2bb3Spatrick uintptr_t p;
333cab2bb3Spatrick for (unsigned i = 0; i < sz; ++i) {
343cab2bb3Spatrick p = __sanitizer::atomic_load_relaxed(&caller_pcs[i]);
353cab2bb3Spatrick if (p == 0) break; // Concurrent update.
363cab2bb3Spatrick if (p == caller) return false;
373cab2bb3Spatrick }
383cab2bb3Spatrick if (p == 0) continue; // FIXME: yield?
393cab2bb3Spatrick }
403cab2bb3Spatrick
413cab2bb3Spatrick if (!__sanitizer::atomic_compare_exchange_strong(
423cab2bb3Spatrick &caller_pcs_sz, &sz, sz + 1, __sanitizer::memory_order_seq_cst))
433cab2bb3Spatrick continue; // Concurrent update! Try again from the start.
443cab2bb3Spatrick
453cab2bb3Spatrick if (sz == kMaxCallerPcs) {
463cab2bb3Spatrick message("ubsan: too many errors\n");
473cab2bb3Spatrick return false;
483cab2bb3Spatrick }
493cab2bb3Spatrick __sanitizer::atomic_store_relaxed(&caller_pcs[sz], caller);
503cab2bb3Spatrick return true;
513cab2bb3Spatrick }
523cab2bb3Spatrick }
533cab2bb3Spatrick
decorate_msg(char * buf,uintptr_t caller)54*810390e3Srobert __attribute__((noinline)) static void decorate_msg(char *buf,
55*810390e3Srobert uintptr_t caller) {
56*810390e3Srobert // print the address by nibbles
57*810390e3Srobert for (unsigned shift = sizeof(uintptr_t) * 8; shift;) {
58*810390e3Srobert shift -= 4;
59*810390e3Srobert unsigned nibble = (caller >> shift) & 0xf;
60*810390e3Srobert *(buf++) = nibble < 10 ? nibble + '0' : nibble - 10 + 'a';
61*810390e3Srobert }
62*810390e3Srobert // finish the message
63*810390e3Srobert buf[0] = '\n';
64*810390e3Srobert buf[1] = '\0';
65*810390e3Srobert }
66*810390e3Srobert
673cab2bb3Spatrick #if defined(__ANDROID__)
683cab2bb3Spatrick extern "C" __attribute__((weak)) void android_set_abort_message(const char *);
abort_with_message(const char * msg)693cab2bb3Spatrick static void abort_with_message(const char *msg) {
703cab2bb3Spatrick if (&android_set_abort_message) android_set_abort_message(msg);
713cab2bb3Spatrick abort();
723cab2bb3Spatrick }
733cab2bb3Spatrick #else
abort_with_message(const char *)743cab2bb3Spatrick static void abort_with_message(const char *) { abort(); }
753cab2bb3Spatrick #endif
763cab2bb3Spatrick
773cab2bb3Spatrick #if SANITIZER_DEBUG
783cab2bb3Spatrick namespace __sanitizer {
793cab2bb3Spatrick // The DCHECK macro needs this symbol to be defined.
CheckFailed(const char * file,int,const char * cond,u64,u64)803cab2bb3Spatrick void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) {
813cab2bb3Spatrick message("Sanitizer CHECK failed: ");
823cab2bb3Spatrick message(file);
833cab2bb3Spatrick message(":?? : "); // FIXME: Show line number.
843cab2bb3Spatrick message(cond);
853cab2bb3Spatrick abort();
863cab2bb3Spatrick }
873cab2bb3Spatrick } // namespace __sanitizer
883cab2bb3Spatrick #endif
893cab2bb3Spatrick
903cab2bb3Spatrick #define INTERFACE extern "C" __attribute__((visibility("default")))
913cab2bb3Spatrick
92*810390e3Srobert // How many chars we need to reserve to print an address.
93*810390e3Srobert constexpr unsigned kAddrBuf = SANITIZER_WORDSIZE / 4;
94*810390e3Srobert #define MSG_TMPL(msg) "ubsan: " msg " by 0x"
95*810390e3Srobert #define MSG_TMPL_END(buf, msg) (buf + sizeof(MSG_TMPL(msg)) - 1)
96*810390e3Srobert // Reserve an additional byte for '\n'.
97*810390e3Srobert #define MSG_BUF_LEN(msg) (sizeof(MSG_TMPL(msg)) + kAddrBuf + 1)
98*810390e3Srobert
993cab2bb3Spatrick #define HANDLER_RECOVER(name, msg) \
1003cab2bb3Spatrick INTERFACE void __ubsan_handle_##name##_minimal() { \
101*810390e3Srobert uintptr_t caller = GET_CALLER_PC(); \
102*810390e3Srobert if (!report_this_error(caller)) return; \
103*810390e3Srobert char msg_buf[MSG_BUF_LEN(msg)] = MSG_TMPL(msg); \
104*810390e3Srobert decorate_msg(MSG_TMPL_END(msg_buf, msg), caller); \
105*810390e3Srobert message(msg_buf); \
1063cab2bb3Spatrick }
1073cab2bb3Spatrick
1083cab2bb3Spatrick #define HANDLER_NORECOVER(name, msg) \
1093cab2bb3Spatrick INTERFACE void __ubsan_handle_##name##_minimal_abort() { \
110*810390e3Srobert char msg_buf[MSG_BUF_LEN(msg)] = MSG_TMPL(msg); \
111*810390e3Srobert decorate_msg(MSG_TMPL_END(msg_buf, msg), GET_CALLER_PC()); \
112*810390e3Srobert message(msg_buf); \
113*810390e3Srobert abort_with_message(msg_buf); \
1143cab2bb3Spatrick }
1153cab2bb3Spatrick
1163cab2bb3Spatrick #define HANDLER(name, msg) \
1173cab2bb3Spatrick HANDLER_RECOVER(name, msg) \
1183cab2bb3Spatrick HANDLER_NORECOVER(name, msg)
1193cab2bb3Spatrick
1203cab2bb3Spatrick HANDLER(type_mismatch, "type-mismatch")
1213cab2bb3Spatrick HANDLER(alignment_assumption, "alignment-assumption")
1223cab2bb3Spatrick HANDLER(add_overflow, "add-overflow")
1233cab2bb3Spatrick HANDLER(sub_overflow, "sub-overflow")
1243cab2bb3Spatrick HANDLER(mul_overflow, "mul-overflow")
1253cab2bb3Spatrick HANDLER(negate_overflow, "negate-overflow")
1263cab2bb3Spatrick HANDLER(divrem_overflow, "divrem-overflow")
1273cab2bb3Spatrick HANDLER(shift_out_of_bounds, "shift-out-of-bounds")
1283cab2bb3Spatrick HANDLER(out_of_bounds, "out-of-bounds")
1293cab2bb3Spatrick HANDLER_RECOVER(builtin_unreachable, "builtin-unreachable")
1303cab2bb3Spatrick HANDLER_RECOVER(missing_return, "missing-return")
1313cab2bb3Spatrick HANDLER(vla_bound_not_positive, "vla-bound-not-positive")
1323cab2bb3Spatrick HANDLER(float_cast_overflow, "float-cast-overflow")
1333cab2bb3Spatrick HANDLER(load_invalid_value, "load-invalid-value")
1343cab2bb3Spatrick HANDLER(invalid_builtin, "invalid-builtin")
1351f9cb04fSpatrick HANDLER(invalid_objc_cast, "invalid-objc-cast")
1363cab2bb3Spatrick HANDLER(function_type_mismatch, "function-type-mismatch")
1373cab2bb3Spatrick HANDLER(implicit_conversion, "implicit-conversion")
1383cab2bb3Spatrick HANDLER(nonnull_arg, "nonnull-arg")
1393cab2bb3Spatrick HANDLER(nonnull_return, "nonnull-return")
1403cab2bb3Spatrick HANDLER(nullability_arg, "nullability-arg")
1413cab2bb3Spatrick HANDLER(nullability_return, "nullability-return")
1423cab2bb3Spatrick HANDLER(pointer_overflow, "pointer-overflow")
1433cab2bb3Spatrick HANDLER(cfi_check_fail, "cfi-check-fail")
144