// REFERENCES: // https://wiki.osdev.org/Undefined_Behavior_Sanitization #include #include #include struct source_location { const char *file; uint32_t line; uint32_t column; }; struct type_descriptor { uint16_t type_kind; uint16_t type_info; char *type_name; }; struct type_mismatch_data { struct source_location loc; struct type_descriptor *type; unsigned long alignment; unsigned char type_check_kind; }; struct type_mismatch_data_v1 { struct source_location loc; struct type_descriptor *type; unsigned char alignment; unsigned char type_check_kind; }; struct overflow_data { struct source_location loc; struct type_descriptor *type; }; struct shift_out_of_bounds_data { struct source_location loc; struct type_descriptor *lhs_type; struct type_descriptor *rhs_type; }; struct out_of_bounds_data { struct source_location loc; struct type_descriptor *array_type; struct type_descriptor *index_type; }; struct unreachable_data { struct source_location loc; }; struct vla_bound_data { struct source_location loc; struct type_descriptor *type; }; struct invalid_value_data { struct source_location loc; struct type_descriptor *type; }; struct nonnull_arg_data { struct source_location loc; }; struct nonnull_return_data { struct source_location loc; struct source_location attr_loc; }; struct invalid_builtin_data { struct source_location loc; uint8_t kind; }; struct pointer_overflow_data { struct source_location loc; }; static void ubsan_print(struct source_location *loc, const char *message) { writefmt("UBSAN error {s}:{d}:{d} {s}\n", loc->file, loc->line, loc->column, message); } void __ubsan_handle_add_overflow(struct overflow_data *data) { ubsan_print(&data->loc, "addition overflow"); } void __ubsan_handle_sub_overflow(struct overflow_data *data) { ubsan_print(&data->loc, "subtraction overflow"); } void __ubsan_handle_mul_overflow(struct overflow_data *data) { ubsan_print(&data->loc, "multiplication overflow"); } void __ubsan_handle_divrem_overflow(struct overflow_data *data) { ubsan_print(&data->loc, "division overflow"); } void __ubsan_handle_negate_overflow(struct overflow_data *data) { ubsan_print(&data->loc, "negation overflow"); } void __ubsan_handle_pointer_overflow(struct overflow_data *data) { ubsan_print(&data->loc, "pointer overflow"); } void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data) { ubsan_print(&data->loc, "shift out of bounds"); } void __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data) { ubsan_print(&data->loc, "array out of bounds"); } void __ubsan_handle_load_invalid_value(struct invalid_value_data *data) { ubsan_print(&data->loc, "invalid load value"); } void __ubsan_handle_type_mismatch(struct type_mismatch_data *data, uintptr_t ptr) { if (ptr == (uintptr_t)NULL) { ubsan_print(&data->loc, "null pointer access"); } else if ((data->alignment != 0) && ((ptr & (((uintptr_t)1 << data->alignment) - (uintptr_t)1)) != 0)) { ubsan_print(&data->loc, "misaligned pointer is used"); } else { ubsan_print(&data->loc, "insufficient space for an object"); } } void __ubsan_handle_type_mismatch_v1(struct type_mismatch_data_v1 *data, uintptr_t ptr) { if (ptr == (uintptr_t)NULL) { ubsan_print(&data->loc, "null pointer access"); } else if ((data->alignment != 0) && ((ptr & (((uintptr_t)1 << data->alignment) - (uintptr_t)1)) != 0)) { ubsan_print(&data->loc, "misaligned pointer is used"); } else { ubsan_print(&data->loc, "insufficient space for an object"); } } void __ubsan_handle_vla_bound_not_positive(struct vla_bound_data *data) { ubsan_print(&data->loc, "variable-length argument out of bounds"); } void __ubsan_handle_nonnull_return(struct nonnull_return_data *data) { ubsan_print(&data->loc, "null pointer returned from a function 'nonnull' specified"); } void __ubsan_handle_nonnull_return_v1(struct nonnull_return_data *data, struct source_location *loc) { ubsan_print(&data->loc, "null pointer returned from a function 'nonnull' specified"); } void __ubsan_handle_nonnull_arg(struct nonnull_arg_data *data) { ubsan_print(&data->loc, "non-null argument is null"); } void __ubsan_handle_builtin_unreachable(struct unreachable_data *data) { ubsan_print(&data->loc, "unreachable code reached"); } void __ubsan_handle_invalid_builtin(struct invalid_builtin_data *data) { ubsan_print(&data->loc, "invalid builtin"); } void __ubsan_handle_missing_return(struct unreachable_data *data) { ubsan_print(&data->loc, "missing return value"); }