/** * @file ubsan.c * Tiny undefined behaviour sanitizer, mostly lifted from * https://github.com/Abb1x/tinyubsan/blob/master/src/tinyubsan.c * * \todo Add in more runtime info. * * Note that this file's documentation is pretty vague, as I don't know the ins * and outs of the undefined behaviour sanitizer subsystem. */ #include #include /** * Describes a source file location. */ struct source_location { /** Filename. */ const char *file; /** Line number. */ uint32_t line; /** Column number. */ uint32_t column; }; /** * Describes the type of undefined behaviour. * * Currently largely unused, \todo implement better undefined behaviour bug * messages. */ struct type_descriptor { /** Type kind. */ uint16_t kind; /** Additional type info. */ uint16_t info; /** Type name. */ char name[]; }; /** * Describes overflows. */ struct overflow_data { /** Corresponding source location. */ struct source_location location; /** Extra information. */ struct type_descriptor *type; }; /** * Describes out of bounds shifts. */ struct shift_out_of_bounds_data { /** Corresponding source location. */ struct source_location location; /** Extra information #1 */ struct type_descriptor *left_type; /** Extra information #2 */ struct type_descriptor *right_type; }; /** * Describes invalid values. */ struct invalid_value_data { /** Corresponding source location. */ struct source_location location; /** Extra information. */ struct type_descriptor *type; }; /** * Describes out of bounds array accesses. */ struct array_out_of_bounds_data { /** Corresponding source location. */ struct source_location location; /** Information about the array. */ struct type_descriptor *array_type; /** Information about the access. */ struct type_descriptor *index_type; }; /** * Describes mismatched types. Incorrect pointers at least, possibly other stuff * as well. */ struct type_mismatch_v1_data { /** Corresponding source location. */ struct source_location location; /** Extra information. */ struct type_descriptor *type; /** Alignment. */ unsigned char log_alignment; /** Kind (?). */ unsigned char type_check_kind; }; /** * Describes negative VLAs. Note that this kernel explicitly disallows VLAs, * as does the Linux kernel. */ struct negative_vla_data { /** Corresponding source location. */ struct source_location location; /** Extra information. */ struct type_descriptor *type; }; /** * Describes nonnull return. A function is marked with nonnull, but still * returns null. */ struct nonnull_return_data { /** Corresponding source location. */ struct source_location location; }; /** * Describes nonnull arguments. Situations where an argument is marked with * __attribute__("null"), but is given a value. */ struct nonnull_arg_data { /** Corresponding source location. */ struct source_location location; }; /** * Describes unreachable conditions. Mainly for __builtin_unreachable(). */ struct unreachable_data { /** Corresponding source location. */ struct source_location location; }; /** * Describes invalid builtin data. Incorrect usage of __builtin_*(). */ struct invalid_builtin_data { /** Corresponding source location. */ struct source_location location; /** Extra information (?) */ unsigned char kind; }; /** * Wrapper around \ref bug(). Prepends location information to the message. * * @param message Message to be printed. * @param loc Location information. */ static void print_location(const char *message, struct source_location loc) { bug("ubsan: %s at file %s, line %ju, column %ju\n", message, loc.file, (uintmax_t)loc.line, (uintmax_t)loc.column); } /** * Handle overflow during addition. * * @param data Overflow information, generated by the compiler. */ void __ubsan_handle_add_overflow(struct overflow_data *data) { print_location("addition overflow", data->location); } /** * Handle overflow during subtraction. * * @param data Overflow information, generated by the compiler. */ void __ubsan_handle_sub_overflow(struct overflow_data *data) { print_location("subtraction overflow", data->location); } /** * Handle overflow during multiplication. * * @param data Overflow information, generated by the compiler. */ void __ubsan_handle_mul_overflow(struct overflow_data *data) { print_location("multiplication overflow", data->location); } /** * Handle overflow during division or taking a remainder. * * @param data Overflow information, generated by the compiler. */ void __ubsan_handle_divrem_overflow(struct overflow_data *data) { print_location("division overflow", data->location); } /** * Handle overflow during negation. * * @param data Overflow information, generated by the compiler. */ void __ubsan_handle_negate_overflow(struct overflow_data *data) { print_location("negation overflow", data->location); } /** * Handle pointer overflow. * * @param data Overflow information, generated by the compiler. */ void __ubsan_handle_pointer_overflow(struct overflow_data *data) { print_location("pointer overflow", data->location); } /** * Handle out of bounds shifts. * * @param data Out of bounds information, generated by the compiler. */ void __ubsan_handle_shift_out_of_bounds( struct shift_out_of_bounds_data *data) { print_location("shift out of bounds", data->location); } /** * Handle invalid load values. * * @param data Load information, generated by the compiler. */ void __ubsan_handle_load_invalid_value(struct invalid_value_data *data) { print_location("invalid load value", data->location); } /** * Handle array out of bounds accesses. * * @param data Out of bounds information, generated by the compiler. */ void __ubsan_handle_out_of_bounds(struct array_out_of_bounds_data *data) { print_location("array out of bounds", data->location); } /** * Handle type mismatch, one format. * * @param data Type mismatch information, generated by the compiler. * @param ptr Pointer that caused a mismatch. */ void __ubsan_handle_type_mismatch_v1(struct type_mismatch_v1_data *data, uintptr_t ptr) { if (!ptr) { print_location("use of NULL pointer", data->location); } else if (ptr & ((1 << data->log_alignment) - 1)) { print_location("use of misaligned pointer", data->location); } else { print_location("no space for object", data->location); } } /** * Handle negative VLA. * * @param data VLA information, generated by the compiler. */ void __ubsan_handle_vla_bound_not_positive(struct negative_vla_data *data) { print_location("variable-length argument is negative", data->location); } /** * Handle nonnull return. * * @param data Return information, generated by compiler. */ void __ubsan_handle_nonnull_return(struct nonnull_return_data *data) { print_location("non-null return is null", data->location); } /** * Handle nonnull argument. * * @param data Argument information, generated by compiler. */ void __ubsan_handle_nonnull_arg(struct nonnull_arg_data *data) { print_location("non-null argument is null", data->location); } /** * Handle unreachable code. * * @param data Unreachable code information, generated by compiler. */ void __ubsan_handle_builtin_unreachable(struct unreachable_data *data) { print_location("unreachable code reached", data->location); } /** * Handle invalid builtin. * * @param data Builtin information, generated by compiler. */ void __ubsan_handle_invalid_builtin(struct invalid_builtin_data *data) { print_location("invalid builtin", data->location); }