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