banan-os/kernel/ubsan.cpp

130 lines
3.7 KiB
C++

#include <kernel/Debug.h>
#include <kernel/Panic.h>
extern "C"
{
struct source_location
{
const char *file;
uint32_t line;
uint32_t column;
};
struct type_descriptor
{
uint16_t kind;
uint16_t info;
char name[1];
};
struct type_mismatch_data
{
source_location location;
const type_descriptor& type;
uint8_t alignment;
uint8_t type_check_kind;
};
struct out_of_bounds_data
{
source_location location;
const type_descriptor& left_type;
const type_descriptor& right_type;
};
struct shift_out_of_bounds_data
{
source_location location;
const type_descriptor& left_type;
const type_descriptor& right_type;
};
struct pointer_overflow_data
{
source_location location;
};
struct invalid_value_data
{
source_location location;
const type_descriptor& type;
};
struct overflow_data
{
source_location location;
const type_descriptor& type;
};
struct vla_bound_data
{
source_location location;
const type_descriptor& type;
};
enum builtin_check_kind : unsigned char
{
BCK_CTZPassedZero,
BCK_CLZPassedZero,
};
struct invalid_builtin_data
{
source_location location;
builtin_check_kind kind;
};
using value_handle = uintptr_t;
static const char* type_check_kinds[] = {
"load of", "store to", "reference binding to", "member access within",
"member call on", "constructor call on", "downcast of", "downcast of",
"upcast of", "cast to virtual base of", "_Nonnull binding to",
"dynamic operation on"
};
#define HANDLER(handler, fatal, ...) \
void handler(__VA_ARGS__) \
{ \
if constexpr(fatal) \
Kernel::panic("{}:{} {}", data->location.file, data->location.line, __FUNCTION__); \
else \
derrorln("{}:{} {}", data->location.file, data->location.line, __FUNCTION__); \
}
static void print_location_impl(const source_location& location, const char* function)
{
derrorln("{}:{} {}", location.file, location.line, function);
}
#define print_location(location) print_location_impl(location, __FUNCTION__)
HANDLER(__ubsan_handle_pointer_overflow, false, pointer_overflow_data* data, value_handle, value_handle)
HANDLER(__ubsan_handle_load_invalid_value, false, invalid_value_data* data, value_handle)
HANDLER(__ubsan_handle_out_of_bounds, false, out_of_bounds_data* data, value_handle)
HANDLER(__ubsan_handle_shift_out_of_bounds, false, shift_out_of_bounds_data* data, value_handle, value_handle)
HANDLER(__ubsan_handle_add_overflow, false, overflow_data* data, value_handle, value_handle)
HANDLER(__ubsan_handle_sub_overflow, false, overflow_data* data, value_handle, value_handle)
HANDLER(__ubsan_handle_mul_overflow, false, overflow_data* data, value_handle, value_handle)
HANDLER(__ubsan_handle_divrem_overflow, false, overflow_data* data, value_handle, value_handle)
HANDLER(__ubsan_handle_negate_overflow, false, overflow_data* data, value_handle)
HANDLER(__ubsan_handle_vla_bound_not_positive, false, vla_bound_data* data, value_handle);
HANDLER(__ubsan_handle_invalid_builtin, false, invalid_builtin_data* data);
void __ubsan_handle_type_mismatch_v1(type_mismatch_data* data, value_handle pointer)
{
print_location(data->location);
const char* kind = type_check_kinds[data->type_check_kind];
uintptr_t alignment = (uintptr_t)1 << data->alignment;
if (!pointer)
derrorln("{} null pointer of type {}", kind, data->type.name);
else if (pointer & (alignment - 1))
derrorln("{} misaligned address {} for type {}, which requires {} byte alignment", kind, (void*)pointer, data->type.name, alignment);
else
derrorln("{} address {} with insufficient space for an object of type {}", kind, (void*)pointer, data->type.name);
}
}