225 lines
4.5 KiB
C
225 lines
4.5 KiB
C
// REFERENCES:
|
|
// https://wiki.osdev.org/Undefined_Behavior_Sanitization
|
|
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include <write/write.h>
|
|
|
|
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");
|
|
}
|
|
|