#define MODULE "ubsan" #include #include #include #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