diff options
Diffstat (limited to 'lib/ubsan_minimal/ubsan_minimal_handlers.cc')
-rw-r--r-- | lib/ubsan_minimal/ubsan_minimal_handlers.cc | 91 |
1 files changed, 91 insertions, 0 deletions
diff --git a/lib/ubsan_minimal/ubsan_minimal_handlers.cc b/lib/ubsan_minimal/ubsan_minimal_handlers.cc new file mode 100644 index 000000000..3ab2811c6 --- /dev/null +++ b/lib/ubsan_minimal/ubsan_minimal_handlers.cc @@ -0,0 +1,91 @@ +#include <atomic> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +static void message(const char *msg) { + write(2, msg, strlen(msg)); +} + +static const int kMaxCallerPcs = 20; +static std::atomic<void *> caller_pcs[kMaxCallerPcs]; +// Number of elements in caller_pcs. A special value of kMaxCallerPcs + 1 means +// that "too many errors" has already been reported. +static std::atomic<int> caller_pcs_sz; + +__attribute__((noinline)) +static bool report_this_error(void *caller) { + if (caller == nullptr) return false; + while (true) { + int sz = caller_pcs_sz.load(std::memory_order_relaxed); + if (sz > kMaxCallerPcs) return false; // early exit + // when sz==kMaxCallerPcs print "too many errors", but only when cmpxchg + // succeeds in order to not print it multiple times. + if (sz > 0 && sz < kMaxCallerPcs) { + void *p; + for (int i = 0; i < sz; ++i) { + p = caller_pcs[i].load(std::memory_order_relaxed); + if (p == nullptr) break; // Concurrent update. + if (p == caller) return false; + } + if (p == nullptr) continue; // FIXME: yield? + } + + if (!caller_pcs_sz.compare_exchange_strong(sz, sz + 1)) + continue; // Concurrent update! Try again from the start. + + if (sz == kMaxCallerPcs) { + message("ubsan: too many errors\n"); + return false; + } + caller_pcs[sz].store(caller, std::memory_order_relaxed); + return true; + } +} + +#if defined(__ANDROID__) +extern "C" void android_set_abort_message(const char *msg); +static void abort_with_message(const char *msg) { +#if __ANDROID_API__ >= 21 + android_set_abort_message(msg); +#endif + abort(); +} +#else +static void abort_with_message(const char *) { abort(); } +#endif + +#define INTERFACE extern "C" __attribute__((visibility("default"))) + +// FIXME: add caller pc to the error message (possibly as "ubsan: error-type +// @1234ABCD"). +#define HANDLER(name, msg) \ + INTERFACE void __ubsan_handle_##name##_minimal() { \ + if (!report_this_error(__builtin_return_address(0))) return; \ + message("ubsan: " msg "\n"); \ + } \ + \ + INTERFACE void __ubsan_handle_##name##_minimal_abort() { \ + message("ubsan: " msg "\n"); \ + abort_with_message("ubsan: " msg); \ + } + +HANDLER(type_mismatch, "type-mismatch") +HANDLER(add_overflow, "add-overflow") +HANDLER(sub_overflow, "sub-overflow") +HANDLER(mul_overflow, "mul-overflow") +HANDLER(negate_overflow, "negate-overflow") +HANDLER(divrem_overflow, "divrem-overflow") +HANDLER(shift_out_of_bounds, "shift-out-of-bounds") +HANDLER(out_of_bounds, "out-of-bounds") +HANDLER(builtin_unreachable, "builtin-unreachable") +HANDLER(missing_return, "missing-return") +HANDLER(vla_bound_not_positive, "vla-bound-not-positive") +HANDLER(float_cast_overflow, "float-cast-overflow") +HANDLER(load_invalid_value, "load-invalid-value") +HANDLER(invalid_builtin, "invalid-builtin") +HANDLER(function_type_mismatch, "function-type-mismatch") +HANDLER(nonnull_arg, "nonnull-arg") +HANDLER(nullability_arg, "nullability-arg") +HANDLER(pointer_overflow, "pointer-overflow") +HANDLER(cfi_check_fail, "cfi-check-fail") |