Skip to content

Commit e5e0f23

Browse files
authored
[nfc][ubsan-minimal] Refactor error reporting to use a single function (#119920)
This refactoring will allow to make this function weak later on so that it could be overloaded by a client. See #119242.
1 parent c4a78b6 commit e5e0f23

File tree

1 file changed

+55
-44
lines changed

1 file changed

+55
-44
lines changed

compiler-rt/lib/ubsan_minimal/ubsan_minimal_handlers.cpp

Lines changed: 55 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,50 @@ static __sanitizer::atomic_uintptr_t caller_pcs[kMaxCallerPcs];
2020
// that "too many errors" has already been reported.
2121
static __sanitizer::atomic_uint32_t caller_pcs_sz;
2222

23-
__attribute__((noinline)) static bool report_this_error(uintptr_t caller) {
23+
static char *append_str(const char *s, char *buf, const char *end) {
24+
for (const char *p = s; (buf < end) && (*p != '\0'); ++p, ++buf)
25+
*buf = *p;
26+
return buf;
27+
}
28+
29+
static char *append_hex(uintptr_t d, char *buf, const char *end) {
30+
// Print the address by nibbles.
31+
for (unsigned shift = sizeof(uintptr_t) * 8; shift && buf < end;) {
32+
shift -= 4;
33+
unsigned nibble = (d >> shift) & 0xf;
34+
*(buf++) = nibble < 10 ? nibble + '0' : nibble - 10 + 'a';
35+
}
36+
return buf;
37+
}
38+
39+
static void format_msg(const char *kind, uintptr_t caller, char *buf,
40+
const char *end) {
41+
buf = append_str("ubsan: ", buf, end);
42+
buf = append_str(kind, buf, end);
43+
buf = append_str(" by 0x", buf, end);
44+
buf = append_hex(caller, buf, end);
45+
buf = append_str("\n", buf, end);
46+
if (buf == end)
47+
--buf; // Make sure we don't cause a buffer overflow.
48+
*buf = '\0';
49+
}
50+
51+
static void report_error(const char *kind, uintptr_t caller) {
2452
if (caller == 0)
25-
return false;
53+
return;
2654
while (true) {
2755
unsigned sz = __sanitizer::atomic_load_relaxed(&caller_pcs_sz);
28-
if (sz > kMaxCallerPcs) return false; // early exit
56+
if (sz > kMaxCallerPcs)
57+
return; // early exit
2958
// when sz==kMaxCallerPcs print "too many errors", but only when cmpxchg
3059
// succeeds in order to not print it multiple times.
3160
if (sz > 0 && sz < kMaxCallerPcs) {
3261
uintptr_t p;
3362
for (unsigned i = 0; i < sz; ++i) {
3463
p = __sanitizer::atomic_load_relaxed(&caller_pcs[i]);
3564
if (p == 0) break; // Concurrent update.
36-
if (p == caller) return false;
65+
if (p == caller)
66+
return;
3767
}
3868
if (p == 0) continue; // FIXME: yield?
3969
}
@@ -44,34 +74,27 @@ __attribute__((noinline)) static bool report_this_error(uintptr_t caller) {
4474

4575
if (sz == kMaxCallerPcs) {
4676
message("ubsan: too many errors\n");
47-
return false;
77+
return;
4878
}
4979
__sanitizer::atomic_store_relaxed(&caller_pcs[sz], caller);
50-
return true;
51-
}
52-
}
5380

54-
__attribute__((noinline)) static void decorate_msg(char *buf,
55-
uintptr_t caller) {
56-
// print the address by nibbles
57-
for (unsigned shift = sizeof(uintptr_t) * 8; shift;) {
58-
shift -= 4;
59-
unsigned nibble = (caller >> shift) & 0xf;
60-
*(buf++) = nibble < 10 ? nibble + '0' : nibble - 10 + 'a';
81+
char msg_buf[128];
82+
format_msg(kind, caller, msg_buf, msg_buf + sizeof(msg_buf));
83+
message(msg_buf);
6184
}
62-
// finish the message
63-
buf[0] = '\n';
64-
buf[1] = '\0';
6585
}
6686

6787
#if defined(__ANDROID__)
6888
extern "C" __attribute__((weak)) void android_set_abort_message(const char *);
69-
static void abort_with_message(const char *msg) {
70-
if (&android_set_abort_message) android_set_abort_message(msg);
89+
static void abort_with_message(const char *kind, uintptr_t caller) {
90+
char msg_buf[128];
91+
format_msg(kind, caller, msg_buf, msg_buf + sizeof(msg_buf));
92+
if (&android_set_abort_message)
93+
android_set_abort_message(msg_buf);
7194
abort();
7295
}
7396
#else
74-
static void abort_with_message(const char *) { abort(); }
97+
static void abort_with_message(const char *kind, uintptr_t caller) { abort(); }
7598
#endif
7699

77100
#if SANITIZER_DEBUG
@@ -89,33 +112,21 @@ void NORETURN CheckFailed(const char *file, int, const char *cond, u64, u64) {
89112

90113
#define INTERFACE extern "C" __attribute__((visibility("default")))
91114

92-
// How many chars we need to reserve to print an address.
93-
constexpr unsigned kAddrBuf = SANITIZER_WORDSIZE / 4;
94-
#define MSG_TMPL(msg) "ubsan: " msg " by 0x"
95-
#define MSG_TMPL_END(buf, msg) (buf + sizeof(MSG_TMPL(msg)) - 1)
96-
// Reserve an additional byte for '\n'.
97-
#define MSG_BUF_LEN(msg) (sizeof(MSG_TMPL(msg)) + kAddrBuf + 1)
98-
99-
#define HANDLER_RECOVER(name, msg) \
100-
INTERFACE void __ubsan_handle_##name##_minimal() { \
101-
uintptr_t caller = GET_CALLER_PC(); \
102-
if (!report_this_error(caller)) return; \
103-
char msg_buf[MSG_BUF_LEN(msg)] = MSG_TMPL(msg); \
104-
decorate_msg(MSG_TMPL_END(msg_buf, msg), caller); \
105-
message(msg_buf); \
115+
#define HANDLER_RECOVER(name, kind) \
116+
INTERFACE void __ubsan_handle_##name##_minimal() { \
117+
report_error(kind, GET_CALLER_PC()); \
106118
}
107119

108-
#define HANDLER_NORECOVER(name, msg) \
109-
INTERFACE void __ubsan_handle_##name##_minimal_abort() { \
110-
char msg_buf[MSG_BUF_LEN(msg)] = MSG_TMPL(msg); \
111-
decorate_msg(MSG_TMPL_END(msg_buf, msg), GET_CALLER_PC()); \
112-
message(msg_buf); \
113-
abort_with_message(msg_buf); \
120+
#define HANDLER_NORECOVER(name, kind) \
121+
INTERFACE void __ubsan_handle_##name##_minimal_abort() { \
122+
uintptr_t caller = GET_CALLER_PC(); \
123+
report_error(kind, caller); \
124+
abort_with_message(kind, caller); \
114125
}
115126

116-
#define HANDLER(name, msg) \
117-
HANDLER_RECOVER(name, msg) \
118-
HANDLER_NORECOVER(name, msg)
127+
#define HANDLER(name, kind) \
128+
HANDLER_RECOVER(name, kind) \
129+
HANDLER_NORECOVER(name, kind)
119130

120131
HANDLER(type_mismatch, "type-mismatch")
121132
HANDLER(alignment_assumption, "alignment-assumption")

0 commit comments

Comments
 (0)