Add rudimentary support for undefined behavior sanitizer.
[helenos.git] / uspace / lib / c / generic / ubsan.c
blobb5f1b8a66d694c28241c249a00be1efe455bbd8b
1 // SPDX-License-Identifier: BSD-2-Clause
2 /*
3 * Copyright (c) 2016, Linaro Limited
4 */
6 /* Modified for HelenOS use by Jiří Zárevúcky. */
8 #include <stdbool.h>
9 #include <inttypes.h>
10 #include <stdlib.h>
11 #include <stddef.h>
12 #include <mem.h>
13 #include <io/kio.h>
15 #define PRINTF(...) kio_printf(__VA_ARGS__)
16 #define ubsan_panic() abort()
18 struct source_location {
19 const char *file_name;
20 uint32_t line;
21 uint32_t column;
24 struct type_descriptor {
25 uint16_t type_kind;
26 uint16_t type_info;
27 char type_name[];
30 struct type_mismatch_data {
31 struct source_location loc;
32 struct type_descriptor *type;
33 unsigned long alignment;
34 unsigned char type_check_kind;
37 struct overflow_data {
38 struct source_location loc;
39 struct type_descriptor *type;
42 struct shift_out_of_bounds_data {
43 struct source_location loc;
44 struct type_descriptor *lhs_type;
45 struct type_descriptor *rhs_type;
48 struct out_of_bounds_data {
49 struct source_location loc;
50 struct type_descriptor *array_type;
51 struct type_descriptor *index_type;
54 struct unreachable_data {
55 struct source_location loc;
58 struct vla_bound_data {
59 struct source_location loc;
60 struct type_descriptor *type;
63 struct invalid_value_data {
64 struct source_location loc;
65 struct type_descriptor *type;
68 struct nonnull_arg_data {
69 struct source_location loc;
72 struct nonnull_return_data {
73 struct source_location loc;
74 struct source_location attr_loc;
78 * When compiling with -fsanitize=undefined the compiler expects functions
79 * with the following signatures. The functions are never called directly,
80 * only when undefined behavior is detected in instrumented code.
82 void __ubsan_handle_type_mismatch(struct type_mismatch_data *data, unsigned long ptr);
83 void __ubsan_handle_add_overflow(struct overflow_data *data, unsigned long lhs, unsigned long rhs);
84 void __ubsan_handle_sub_overflow(struct overflow_data *data, unsigned long lhs, unsigned long rhs);
85 void __ubsan_handle_mul_overflow(struct overflow_data *data, unsigned long lhs, unsigned long rhs);
86 void __ubsan_handle_negate_overflow(struct overflow_data *data, unsigned long old_val);
87 void __ubsan_handle_divrem_overflow(struct overflow_data *data, unsigned long lhs, unsigned long rhs);
88 void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data, unsigned long lhs, unsigned long rhs);
89 void __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data, unsigned long idx);
90 void __ubsan_handle_unreachable(struct unreachable_data *data);
91 void __ubsan_handle_missing_return(struct unreachable_data *data);
92 void __ubsan_handle_vla_bound_not_positive(struct vla_bound_data *data, unsigned long bound);
93 void __ubsan_handle_load_invalid_value(struct invalid_value_data *data, unsigned long val);
94 #if __GCC_VERSION < 60000
95 void __ubsan_handle_nonnull_arg(struct nonnull_arg_data *data, size_t arg_no);
96 #else
97 void __ubsan_handle_nonnull_arg(struct nonnull_arg_data *data);
98 #endif
99 void __ubsan_handle_nonnull_return(struct nonnull_return_data *data);
101 static void print_loc(const char *func, struct source_location *loc)
103 const char *f = func;
104 const char func_prefix[] = "__ubsan_handle";
106 if (!memcmp(f, func_prefix, sizeof(func_prefix) - 1))
107 f += sizeof(func_prefix);
109 PRINTF("Undefined behavior %s at %s:%" PRIu32 " col %" PRIu32 "\n",
110 f, loc->file_name, loc->line, loc->column);
113 void __ubsan_handle_type_mismatch(struct type_mismatch_data *data,
114 unsigned long ptr)
116 print_loc(__func__, &data->loc);
117 ubsan_panic();
120 void __ubsan_handle_add_overflow(struct overflow_data *data,
121 unsigned long lhs,
122 unsigned long rhs)
124 print_loc(__func__, &data->loc);
125 ubsan_panic();
128 void __ubsan_handle_sub_overflow(struct overflow_data *data,
129 unsigned long lhs,
130 unsigned long rhs)
132 print_loc(__func__, &data->loc);
133 ubsan_panic();
136 void __ubsan_handle_mul_overflow(struct overflow_data *data,
137 unsigned long lhs,
138 unsigned long rhs)
140 print_loc(__func__, &data->loc);
141 ubsan_panic();
144 void __ubsan_handle_negate_overflow(struct overflow_data *data,
145 unsigned long old_val)
147 print_loc(__func__, &data->loc);
148 ubsan_panic();
151 void __ubsan_handle_divrem_overflow(struct overflow_data *data,
152 unsigned long lhs,
153 unsigned long rhs)
155 print_loc(__func__, &data->loc);
156 ubsan_panic();
159 void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data,
160 unsigned long lhs,
161 unsigned long rhs)
163 print_loc(__func__, &data->loc);
164 PRINTF("LHS type: %s, value: %lu, RHS type: %s, value: %lu\n",
165 data->lhs_type->type_name, lhs, data->rhs_type->type_name, rhs);
166 ubsan_panic();
169 void __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data,
170 unsigned long idx)
172 print_loc(__func__, &data->loc);
173 ubsan_panic();
176 void __ubsan_handle_unreachable(struct unreachable_data *data)
178 print_loc(__func__, &data->loc);
179 ubsan_panic();
182 void __ubsan_handle_missing_return(struct unreachable_data *data)
184 print_loc(__func__, &data->loc);
185 ubsan_panic();
188 void __ubsan_handle_vla_bound_not_positive(struct vla_bound_data *data,
189 unsigned long bound)
191 print_loc(__func__, &data->loc);
192 ubsan_panic();
195 void __ubsan_handle_load_invalid_value(struct invalid_value_data *data,
196 unsigned long val)
198 print_loc(__func__, &data->loc);
199 ubsan_panic();
202 #if __GCC_VERSION < 60000
203 void __ubsan_handle_nonnull_arg(struct nonnull_arg_data *data, size_t arg_no)
205 print_loc(__func__, &data->loc);
206 ubsan_panic();
208 #else
209 void __ubsan_handle_nonnull_arg(struct nonnull_arg_data *data)
211 print_loc(__func__, &data->loc);
212 ubsan_panic();
214 #endif
216 void __ubsan_handle_nonnull_return(struct nonnull_return_data *data)
218 print_loc(__func__, &data->loc);
219 ubsan_panic();