205 lines
6.1 KiB
C++
205 lines
6.1 KiB
C++
|
#define MODULE "ubsan"
|
||
|
|
||
|
#include <log/Log.h>
|
||
|
#include <panic/Panic.h>
|
||
|
#include <stdint.h>
|
||
|
|
||
|
#pragma GCC push_options
|
||
|
#pragma GCC diagnostic ignored "-Wpedantic"
|
||
|
|
||
|
struct source_location
|
||
|
{
|
||
|
const char* file;
|
||
|
uint32_t line;
|
||
|
uint32_t column;
|
||
|
};
|
||
|
|
||
|
struct type_descriptor
|
||
|
{
|
||
|
uint16_t kind;
|
||
|
uint16_t info;
|
||
|
char name[];
|
||
|
};
|
||
|
|
||
|
struct type_mismatch_info
|
||
|
{
|
||
|
struct source_location location;
|
||
|
struct type_descriptor* type;
|
||
|
uintptr_t alignment;
|
||
|
uint8_t type_check_kind;
|
||
|
};
|
||
|
|
||
|
struct type_mismatch_info_v1
|
||
|
{
|
||
|
struct source_location location;
|
||
|
struct type_descriptor* type;
|
||
|
unsigned char log_alignment;
|
||
|
unsigned char type_check_kind;
|
||
|
};
|
||
|
|
||
|
struct overflow_info
|
||
|
{
|
||
|
struct source_location location;
|
||
|
struct type_descriptor* type;
|
||
|
};
|
||
|
|
||
|
struct unreachable_info
|
||
|
{
|
||
|
struct source_location location;
|
||
|
};
|
||
|
|
||
|
struct out_of_bounds_info
|
||
|
{
|
||
|
struct source_location location;
|
||
|
struct type_descriptor* array_type;
|
||
|
struct type_descriptor* index_type;
|
||
|
};
|
||
|
|
||
|
struct invalid_value_info
|
||
|
{
|
||
|
struct source_location location;
|
||
|
struct type_descriptor* type;
|
||
|
};
|
||
|
|
||
|
struct shift_out_of_bounds_info
|
||
|
{
|
||
|
struct source_location location;
|
||
|
struct type_descriptor* lhs_type;
|
||
|
struct type_descriptor* rhs_type;
|
||
|
};
|
||
|
|
||
|
struct pointer_overflow_info
|
||
|
{
|
||
|
struct source_location location;
|
||
|
};
|
||
|
|
||
|
#define is_aligned(value, alignment) !(value & (alignment - 1))
|
||
|
|
||
|
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",
|
||
|
};
|
||
|
|
||
|
static void log_location(source_location* location)
|
||
|
{
|
||
|
kinfoln("at %s:%d:%d", location->file, location->line, location->column);
|
||
|
}
|
||
|
|
||
|
extern "C" void __ubsan_handle_type_mismatch(type_mismatch_info* type_mismatch, uintptr_t pointer)
|
||
|
{
|
||
|
source_location* location = &type_mismatch->location;
|
||
|
if (pointer == 0) { kinfoln("Null pointer access"); }
|
||
|
else if (type_mismatch->alignment != 0 && is_aligned(pointer, type_mismatch->alignment))
|
||
|
{
|
||
|
// Most useful on architectures with stricter memory alignment requirements, like ARM.
|
||
|
kinfoln("Unaligned memory access");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
kinfoln("Insufficient size");
|
||
|
kinfoln("%s address %p with insufficient space for object of type %s\n",
|
||
|
Type_Check_Kinds[type_mismatch->type_check_kind], (void*)pointer, type_mismatch->type->name);
|
||
|
}
|
||
|
log_location(location);
|
||
|
panic("Undefined behaviour detected");
|
||
|
}
|
||
|
|
||
|
extern "C" void __ubsan_handle_type_mismatch_v1(type_mismatch_info_v1* type_mismatch, unsigned long pointer)
|
||
|
{
|
||
|
type_mismatch_info info = {type_mismatch->location, type_mismatch->type, 1UL << type_mismatch->log_alignment,
|
||
|
type_mismatch->type_check_kind};
|
||
|
|
||
|
__ubsan_handle_type_mismatch(&info, pointer);
|
||
|
}
|
||
|
|
||
|
extern "C" void __ubsan_handle_add_overflow(overflow_info* overflow_data, uintptr_t, uintptr_t)
|
||
|
{
|
||
|
source_location* location = &overflow_data->location;
|
||
|
kinfoln("Addition overflow for two values of type %s", overflow_data->type->name);
|
||
|
log_location(location);
|
||
|
panic("Undefined behaviour detected");
|
||
|
}
|
||
|
|
||
|
extern "C" void __ubsan_handle_sub_overflow(overflow_info* overflow_data, uintptr_t, uintptr_t)
|
||
|
{
|
||
|
source_location* location = &overflow_data->location;
|
||
|
kinfoln("Substraction overflow for two values of type %s", overflow_data->type->name);
|
||
|
log_location(location);
|
||
|
panic("Undefined behaviour detected");
|
||
|
}
|
||
|
|
||
|
extern "C" void __ubsan_handle_mul_overflow(overflow_info* overflow_data, uintptr_t, uintptr_t)
|
||
|
{
|
||
|
source_location* location = &overflow_data->location;
|
||
|
kinfoln("Multiplication overflow for two values of type %s", overflow_data->type->name);
|
||
|
log_location(location);
|
||
|
panic("Undefined behaviour detected");
|
||
|
}
|
||
|
|
||
|
extern "C" void __ubsan_handle_negate_overflow(overflow_info* overflow_data, uintptr_t)
|
||
|
{
|
||
|
source_location* location = &overflow_data->location;
|
||
|
kinfoln("Negation overflow for two values of type %s", overflow_data->type->name);
|
||
|
log_location(location);
|
||
|
panic("Undefined behaviour detected");
|
||
|
}
|
||
|
|
||
|
extern "C" void __ubsan_handle_divrem_overflow(overflow_info* overflow_data, uintptr_t, uintptr_t)
|
||
|
{
|
||
|
source_location* location = &overflow_data->location;
|
||
|
kinfoln("Division overflow for two values of type %s", overflow_data->type->name);
|
||
|
log_location(location);
|
||
|
panic("Undefined behaviour detected");
|
||
|
}
|
||
|
|
||
|
extern "C" void __ubsan_handle_builtin_unreachable(unreachable_info* unreachable_data)
|
||
|
{
|
||
|
source_location* location = &unreachable_data->location;
|
||
|
kinfoln("Reached the unreachable");
|
||
|
log_location(location);
|
||
|
panic("Undefined behaviour detected");
|
||
|
}
|
||
|
|
||
|
extern "C" void __ubsan_handle_out_of_bounds(out_of_bounds_info* out_of_bounds_data, uintptr_t index)
|
||
|
{
|
||
|
source_location* location = &out_of_bounds_data->location;
|
||
|
kinfoln("Out of bounds access at index %ld of array type %s and index type %s", index,
|
||
|
out_of_bounds_data->array_type->name, out_of_bounds_data->index_type->name);
|
||
|
log_location(location);
|
||
|
panic("Undefined behaviour detected");
|
||
|
}
|
||
|
|
||
|
extern "C" void __ubsan_handle_load_invalid_value(invalid_value_info* invalid_value_data, uintptr_t)
|
||
|
{
|
||
|
source_location* location = &invalid_value_data->location;
|
||
|
kinfoln("Invalid value load of type %s", invalid_value_data->type->name);
|
||
|
log_location(location);
|
||
|
panic("Undefined behaviour detected");
|
||
|
}
|
||
|
|
||
|
extern "C" void __ubsan_handle_shift_out_of_bounds(shift_out_of_bounds_info* shift_out_of_bounds_data, uintptr_t,
|
||
|
uintptr_t)
|
||
|
{
|
||
|
source_location* location = &shift_out_of_bounds_data->location;
|
||
|
kinfoln("Shift out of bounds for type %s", shift_out_of_bounds_data->lhs_type->name);
|
||
|
log_location(location);
|
||
|
panic("Undefined behaviour detected");
|
||
|
}
|
||
|
|
||
|
extern "C" void __ubsan_handle_pointer_overflow(pointer_overflow_info* pointer_overflow_data, uintptr_t, uintptr_t)
|
||
|
{
|
||
|
source_location* location = &pointer_overflow_data->location;
|
||
|
kinfoln("Pointer overflow");
|
||
|
log_location(location);
|
||
|
panic("Undefined behaviour detected");
|
||
|
}
|
||
|
|
||
|
#pragma GCC pop_options
|