|
@@ -21,8 +21,32 @@ Atomic<bool> AK::UBSanitizer::g_ubsan_is_deadly;
|
|
abort(); \
|
|
abort(); \
|
|
} while (0)
|
|
} while (0)
|
|
|
|
|
|
|
|
+// FIXME: Dump backtrace of this process (with symbols? without symbols?) in case the user wants non-deadly UBSAN
|
|
|
|
+// Should probably go through the kernel for SC_dump_backtrace, then access the loader's symbol tables
|
|
|
|
+// rather than going through the symbolizer service?
|
|
|
|
+#define ABORT_IF_DEADLY() \
|
|
|
|
+ do { \
|
|
|
|
+ if (g_ubsan_is_deadly.load(AK::MemoryOrder::memory_order_acquire)) { \
|
|
|
|
+ WARNLN_AND_DBGLN("UBSAN: UB is configured to be deadly"); \
|
|
|
|
+ abort(); \
|
|
|
|
+ } \
|
|
|
|
+ } while (0)
|
|
|
|
+
|
|
extern "C" {
|
|
extern "C" {
|
|
|
|
|
|
|
|
+[[gnu::constructor]] static void init_ubsan_options()
|
|
|
|
+{
|
|
|
|
+ auto const* options_ptr = getenv("UBSAN_OPTIONS");
|
|
|
|
+ auto options = options_ptr != NULL ? StringView { options_ptr, strlen(options_ptr) } : StringView {};
|
|
|
|
+ // FIXME: Parse more options and complain about invalid options
|
|
|
|
+ if (!options.is_null()) {
|
|
|
|
+ if (options.contains("halt_on_error=1"sv))
|
|
|
|
+ g_ubsan_is_deadly.store(true, AK::MemoryOrder::memory_order_relaxed);
|
|
|
|
+ else if (options.contains("halt_on_error=0"sv))
|
|
|
|
+ g_ubsan_is_deadly.store(false, AK::MemoryOrder::memory_order_relaxed);
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
static void print_location(SourceLocation const& location)
|
|
static void print_location(SourceLocation const& location)
|
|
{
|
|
{
|
|
if (!location.filename()) {
|
|
if (!location.filename()) {
|
|
@@ -30,35 +54,13 @@ static void print_location(SourceLocation const& location)
|
|
} else {
|
|
} else {
|
|
WARNLN_AND_DBGLN("UBSAN: at {}, line {}, column: {}", location.filename(), location.line(), location.column());
|
|
WARNLN_AND_DBGLN("UBSAN: at {}, line {}, column: {}", location.filename(), location.line(), location.column());
|
|
}
|
|
}
|
|
- // FIXME: Dump backtrace of this process (with symbols? without symbols?) in case the user wants non-deadly UBSAN
|
|
|
|
- // Should probably go through the kernel for SC_dump_backtrace, then access the loader's symbol tables rather than
|
|
|
|
- // going through the symbolizer service?
|
|
|
|
-
|
|
|
|
- static bool checked_env_for_deadly = false;
|
|
|
|
- if (!checked_env_for_deadly) {
|
|
|
|
- checked_env_for_deadly = true;
|
|
|
|
- auto const* options_ptr = getenv("UBSAN_OPTIONS");
|
|
|
|
- auto options = options_ptr != NULL ? StringView { options_ptr, strlen(options_ptr) } : StringView {};
|
|
|
|
- // FIXME: Parse more options and complain about invalid options
|
|
|
|
- if (!options.is_null()) {
|
|
|
|
- if (options.contains("halt_on_error=1"sv))
|
|
|
|
- g_ubsan_is_deadly = true;
|
|
|
|
- else if (options.contains("halt_on_error=0"sv))
|
|
|
|
- g_ubsan_is_deadly = false;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- if (g_ubsan_is_deadly) {
|
|
|
|
- WARNLN_AND_DBGLN("UB is configured to be deadly");
|
|
|
|
- VERIFY_NOT_REACHED();
|
|
|
|
- }
|
|
|
|
}
|
|
}
|
|
|
|
|
|
// Calls to these functions are automatically inserted by the compiler,
|
|
// Calls to these functions are automatically inserted by the compiler,
|
|
// so there is no point in declaring them in a header.
|
|
// so there is no point in declaring them in a header.
|
|
#pragma GCC diagnostic ignored "-Wmissing-declarations"
|
|
#pragma GCC diagnostic ignored "-Wmissing-declarations"
|
|
|
|
|
|
-void __ubsan_handle_load_invalid_value(InvalidValueData&, ValueHandle) __attribute__((used));
|
|
|
|
-void __ubsan_handle_load_invalid_value(InvalidValueData& data, ValueHandle)
|
|
|
|
|
|
+static void handle_load_invalid_value(InvalidValueData& data, ValueHandle)
|
|
{
|
|
{
|
|
auto location = data.location.permanently_clear();
|
|
auto location = data.location.permanently_clear();
|
|
if (!location.needs_logging())
|
|
if (!location.needs_logging())
|
|
@@ -66,9 +68,18 @@ void __ubsan_handle_load_invalid_value(InvalidValueData& data, ValueHandle)
|
|
WARNLN_AND_DBGLN("UBSAN: load-invalid-value: {} ({}-bit)", data.type.name(), data.type.bit_width());
|
|
WARNLN_AND_DBGLN("UBSAN: load-invalid-value: {} ({}-bit)", data.type.name(), data.type.bit_width());
|
|
print_location(location);
|
|
print_location(location);
|
|
}
|
|
}
|
|
|
|
+[[gnu::used]] void __ubsan_handle_load_invalid_value(InvalidValueData& data, ValueHandle handle)
|
|
|
|
+{
|
|
|
|
+ handle_load_invalid_value(data, handle);
|
|
|
|
+ ABORT_IF_DEADLY();
|
|
|
|
+}
|
|
|
|
+[[gnu::used, noreturn]] void __ubsan_handle_load_invalid_value_abort(InvalidValueData& data, ValueHandle handle)
|
|
|
|
+{
|
|
|
|
+ handle_load_invalid_value(data, handle);
|
|
|
|
+ ABORT_ALWAYS();
|
|
|
|
+}
|
|
|
|
|
|
-void __ubsan_handle_nonnull_arg(NonnullArgData&) __attribute__((used));
|
|
|
|
-void __ubsan_handle_nonnull_arg(NonnullArgData& data)
|
|
|
|
|
|
+static void handle_nonnull_arg(NonnullArgData& data)
|
|
{
|
|
{
|
|
auto location = data.location.permanently_clear();
|
|
auto location = data.location.permanently_clear();
|
|
if (!location.needs_logging())
|
|
if (!location.needs_logging())
|
|
@@ -77,8 +88,18 @@ void __ubsan_handle_nonnull_arg(NonnullArgData& data)
|
|
print_location(location);
|
|
print_location(location);
|
|
}
|
|
}
|
|
|
|
|
|
-void __ubsan_handle_nullability_arg(NonnullArgData&) __attribute__((used));
|
|
|
|
-void __ubsan_handle_nullability_arg(NonnullArgData& data)
|
|
|
|
|
|
+[[gnu::used]] void __ubsan_handle_nonnull_arg(NonnullArgData& data)
|
|
|
|
+{
|
|
|
|
+ handle_nonnull_arg(data);
|
|
|
|
+ ABORT_IF_DEADLY();
|
|
|
|
+}
|
|
|
|
+[[gnu::used, noreturn]] void __ubsan_handle_nonnull_arg_abort(NonnullArgData& data)
|
|
|
|
+{
|
|
|
|
+ handle_nonnull_arg(data);
|
|
|
|
+ ABORT_ALWAYS();
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+static void handle_nullability_arg(NonnullArgData& data)
|
|
{
|
|
{
|
|
auto location = data.location.permanently_clear();
|
|
auto location = data.location.permanently_clear();
|
|
if (!location.needs_logging())
|
|
if (!location.needs_logging())
|
|
@@ -86,9 +107,18 @@ void __ubsan_handle_nullability_arg(NonnullArgData& data)
|
|
WARNLN_AND_DBGLN("UBSAN: null pointer passed as argument {}, which is declared to never be null", data.argument_index);
|
|
WARNLN_AND_DBGLN("UBSAN: null pointer passed as argument {}, which is declared to never be null", data.argument_index);
|
|
print_location(location);
|
|
print_location(location);
|
|
}
|
|
}
|
|
|
|
+[[gnu::used]] void __ubsan_handle_nullability_arg(NonnullArgData& data)
|
|
|
|
+{
|
|
|
|
+ handle_nullability_arg(data);
|
|
|
|
+ ABORT_IF_DEADLY();
|
|
|
|
+}
|
|
|
|
+[[gnu::used, noreturn]] void __ubsan_handle_nullability_arg_abort(NonnullArgData& data)
|
|
|
|
+{
|
|
|
|
+ handle_nullability_arg(data);
|
|
|
|
+ ABORT_ALWAYS();
|
|
|
|
+}
|
|
|
|
|
|
-void __ubsan_handle_nonnull_return_v1(NonnullReturnData const&, SourceLocation&) __attribute__((used));
|
|
|
|
-void __ubsan_handle_nonnull_return_v1(NonnullReturnData const&, SourceLocation& location)
|
|
|
|
|
|
+static void handle_nonnull_return_v1(NonnullReturnData const&, SourceLocation& location)
|
|
{
|
|
{
|
|
auto loc = location.permanently_clear();
|
|
auto loc = location.permanently_clear();
|
|
if (!loc.needs_logging())
|
|
if (!loc.needs_logging())
|
|
@@ -96,9 +126,18 @@ void __ubsan_handle_nonnull_return_v1(NonnullReturnData const&, SourceLocation&
|
|
WARNLN_AND_DBGLN("UBSAN: null pointer return from function declared to never return null");
|
|
WARNLN_AND_DBGLN("UBSAN: null pointer return from function declared to never return null");
|
|
print_location(loc);
|
|
print_location(loc);
|
|
}
|
|
}
|
|
|
|
+[[gnu::used]] void __ubsan_handle_nonnull_return_v1(NonnullReturnData const& data, SourceLocation& location)
|
|
|
|
+{
|
|
|
|
+ handle_nonnull_return_v1(data, location);
|
|
|
|
+ ABORT_IF_DEADLY();
|
|
|
|
+}
|
|
|
|
+[[gnu::used, noreturn]] void __ubsan_handle_nonnull_return_v1_abort(NonnullReturnData const& data, SourceLocation& location)
|
|
|
|
+{
|
|
|
|
+ handle_nonnull_return_v1(data, location);
|
|
|
|
+ ABORT_ALWAYS();
|
|
|
|
+}
|
|
|
|
|
|
-void __ubsan_handle_nullability_return_v1(NonnullReturnData const& data, SourceLocation& location) __attribute__((used));
|
|
|
|
-void __ubsan_handle_nullability_return_v1(NonnullReturnData const&, SourceLocation& location)
|
|
|
|
|
|
+static void handle_nullability_return_v1(NonnullReturnData const&, SourceLocation& location)
|
|
{
|
|
{
|
|
auto loc = location.permanently_clear();
|
|
auto loc = location.permanently_clear();
|
|
if (!loc.needs_logging())
|
|
if (!loc.needs_logging())
|
|
@@ -106,9 +145,18 @@ void __ubsan_handle_nullability_return_v1(NonnullReturnData const&, SourceLocati
|
|
WARNLN_AND_DBGLN("UBSAN: null pointer return from function declared to never return null");
|
|
WARNLN_AND_DBGLN("UBSAN: null pointer return from function declared to never return null");
|
|
print_location(loc);
|
|
print_location(loc);
|
|
}
|
|
}
|
|
|
|
+[[gnu::used]] void __ubsan_handle_nullability_return_v1(NonnullReturnData const& data, SourceLocation& location)
|
|
|
|
+{
|
|
|
|
+ handle_nullability_return_v1(data, location);
|
|
|
|
+ ABORT_IF_DEADLY();
|
|
|
|
+}
|
|
|
|
+[[gnu::used, noreturn]] void __ubsan_handle_nullability_return_v1_abort(NonnullReturnData const& data, SourceLocation& location)
|
|
|
|
+{
|
|
|
|
+ handle_nullability_return_v1(data, location);
|
|
|
|
+ ABORT_ALWAYS();
|
|
|
|
+}
|
|
|
|
|
|
-void __ubsan_handle_vla_bound_not_positive(VLABoundData&, ValueHandle) __attribute__((used));
|
|
|
|
-void __ubsan_handle_vla_bound_not_positive(VLABoundData& data, ValueHandle)
|
|
|
|
|
|
+static void handle_vla_bound_not_positive(VLABoundData& data, ValueHandle)
|
|
{
|
|
{
|
|
auto location = data.location.permanently_clear();
|
|
auto location = data.location.permanently_clear();
|
|
if (!location.needs_logging())
|
|
if (!location.needs_logging())
|
|
@@ -116,9 +164,18 @@ void __ubsan_handle_vla_bound_not_positive(VLABoundData& data, ValueHandle)
|
|
WARNLN_AND_DBGLN("UBSAN: VLA bound not positive {} ({}-bit)", data.type.name(), data.type.bit_width());
|
|
WARNLN_AND_DBGLN("UBSAN: VLA bound not positive {} ({}-bit)", data.type.name(), data.type.bit_width());
|
|
print_location(location);
|
|
print_location(location);
|
|
}
|
|
}
|
|
|
|
+[[gnu::used]] void __ubsan_handle_vla_bound_not_positive(VLABoundData& data, ValueHandle handle)
|
|
|
|
+{
|
|
|
|
+ handle_vla_bound_not_positive(data, handle);
|
|
|
|
+ ABORT_IF_DEADLY();
|
|
|
|
+}
|
|
|
|
+[[gnu::used, noreturn]] void __ubsan_handle_vla_bound_not_positive_abort(VLABoundData& data, ValueHandle handle)
|
|
|
|
+{
|
|
|
|
+ handle_vla_bound_not_positive(data, handle);
|
|
|
|
+ ABORT_ALWAYS();
|
|
|
|
+}
|
|
|
|
|
|
-void __ubsan_handle_add_overflow(OverflowData&, ValueHandle lhs, ValueHandle rhs) __attribute__((used));
|
|
|
|
-void __ubsan_handle_add_overflow(OverflowData& data, ValueHandle, ValueHandle)
|
|
|
|
|
|
+static void handle_add_overflow(OverflowData& data, ValueHandle, ValueHandle)
|
|
{
|
|
{
|
|
auto location = data.location.permanently_clear();
|
|
auto location = data.location.permanently_clear();
|
|
if (!location.needs_logging())
|
|
if (!location.needs_logging())
|
|
@@ -126,9 +183,18 @@ void __ubsan_handle_add_overflow(OverflowData& data, ValueHandle, ValueHandle)
|
|
WARNLN_AND_DBGLN("UBSAN: addition overflow, {} ({}-bit)", data.type.name(), data.type.bit_width());
|
|
WARNLN_AND_DBGLN("UBSAN: addition overflow, {} ({}-bit)", data.type.name(), data.type.bit_width());
|
|
print_location(location);
|
|
print_location(location);
|
|
}
|
|
}
|
|
|
|
+[[gnu::used]] void __ubsan_handle_add_overflow(OverflowData& data, ValueHandle lhs, ValueHandle rhs)
|
|
|
|
+{
|
|
|
|
+ handle_add_overflow(data, lhs, rhs);
|
|
|
|
+ ABORT_IF_DEADLY();
|
|
|
|
+}
|
|
|
|
+[[gnu::used, noreturn]] void __ubsan_handle_add_overflow_abort(OverflowData& data, ValueHandle lhs, ValueHandle rhs)
|
|
|
|
+{
|
|
|
|
+ handle_add_overflow(data, lhs, rhs);
|
|
|
|
+ ABORT_ALWAYS();
|
|
|
|
+}
|
|
|
|
|
|
-void __ubsan_handle_sub_overflow(OverflowData&, ValueHandle lhs, ValueHandle rhs) __attribute__((used));
|
|
|
|
-void __ubsan_handle_sub_overflow(OverflowData& data, ValueHandle, ValueHandle)
|
|
|
|
|
|
+static void handle_sub_overflow(OverflowData& data, ValueHandle, ValueHandle)
|
|
{
|
|
{
|
|
auto location = data.location.permanently_clear();
|
|
auto location = data.location.permanently_clear();
|
|
if (!location.needs_logging())
|
|
if (!location.needs_logging())
|
|
@@ -136,9 +202,18 @@ void __ubsan_handle_sub_overflow(OverflowData& data, ValueHandle, ValueHandle)
|
|
WARNLN_AND_DBGLN("UBSAN: subtraction overflow, {} ({}-bit)", data.type.name(), data.type.bit_width());
|
|
WARNLN_AND_DBGLN("UBSAN: subtraction overflow, {} ({}-bit)", data.type.name(), data.type.bit_width());
|
|
print_location(location);
|
|
print_location(location);
|
|
}
|
|
}
|
|
|
|
+[[gnu::used]] void __ubsan_handle_sub_overflow(OverflowData& data, ValueHandle lhs, ValueHandle rhs)
|
|
|
|
+{
|
|
|
|
+ handle_sub_overflow(data, lhs, rhs);
|
|
|
|
+ ABORT_IF_DEADLY();
|
|
|
|
+}
|
|
|
|
+[[gnu::used, noreturn]] void __ubsan_handle_sub_overflow_abort(OverflowData& data, ValueHandle lhs, ValueHandle rhs)
|
|
|
|
+{
|
|
|
|
+ handle_sub_overflow(data, lhs, rhs);
|
|
|
|
+ ABORT_ALWAYS();
|
|
|
|
+}
|
|
|
|
|
|
-void __ubsan_handle_negate_overflow(OverflowData&, ValueHandle) __attribute__((used));
|
|
|
|
-void __ubsan_handle_negate_overflow(OverflowData& data, ValueHandle)
|
|
|
|
|
|
+static void handle_negate_overflow(OverflowData& data, ValueHandle)
|
|
{
|
|
{
|
|
auto location = data.location.permanently_clear();
|
|
auto location = data.location.permanently_clear();
|
|
if (!location.needs_logging())
|
|
if (!location.needs_logging())
|
|
@@ -146,9 +221,18 @@ void __ubsan_handle_negate_overflow(OverflowData& data, ValueHandle)
|
|
WARNLN_AND_DBGLN("UBSAN: negation overflow, {} ({}-bit)", data.type.name(), data.type.bit_width());
|
|
WARNLN_AND_DBGLN("UBSAN: negation overflow, {} ({}-bit)", data.type.name(), data.type.bit_width());
|
|
print_location(location);
|
|
print_location(location);
|
|
}
|
|
}
|
|
|
|
+[[gnu::used]] void __ubsan_handle_negate_overflow(OverflowData& data, ValueHandle value)
|
|
|
|
+{
|
|
|
|
+ handle_negate_overflow(data, value);
|
|
|
|
+ ABORT_IF_DEADLY();
|
|
|
|
+}
|
|
|
|
+[[gnu::used, noreturn]] void __ubsan_handle_negate_overflow_abort(OverflowData& data, ValueHandle value)
|
|
|
|
+{
|
|
|
|
+ handle_negate_overflow(data, value);
|
|
|
|
+ ABORT_ALWAYS();
|
|
|
|
+}
|
|
|
|
|
|
-void __ubsan_handle_mul_overflow(OverflowData&, ValueHandle lhs, ValueHandle rhs) __attribute__((used));
|
|
|
|
-void __ubsan_handle_mul_overflow(OverflowData& data, ValueHandle, ValueHandle)
|
|
|
|
|
|
+static void handle_mul_overflow(OverflowData& data, ValueHandle, ValueHandle)
|
|
{
|
|
{
|
|
auto location = data.location.permanently_clear();
|
|
auto location = data.location.permanently_clear();
|
|
if (!location.needs_logging())
|
|
if (!location.needs_logging())
|
|
@@ -156,9 +240,18 @@ void __ubsan_handle_mul_overflow(OverflowData& data, ValueHandle, ValueHandle)
|
|
WARNLN_AND_DBGLN("UBSAN: multiplication overflow, {} ({}-bit)", data.type.name(), data.type.bit_width());
|
|
WARNLN_AND_DBGLN("UBSAN: multiplication overflow, {} ({}-bit)", data.type.name(), data.type.bit_width());
|
|
print_location(location);
|
|
print_location(location);
|
|
}
|
|
}
|
|
|
|
+[[gnu::used]] void __ubsan_handle_mul_overflow(OverflowData& data, ValueHandle lhs, ValueHandle rhs)
|
|
|
|
+{
|
|
|
|
+ handle_mul_overflow(data, lhs, rhs);
|
|
|
|
+ ABORT_IF_DEADLY();
|
|
|
|
+}
|
|
|
|
+[[gnu::used, noreturn]] void __ubsan_handle_mul_overflow_abort(OverflowData& data, ValueHandle lhs, ValueHandle rhs)
|
|
|
|
+{
|
|
|
|
+ handle_mul_overflow(data, lhs, rhs);
|
|
|
|
+ ABORT_ALWAYS();
|
|
|
|
+}
|
|
|
|
|
|
-void __ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData&, ValueHandle lhs, ValueHandle rhs) __attribute__((used));
|
|
|
|
-void __ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData& data, ValueHandle, ValueHandle)
|
|
|
|
|
|
+static void handle_shift_out_of_bounds(ShiftOutOfBoundsData& data, ValueHandle, ValueHandle)
|
|
{
|
|
{
|
|
auto location = data.location.permanently_clear();
|
|
auto location = data.location.permanently_clear();
|
|
if (!location.needs_logging())
|
|
if (!location.needs_logging())
|
|
@@ -166,9 +259,18 @@ void __ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData& data, ValueHandle,
|
|
WARNLN_AND_DBGLN("UBSAN: shift out of bounds, {} ({}-bit) shifted by {} ({}-bit)", data.lhs_type.name(), data.lhs_type.bit_width(), data.rhs_type.name(), data.rhs_type.bit_width());
|
|
WARNLN_AND_DBGLN("UBSAN: shift out of bounds, {} ({}-bit) shifted by {} ({}-bit)", data.lhs_type.name(), data.lhs_type.bit_width(), data.rhs_type.name(), data.rhs_type.bit_width());
|
|
print_location(location);
|
|
print_location(location);
|
|
}
|
|
}
|
|
|
|
+[[gnu::used]] void __ubsan_handle_shift_out_of_bounds(ShiftOutOfBoundsData& data, ValueHandle lhs, ValueHandle rhs)
|
|
|
|
+{
|
|
|
|
+ handle_shift_out_of_bounds(data, lhs, rhs);
|
|
|
|
+ ABORT_IF_DEADLY();
|
|
|
|
+}
|
|
|
|
+[[gnu::used, noreturn]] void __ubsan_handle_shift_out_of_bounds_abort(ShiftOutOfBoundsData& data, ValueHandle lhs, ValueHandle rhs)
|
|
|
|
+{
|
|
|
|
+ handle_shift_out_of_bounds(data, lhs, rhs);
|
|
|
|
+ ABORT_ALWAYS();
|
|
|
|
+}
|
|
|
|
|
|
-void __ubsan_handle_divrem_overflow(OverflowData&, ValueHandle lhs, ValueHandle rhs) __attribute__((used));
|
|
|
|
-void __ubsan_handle_divrem_overflow(OverflowData& data, ValueHandle, ValueHandle)
|
|
|
|
|
|
+static void handle_divrem_overflow(OverflowData& data, ValueHandle, ValueHandle)
|
|
{
|
|
{
|
|
auto location = data.location.permanently_clear();
|
|
auto location = data.location.permanently_clear();
|
|
if (!location.needs_logging())
|
|
if (!location.needs_logging())
|
|
@@ -176,9 +278,18 @@ void __ubsan_handle_divrem_overflow(OverflowData& data, ValueHandle, ValueHandle
|
|
WARNLN_AND_DBGLN("UBSAN: divrem overflow, {} ({}-bit)", data.type.name(), data.type.bit_width());
|
|
WARNLN_AND_DBGLN("UBSAN: divrem overflow, {} ({}-bit)", data.type.name(), data.type.bit_width());
|
|
print_location(location);
|
|
print_location(location);
|
|
}
|
|
}
|
|
|
|
+[[gnu::used]] void __ubsan_handle_divrem_overflow(OverflowData& data, ValueHandle lhs, ValueHandle rhs)
|
|
|
|
+{
|
|
|
|
+ handle_divrem_overflow(data, lhs, rhs);
|
|
|
|
+ ABORT_IF_DEADLY();
|
|
|
|
+}
|
|
|
|
+[[gnu::used, noreturn]] void __ubsan_handle_divrem_overflow_abort(OverflowData& data, ValueHandle lhs, ValueHandle rhs)
|
|
|
|
+{
|
|
|
|
+ handle_divrem_overflow(data, lhs, rhs);
|
|
|
|
+ ABORT_ALWAYS();
|
|
|
|
+}
|
|
|
|
|
|
-void __ubsan_handle_out_of_bounds(OutOfBoundsData&, ValueHandle) __attribute__((used));
|
|
|
|
-void __ubsan_handle_out_of_bounds(OutOfBoundsData& data, ValueHandle)
|
|
|
|
|
|
+static void handle_out_of_bounds(OutOfBoundsData& data, ValueHandle)
|
|
{
|
|
{
|
|
auto location = data.location.permanently_clear();
|
|
auto location = data.location.permanently_clear();
|
|
if (!location.needs_logging())
|
|
if (!location.needs_logging())
|
|
@@ -186,9 +297,18 @@ void __ubsan_handle_out_of_bounds(OutOfBoundsData& data, ValueHandle)
|
|
WARNLN_AND_DBGLN("UBSAN: out of bounds access into array of {} ({}-bit), index type {} ({}-bit)", data.array_type.name(), data.array_type.bit_width(), data.index_type.name(), data.index_type.bit_width());
|
|
WARNLN_AND_DBGLN("UBSAN: out of bounds access into array of {} ({}-bit), index type {} ({}-bit)", data.array_type.name(), data.array_type.bit_width(), data.index_type.name(), data.index_type.bit_width());
|
|
print_location(location);
|
|
print_location(location);
|
|
}
|
|
}
|
|
|
|
+[[gnu::used]] void __ubsan_handle_out_of_bounds(OutOfBoundsData& data, ValueHandle index)
|
|
|
|
+{
|
|
|
|
+ handle_out_of_bounds(data, index);
|
|
|
|
+ ABORT_IF_DEADLY();
|
|
|
|
+}
|
|
|
|
+[[gnu::used, noreturn]] void __ubsan_handle_out_of_bounds_abort(OutOfBoundsData& data, ValueHandle index)
|
|
|
|
+{
|
|
|
|
+ handle_out_of_bounds(data, index);
|
|
|
|
+ ABORT_ALWAYS();
|
|
|
|
+}
|
|
|
|
|
|
-void __ubsan_handle_type_mismatch_v1(TypeMismatchData&, ValueHandle) __attribute__((used));
|
|
|
|
-void __ubsan_handle_type_mismatch_v1(TypeMismatchData& data, ValueHandle ptr)
|
|
|
|
|
|
+static void handle_type_mismatch_v1(TypeMismatchData& data, ValueHandle ptr)
|
|
{
|
|
{
|
|
constexpr StringView kinds[] = {
|
|
constexpr StringView kinds[] = {
|
|
"load of"sv,
|
|
"load of"sv,
|
|
@@ -222,9 +342,18 @@ void __ubsan_handle_type_mismatch_v1(TypeMismatchData& data, ValueHandle ptr)
|
|
|
|
|
|
print_location(location);
|
|
print_location(location);
|
|
}
|
|
}
|
|
|
|
+[[gnu::used]] void __ubsan_handle_type_mismatch_v1(TypeMismatchData& data, ValueHandle ptr)
|
|
|
|
+{
|
|
|
|
+ handle_type_mismatch_v1(data, ptr);
|
|
|
|
+ ABORT_IF_DEADLY();
|
|
|
|
+}
|
|
|
|
+[[gnu::used, noreturn]] void __ubsan_handle_type_mismatch_v1_abort(TypeMismatchData& data, ValueHandle ptr)
|
|
|
|
+{
|
|
|
|
+ handle_type_mismatch_v1(data, ptr);
|
|
|
|
+ ABORT_ALWAYS();
|
|
|
|
+}
|
|
|
|
|
|
-void __ubsan_handle_alignment_assumption(AlignmentAssumptionData&, ValueHandle, ValueHandle, ValueHandle) __attribute__((used));
|
|
|
|
-void __ubsan_handle_alignment_assumption(AlignmentAssumptionData& data, ValueHandle pointer, ValueHandle alignment, ValueHandle offset)
|
|
|
|
|
|
+static void handle_alignment_assumption(AlignmentAssumptionData& data, ValueHandle pointer, ValueHandle alignment, ValueHandle offset)
|
|
{
|
|
{
|
|
auto location = data.location.permanently_clear();
|
|
auto location = data.location.permanently_clear();
|
|
if (!location.needs_logging())
|
|
if (!location.needs_logging())
|
|
@@ -242,6 +371,16 @@ void __ubsan_handle_alignment_assumption(AlignmentAssumptionData& data, ValueHan
|
|
|
|
|
|
print_location(location);
|
|
print_location(location);
|
|
}
|
|
}
|
|
|
|
+[[gnu::used]] void __ubsan_handle_alignment_assumption(AlignmentAssumptionData& data, ValueHandle pointer, ValueHandle alignment, ValueHandle offset)
|
|
|
|
+{
|
|
|
|
+ handle_alignment_assumption(data, pointer, alignment, offset);
|
|
|
|
+ ABORT_IF_DEADLY();
|
|
|
|
+}
|
|
|
|
+[[gnu::used, noreturn]] void __ubsan_handle_alignment_assumption_abort(AlignmentAssumptionData& data, ValueHandle pointer, ValueHandle alignment, ValueHandle offset)
|
|
|
|
+{
|
|
|
|
+ handle_alignment_assumption(data, pointer, alignment, offset);
|
|
|
|
+ ABORT_ALWAYS();
|
|
|
|
+}
|
|
|
|
|
|
[[gnu::used, noreturn]] void __ubsan_handle_builtin_unreachable(UnreachableData& data)
|
|
[[gnu::used, noreturn]] void __ubsan_handle_builtin_unreachable(UnreachableData& data)
|
|
{
|
|
{
|
|
@@ -257,8 +396,7 @@ void __ubsan_handle_alignment_assumption(AlignmentAssumptionData& data, ValueHan
|
|
ABORT_ALWAYS();
|
|
ABORT_ALWAYS();
|
|
}
|
|
}
|
|
|
|
|
|
-void __ubsan_handle_implicit_conversion(ImplicitConversionData&, ValueHandle, ValueHandle) __attribute__((used));
|
|
|
|
-void __ubsan_handle_implicit_conversion(ImplicitConversionData& data, ValueHandle, ValueHandle)
|
|
|
|
|
|
+static void handle_implicit_conversion(ImplicitConversionData& data, ValueHandle, ValueHandle)
|
|
{
|
|
{
|
|
auto location = data.location.permanently_clear();
|
|
auto location = data.location.permanently_clear();
|
|
if (!location.needs_logging())
|
|
if (!location.needs_logging())
|
|
@@ -269,9 +407,18 @@ void __ubsan_handle_implicit_conversion(ImplicitConversionData& data, ValueHandl
|
|
data.from_type.name(), data.from_type.bit_width(), src_signed, data.to_type.name(), data.to_type.bit_width(), dst_signed);
|
|
data.from_type.name(), data.from_type.bit_width(), src_signed, data.to_type.name(), data.to_type.bit_width(), dst_signed);
|
|
print_location(location);
|
|
print_location(location);
|
|
}
|
|
}
|
|
|
|
+[[gnu::used]] void __ubsan_handle_implicit_conversion(ImplicitConversionData& data, ValueHandle from, ValueHandle to)
|
|
|
|
+{
|
|
|
|
+ handle_implicit_conversion(data, from, to);
|
|
|
|
+ ABORT_IF_DEADLY();
|
|
|
|
+}
|
|
|
|
+[[gnu::used, noreturn]] void __ubsan_handle_implicit_conversion_abort(ImplicitConversionData& data, ValueHandle from, ValueHandle to)
|
|
|
|
+{
|
|
|
|
+ handle_implicit_conversion(data, from, to);
|
|
|
|
+ ABORT_ALWAYS();
|
|
|
|
+}
|
|
|
|
|
|
-void __ubsan_handle_invalid_builtin(InvalidBuiltinData&) __attribute__((used));
|
|
|
|
-void __ubsan_handle_invalid_builtin(InvalidBuiltinData& data)
|
|
|
|
|
|
+static void handle_invalid_builtin(InvalidBuiltinData& data)
|
|
{
|
|
{
|
|
auto location = data.location.permanently_clear();
|
|
auto location = data.location.permanently_clear();
|
|
if (!location.needs_logging())
|
|
if (!location.needs_logging())
|
|
@@ -279,9 +426,18 @@ void __ubsan_handle_invalid_builtin(InvalidBuiltinData& data)
|
|
WARNLN_AND_DBGLN("UBSAN: passing invalid argument");
|
|
WARNLN_AND_DBGLN("UBSAN: passing invalid argument");
|
|
print_location(location);
|
|
print_location(location);
|
|
}
|
|
}
|
|
|
|
+[[gnu::used]] void __ubsan_handle_invalid_builtin(InvalidBuiltinData& data)
|
|
|
|
+{
|
|
|
|
+ handle_invalid_builtin(data);
|
|
|
|
+ ABORT_IF_DEADLY();
|
|
|
|
+}
|
|
|
|
+[[gnu::used, noreturn]] void __ubsan_handle_invalid_builtin_abort(InvalidBuiltinData& data)
|
|
|
|
+{
|
|
|
|
+ handle_invalid_builtin(data);
|
|
|
|
+ ABORT_ALWAYS();
|
|
|
|
+}
|
|
|
|
|
|
-void __ubsan_handle_pointer_overflow(PointerOverflowData&, ValueHandle, ValueHandle) __attribute__((used));
|
|
|
|
-void __ubsan_handle_pointer_overflow(PointerOverflowData& data, ValueHandle base, ValueHandle result)
|
|
|
|
|
|
+static void handle_pointer_overflow(PointerOverflowData& data, ValueHandle base, ValueHandle result)
|
|
{
|
|
{
|
|
auto location = data.location.permanently_clear();
|
|
auto location = data.location.permanently_clear();
|
|
if (!location.needs_logging())
|
|
if (!location.needs_logging())
|
|
@@ -297,9 +453,18 @@ void __ubsan_handle_pointer_overflow(PointerOverflowData& data, ValueHandle base
|
|
}
|
|
}
|
|
print_location(location);
|
|
print_location(location);
|
|
}
|
|
}
|
|
|
|
+[[gnu::used]] void __ubsan_handle_pointer_overflow(PointerOverflowData& data, ValueHandle base, ValueHandle result)
|
|
|
|
+{
|
|
|
|
+ handle_pointer_overflow(data, base, result);
|
|
|
|
+ ABORT_IF_DEADLY();
|
|
|
|
+}
|
|
|
|
+[[gnu::used, noreturn]] void __ubsan_handle_pointer_overflow_abort(PointerOverflowData& data, ValueHandle base, ValueHandle result)
|
|
|
|
+{
|
|
|
|
+ handle_pointer_overflow(data, base, result);
|
|
|
|
+ ABORT_ALWAYS();
|
|
|
|
+}
|
|
|
|
|
|
-void __ubsan_handle_float_cast_overflow(FloatCastOverflowData&, ValueHandle) __attribute__((used));
|
|
|
|
-void __ubsan_handle_float_cast_overflow(FloatCastOverflowData& data, ValueHandle)
|
|
|
|
|
|
+static void handle_float_cast_overflow(FloatCastOverflowData& data, ValueHandle)
|
|
{
|
|
{
|
|
auto location = data.location.permanently_clear();
|
|
auto location = data.location.permanently_clear();
|
|
if (!location.needs_logging())
|
|
if (!location.needs_logging())
|
|
@@ -307,5 +472,14 @@ void __ubsan_handle_float_cast_overflow(FloatCastOverflowData& data, ValueHandle
|
|
WARNLN_AND_DBGLN("UBSAN: overflow when casting from {} to {}", data.from_type.name(), data.to_type.name());
|
|
WARNLN_AND_DBGLN("UBSAN: overflow when casting from {} to {}", data.from_type.name(), data.to_type.name());
|
|
print_location(location);
|
|
print_location(location);
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+[[gnu::used]] void __ubsan_handle_float_cast_overflow(FloatCastOverflowData& data, ValueHandle value)
|
|
|
|
+{
|
|
|
|
+ handle_float_cast_overflow(data, value);
|
|
|
|
+ ABORT_IF_DEADLY();
|
|
|
|
+}
|
|
|
|
+[[gnu::used, noreturn]] void __ubsan_handle_float_cast_overflow_abort(FloatCastOverflowData& data, ValueHandle value)
|
|
|
|
+{
|
|
|
|
+ handle_float_cast_overflow(data, value);
|
|
|
|
+ ABORT_ALWAYS();
|
|
|
|
+}
|
|
} // extern "C"
|
|
} // extern "C"
|