1 /* SPDX-License-Identifier: ISC */
3 * Undefined behavior sanitizer runtime support.
6 * https://gitlab.com/sortix/sortix/raw/master/libc/ubsan/ubsan.c
10 #include <console/console.h>
12 struct ubsan_source_location
{
18 struct ubsan_type_descriptor
{
24 typedef uintptr_t ubsan_value_handle_t
;
27 * Keep the compiler happy -- it wants prototypes but nobody
28 * except the compiler should be touching these functions.
30 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
32 static void __noreturn
ubsan_abort(const struct ubsan_source_location
*location
,
33 const char *violation
) {
34 static const struct ubsan_source_location unknown_location
= {
40 if (!location
|| !location
->filename
)
41 location
= &unknown_location
;
42 printk(BIOS_ERR
, "%s %s:%lu:%lu\n", violation
, location
->filename
,
43 (unsigned long int)location
->line
,
44 (unsigned long int)location
->column
);
45 die("ubsan: unrecoverable error.\n");
48 #define ABORT_VARIANT(name, params, call) \
49 __noreturn void __ubsan_handle_##name##_abort params; \
50 __noreturn void __ubsan_handle_##name##_abort params { \
51 __ubsan_handle_##name call; \
52 __builtin_unreachable(); \
55 #define ABORT_VARIANT_VP(name) \
56 ABORT_VARIANT(name, (void *a), (a))
57 #define ABORT_VARIANT_VP_VP(name) \
58 ABORT_VARIANT(name, (void *a, void *b), (a, b))
59 #define ABORT_VARIANT_VP_IP(name) \
60 ABORT_VARIANT(name, (void *a, intptr_t b), (a, b))
61 #define ABORT_VARIANT_VP_VP_VP(name) \
62 ABORT_VARIANT(name, (void *a, void *b, void *c), (a, b, c))
64 struct ubsan_type_mismatch_data
{
65 struct ubsan_source_location location
;
66 struct ubsan_type_descriptor
*type
;
68 unsigned char type_check_kind
;
71 void __ubsan_handle_type_mismatch_v1(void *data_raw
, void *pointer_raw
)
73 const struct ubsan_type_mismatch_data
*data
=
74 (struct ubsan_type_mismatch_data
*)data_raw
;
75 ubsan_value_handle_t pointer
= (ubsan_value_handle_t
)pointer_raw
;
76 const char *violation
= "type mismatch";
78 violation
= "null pointer access";
79 else if (data
->alignment
&& (pointer
& (data
->alignment
- 1)))
80 violation
= "unaligned access";
81 ubsan_abort(&data
->location
, violation
);
84 ABORT_VARIANT_VP_VP(type_mismatch_v1
);
86 struct ubsan_overflow_data
{
87 struct ubsan_source_location location
;
88 struct ubsan_type_descriptor
*type
;
91 void __ubsan_handle_add_overflow(void *data_raw
, void *lhs_raw
,
94 const struct ubsan_overflow_data
*data
95 = (struct ubsan_overflow_data
*)data_raw
;
96 ubsan_value_handle_t lhs
= (ubsan_value_handle_t
)lhs_raw
;
97 ubsan_value_handle_t rhs
= (ubsan_value_handle_t
)rhs_raw
;
100 ubsan_abort(&data
->location
, "addition overflow");
103 ABORT_VARIANT_VP_VP_VP(add_overflow
);
105 void __ubsan_handle_sub_overflow(void *data_raw
, void *lhs_raw
,
108 const struct ubsan_overflow_data
*data
109 = (struct ubsan_overflow_data
*)data_raw
;
110 ubsan_value_handle_t lhs
= (ubsan_value_handle_t
)lhs_raw
;
111 ubsan_value_handle_t rhs
= (ubsan_value_handle_t
)rhs_raw
;
114 ubsan_abort(&data
->location
, "subtraction overflow");
117 ABORT_VARIANT_VP_VP_VP(sub_overflow
);
119 void __ubsan_handle_mul_overflow(void *data_raw
, void *lhs_raw
,
122 const struct ubsan_overflow_data
*data
123 = (struct ubsan_overflow_data
*)data_raw
;
124 ubsan_value_handle_t lhs
= (ubsan_value_handle_t
)lhs_raw
;
125 ubsan_value_handle_t rhs
= (ubsan_value_handle_t
)rhs_raw
;
128 ubsan_abort(&data
->location
, "multiplication overflow");
131 ABORT_VARIANT_VP_VP_VP(mul_overflow
);
133 void __ubsan_handle_negate_overflow(void *data_raw
, void *old_value_raw
)
135 const struct ubsan_overflow_data
*data
136 = (struct ubsan_overflow_data
*)data_raw
;
137 ubsan_value_handle_t old_value
138 = (ubsan_value_handle_t
)old_value_raw
;
140 ubsan_abort(&data
->location
, "negation overflow");
143 ABORT_VARIANT_VP_VP(negate_overflow
);
145 void __ubsan_handle_divrem_overflow(void *data_raw
, void *lhs_raw
,
148 const struct ubsan_overflow_data
*data
149 = (struct ubsan_overflow_data
*)data_raw
;
150 ubsan_value_handle_t lhs
= (ubsan_value_handle_t
)lhs_raw
;
151 ubsan_value_handle_t rhs
= (ubsan_value_handle_t
)rhs_raw
;
154 ubsan_abort(&data
->location
, "division remainder overflow");
157 ABORT_VARIANT_VP_VP_VP(divrem_overflow
);
159 struct ubsan_pointer_overflow_data
{
160 struct ubsan_source_location location
;
163 void __ubsan_handle_pointer_overflow(void *data_raw
, void *base_raw
, void *result_raw
)
165 const struct ubsan_pointer_overflow_data
*data
=
166 (struct ubsan_pointer_overflow_data
*)data_raw
;
167 ubsan_value_handle_t base
= (ubsan_value_handle_t
)base_raw
;
168 ubsan_value_handle_t result
= (ubsan_value_handle_t
)result_raw
;
171 ubsan_abort(&data
->location
, "pointer overflow");
174 ABORT_VARIANT_VP_VP_VP(pointer_overflow
);
176 struct ubsan_shift_out_of_bounds_data
{
177 struct ubsan_source_location location
;
178 struct ubsan_type_descriptor
*lhs_type
;
179 struct ubsan_type_descriptor
*rhs_type
;
182 void __ubsan_handle_shift_out_of_bounds(void *data_raw
, void *lhs_raw
,
185 const struct ubsan_shift_out_of_bounds_data
*data
=
186 (struct ubsan_shift_out_of_bounds_data
*)data_raw
;
187 ubsan_value_handle_t lhs
= (ubsan_value_handle_t
)lhs_raw
;
188 ubsan_value_handle_t rhs
= (ubsan_value_handle_t
)rhs_raw
;
191 ubsan_abort(&data
->location
, "shift out of bounds");
194 ABORT_VARIANT_VP_VP_VP(shift_out_of_bounds
);
196 struct ubsan_out_of_bounds_data
{
197 struct ubsan_source_location location
;
198 struct ubsan_type_descriptor
*array_type
;
199 struct ubsan_type_descriptor
*index_type
;
202 void __ubsan_handle_out_of_bounds(void *data_raw
, void *index_raw
)
204 const struct ubsan_out_of_bounds_data
*data
=
205 (struct ubsan_out_of_bounds_data
*)data_raw
;
206 ubsan_value_handle_t index
= (ubsan_value_handle_t
)index_raw
;
208 ubsan_abort(&data
->location
, "out of bounds");
211 ABORT_VARIANT_VP_VP(out_of_bounds
);
213 struct ubsan_unreachable_data
{
214 struct ubsan_source_location location
;
217 void __noreturn
__ubsan_handle_builtin_unreachable(void *data_raw
)
219 struct ubsan_unreachable_data
*data
=
220 (struct ubsan_unreachable_data
*)data_raw
;
221 ubsan_abort(&data
->location
, "reached unreachable");
224 void __noreturn
__ubsan_handle_missing_return(void *data_raw
)
226 const struct ubsan_unreachable_data
*data
=
227 (struct ubsan_unreachable_data
*)data_raw
;
228 ubsan_abort(&data
->location
, "missing return");
231 struct ubsan_vla_bound_data
{
232 struct ubsan_source_location location
;
233 struct ubsan_type_descriptor
*type
;
236 void __ubsan_handle_vla_bound_not_positive(void *data_raw
, void *bound_raw
)
238 const struct ubsan_vla_bound_data
*data
239 = (struct ubsan_vla_bound_data
*)data_raw
;
240 ubsan_value_handle_t bound
= (ubsan_value_handle_t
)bound_raw
;
242 ubsan_abort(&data
->location
, "negative variable array length");
245 ABORT_VARIANT_VP_VP(vla_bound_not_positive
);
247 struct ubsan_float_cast_overflow_data
{
248 struct ubsan_source_location location
;
249 struct ubsan_type_descriptor
*from_type
;
250 struct ubsan_type_descriptor
*to_type
;
253 void __ubsan_handle_float_cast_overflow(void *data_raw
, void *from_raw
)
255 struct ubsan_float_cast_overflow_data
*data
=
256 (struct ubsan_float_cast_overflow_data
*)data_raw
;
257 ubsan_value_handle_t from
= (ubsan_value_handle_t
)from_raw
;
259 ubsan_abort(&data
->location
, "float cast overflow");
262 ABORT_VARIANT_VP_VP(float_cast_overflow
);
264 struct ubsan_invalid_value_data
{
265 struct ubsan_source_location location
;
266 struct ubsan_type_descriptor
*type
;
269 void __ubsan_handle_load_invalid_value(void *data_raw
, void *value_raw
)
271 const struct ubsan_invalid_value_data
*data
=
272 (struct ubsan_invalid_value_data
*)data_raw
;
273 ubsan_value_handle_t value
= (ubsan_value_handle_t
)value_raw
;
275 ubsan_abort(&data
->location
, "invalid value load");
278 ABORT_VARIANT_VP_VP(load_invalid_value
);
280 struct ubsan_function_type_mismatch_data
{
281 struct ubsan_source_location location
;
282 struct ubsan_type_descriptor
*type
;
285 void __ubsan_handle_function_type_mismatch(void *data_raw
, void *value_raw
)
287 const struct ubsan_function_type_mismatch_data
*data
=
288 (struct ubsan_function_type_mismatch_data
*)data_raw
;
289 ubsan_value_handle_t value
= (ubsan_value_handle_t
)value_raw
;
291 ubsan_abort(&data
->location
, "function type mismatch");
294 ABORT_VARIANT_VP_VP(function_type_mismatch
);
296 struct ubsan_nonnull_return_data
{
297 struct ubsan_source_location location
;
298 struct ubsan_source_location attr_location
;
301 void __ubsan_handle_nonnull_return(void *data_raw
)
303 const struct ubsan_nonnull_return_data
*data
=
304 (struct ubsan_nonnull_return_data
*)data_raw
;
305 ubsan_abort(&data
->location
, "null return");
308 ABORT_VARIANT_VP(nonnull_return
);
310 struct ubsan_nonnull_arg_data
{
311 struct ubsan_source_location location
;
312 struct ubsan_source_location attr_location
;
316 * TODO: GCC's libubsan does not have the second parameter, but its builtin
317 * somehow has it and conflict if we don't match it.
319 void __ubsan_handle_nonnull_arg(void *data_raw
, intptr_t index_raw
)
321 const struct ubsan_nonnull_arg_data
*data
=
322 (struct ubsan_nonnull_arg_data
*)data_raw
;
323 ubsan_value_handle_t index
= (ubsan_value_handle_t
)index_raw
;
325 ubsan_abort(&data
->location
, "null argument");
328 ABORT_VARIANT_VP_IP(nonnull_arg
);
330 struct ubsan_cfi_bad_icall_data
{
331 struct ubsan_source_location location
;
332 struct ubsan_type_descriptor
*type
;
335 void __ubsan_handle_cfi_bad_icall(void *data_raw
, void *value_raw
)
337 static const char *abort_text
338 = "cfi: integrity failure during indirect call.";
339 const struct ubsan_cfi_bad_icall_data
*data
=
340 (struct ubsan_cfi_bad_icall_data
*)data_raw
;
341 ubsan_value_handle_t value
= (ubsan_value_handle_t
)value_raw
;
343 ubsan_abort(&data
->location
, abort_text
);
346 ABORT_VARIANT_VP_VP(cfi_bad_icall
);