1 /* SPDX-License-Identifier: ISC */
3 * Undefined behavior sanitizer runtime support.
6 * https://gitlab.com/sortix/sortix/raw/master/libc/ubsan/ubsan.c
8 * Copyright (c) 2014, 2015 Jonas 'Sortie' Termansen.
13 #include <console/console.h>
15 struct ubsan_source_location
{
21 struct ubsan_type_descriptor
{
27 typedef uintptr_t ubsan_value_handle_t
;
30 * Keep the compiler happy -- it wants prototypes but nobody
31 * except the compiler should be touching these functions.
33 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
35 static void __noreturn
ubsan_abort(const struct ubsan_source_location
*location
,
36 const char *violation
) {
37 static const struct ubsan_source_location unknown_location
= {
43 if (!location
|| !location
->filename
)
44 location
= &unknown_location
;
45 printk(BIOS_ERR
, "%s %s:%lu:%lu\n", violation
, location
->filename
,
46 (unsigned long int)location
->line
,
47 (unsigned long int)location
->column
);
48 die("ubsan: unrecoverable error.\n");
51 #define ABORT_VARIANT(name, params, call) \
52 __noreturn void __ubsan_handle_##name##_abort params; \
53 __noreturn void __ubsan_handle_##name##_abort params { \
54 __ubsan_handle_##name call; \
55 __builtin_unreachable(); \
58 #define ABORT_VARIANT_VP(name) \
59 ABORT_VARIANT(name, (void *a), (a))
60 #define ABORT_VARIANT_VP_VP(name) \
61 ABORT_VARIANT(name, (void *a, void *b), (a, b))
62 #define ABORT_VARIANT_VP_IP(name) \
63 ABORT_VARIANT(name, (void *a, intptr_t b), (a, b))
64 #define ABORT_VARIANT_VP_VP_VP(name) \
65 ABORT_VARIANT(name, (void *a, void *b, void *c), (a, b, c))
67 struct ubsan_type_mismatch_data
{
68 struct ubsan_source_location location
;
69 struct ubsan_type_descriptor
*type
;
71 unsigned char type_check_kind
;
74 void __ubsan_handle_type_mismatch_v1(void *data_raw
, void *pointer_raw
)
76 const struct ubsan_type_mismatch_data
*data
=
77 (struct ubsan_type_mismatch_data
*)data_raw
;
78 ubsan_value_handle_t pointer
= (ubsan_value_handle_t
)pointer_raw
;
79 const char *violation
= "type mismatch";
81 violation
= "null pointer access";
82 else if (data
->alignment
&& (pointer
& (data
->alignment
- 1)))
83 violation
= "unaligned access";
84 ubsan_abort(&data
->location
, violation
);
87 ABORT_VARIANT_VP_VP(type_mismatch_v1
);
89 struct ubsan_overflow_data
{
90 struct ubsan_source_location location
;
91 struct ubsan_type_descriptor
*type
;
94 void __ubsan_handle_add_overflow(void *data_raw
, void *lhs_raw
,
97 const struct ubsan_overflow_data
*data
98 = (struct ubsan_overflow_data
*)data_raw
;
99 ubsan_value_handle_t lhs
= (ubsan_value_handle_t
)lhs_raw
;
100 ubsan_value_handle_t rhs
= (ubsan_value_handle_t
)rhs_raw
;
103 ubsan_abort(&data
->location
, "addition overflow");
106 ABORT_VARIANT_VP_VP_VP(add_overflow
);
108 void __ubsan_handle_sub_overflow(void *data_raw
, void *lhs_raw
,
111 const struct ubsan_overflow_data
*data
112 = (struct ubsan_overflow_data
*)data_raw
;
113 ubsan_value_handle_t lhs
= (ubsan_value_handle_t
)lhs_raw
;
114 ubsan_value_handle_t rhs
= (ubsan_value_handle_t
)rhs_raw
;
117 ubsan_abort(&data
->location
, "subtraction overflow");
120 ABORT_VARIANT_VP_VP_VP(sub_overflow
);
122 void __ubsan_handle_mul_overflow(void *data_raw
, void *lhs_raw
,
125 const struct ubsan_overflow_data
*data
126 = (struct ubsan_overflow_data
*)data_raw
;
127 ubsan_value_handle_t lhs
= (ubsan_value_handle_t
)lhs_raw
;
128 ubsan_value_handle_t rhs
= (ubsan_value_handle_t
)rhs_raw
;
131 ubsan_abort(&data
->location
, "multiplication overflow");
134 ABORT_VARIANT_VP_VP_VP(mul_overflow
);
136 void __ubsan_handle_negate_overflow(void *data_raw
, void *old_value_raw
)
138 const struct ubsan_overflow_data
*data
139 = (struct ubsan_overflow_data
*)data_raw
;
140 ubsan_value_handle_t old_value
141 = (ubsan_value_handle_t
)old_value_raw
;
143 ubsan_abort(&data
->location
, "negation overflow");
146 ABORT_VARIANT_VP_VP(negate_overflow
);
148 void __ubsan_handle_divrem_overflow(void *data_raw
, void *lhs_raw
,
151 const struct ubsan_overflow_data
*data
152 = (struct ubsan_overflow_data
*)data_raw
;
153 ubsan_value_handle_t lhs
= (ubsan_value_handle_t
)lhs_raw
;
154 ubsan_value_handle_t rhs
= (ubsan_value_handle_t
)rhs_raw
;
157 ubsan_abort(&data
->location
, "division remainder overflow");
160 ABORT_VARIANT_VP_VP_VP(divrem_overflow
);
162 struct ubsan_pointer_overflow_data
{
163 struct ubsan_source_location location
;
166 void __ubsan_handle_pointer_overflow(void *data_raw
, void *base_raw
, void *result_raw
)
168 const struct ubsan_pointer_overflow_data
*data
=
169 (struct ubsan_pointer_overflow_data
*)data_raw
;
170 ubsan_value_handle_t base
= (ubsan_value_handle_t
)base_raw
;
171 ubsan_value_handle_t result
= (ubsan_value_handle_t
)result_raw
;
174 ubsan_abort(&data
->location
, "pointer overflow");
177 ABORT_VARIANT_VP_VP_VP(pointer_overflow
);
179 struct ubsan_shift_out_of_bounds_data
{
180 struct ubsan_source_location location
;
181 struct ubsan_type_descriptor
*lhs_type
;
182 struct ubsan_type_descriptor
*rhs_type
;
185 void __ubsan_handle_shift_out_of_bounds(void *data_raw
, void *lhs_raw
,
188 const struct ubsan_shift_out_of_bounds_data
*data
=
189 (struct ubsan_shift_out_of_bounds_data
*)data_raw
;
190 ubsan_value_handle_t lhs
= (ubsan_value_handle_t
)lhs_raw
;
191 ubsan_value_handle_t rhs
= (ubsan_value_handle_t
)rhs_raw
;
194 ubsan_abort(&data
->location
, "shift out of bounds");
197 ABORT_VARIANT_VP_VP_VP(shift_out_of_bounds
);
199 struct ubsan_out_of_bounds_data
{
200 struct ubsan_source_location location
;
201 struct ubsan_type_descriptor
*array_type
;
202 struct ubsan_type_descriptor
*index_type
;
205 void __ubsan_handle_out_of_bounds(void *data_raw
, void *index_raw
)
207 const struct ubsan_out_of_bounds_data
*data
=
208 (struct ubsan_out_of_bounds_data
*)data_raw
;
209 ubsan_value_handle_t index
= (ubsan_value_handle_t
)index_raw
;
211 ubsan_abort(&data
->location
, "out of bounds");
214 ABORT_VARIANT_VP_VP(out_of_bounds
);
216 struct ubsan_unreachable_data
{
217 struct ubsan_source_location location
;
220 void __noreturn
__ubsan_handle_builtin_unreachable(void *data_raw
)
222 struct ubsan_unreachable_data
*data
=
223 (struct ubsan_unreachable_data
*)data_raw
;
224 ubsan_abort(&data
->location
, "reached unreachable");
227 void __noreturn
__ubsan_handle_missing_return(void *data_raw
)
229 const struct ubsan_unreachable_data
*data
=
230 (struct ubsan_unreachable_data
*)data_raw
;
231 ubsan_abort(&data
->location
, "missing return");
234 struct ubsan_vla_bound_data
{
235 struct ubsan_source_location location
;
236 struct ubsan_type_descriptor
*type
;
239 void __ubsan_handle_vla_bound_not_positive(void *data_raw
, void *bound_raw
)
241 const struct ubsan_vla_bound_data
*data
242 = (struct ubsan_vla_bound_data
*)data_raw
;
243 ubsan_value_handle_t bound
= (ubsan_value_handle_t
)bound_raw
;
245 ubsan_abort(&data
->location
, "negative variable array length");
248 ABORT_VARIANT_VP_VP(vla_bound_not_positive
);
250 struct ubsan_float_cast_overflow_data
{
251 struct ubsan_source_location location
;
252 struct ubsan_type_descriptor
*from_type
;
253 struct ubsan_type_descriptor
*to_type
;
256 void __ubsan_handle_float_cast_overflow(void *data_raw
, void *from_raw
)
258 struct ubsan_float_cast_overflow_data
*data
=
259 (struct ubsan_float_cast_overflow_data
*)data_raw
;
260 ubsan_value_handle_t from
= (ubsan_value_handle_t
)from_raw
;
262 ubsan_abort(&data
->location
, "float cast overflow");
265 ABORT_VARIANT_VP_VP(float_cast_overflow
);
267 struct ubsan_invalid_value_data
{
268 struct ubsan_source_location location
;
269 struct ubsan_type_descriptor
*type
;
272 void __ubsan_handle_load_invalid_value(void *data_raw
, void *value_raw
)
274 const struct ubsan_invalid_value_data
*data
=
275 (struct ubsan_invalid_value_data
*)data_raw
;
276 ubsan_value_handle_t value
= (ubsan_value_handle_t
)value_raw
;
278 ubsan_abort(&data
->location
, "invalid value load");
281 ABORT_VARIANT_VP_VP(load_invalid_value
);
283 struct ubsan_function_type_mismatch_data
{
284 struct ubsan_source_location location
;
285 struct ubsan_type_descriptor
*type
;
288 void __ubsan_handle_function_type_mismatch(void *data_raw
, void *value_raw
)
290 const struct ubsan_function_type_mismatch_data
*data
=
291 (struct ubsan_function_type_mismatch_data
*)data_raw
;
292 ubsan_value_handle_t value
= (ubsan_value_handle_t
)value_raw
;
294 ubsan_abort(&data
->location
, "function type mismatch");
297 ABORT_VARIANT_VP_VP(function_type_mismatch
);
299 struct ubsan_nonnull_return_data
{
300 struct ubsan_source_location location
;
301 struct ubsan_source_location attr_location
;
304 void __ubsan_handle_nonnull_return(void *data_raw
)
306 const struct ubsan_nonnull_return_data
*data
=
307 (struct ubsan_nonnull_return_data
*)data_raw
;
308 ubsan_abort(&data
->location
, "null return");
311 ABORT_VARIANT_VP(nonnull_return
);
313 struct ubsan_nonnull_arg_data
{
314 struct ubsan_source_location location
;
315 struct ubsan_source_location attr_location
;
319 * TODO: GCC's libubsan does not have the second parameter, but its builtin
320 * somehow has it and conflict if we don't match it.
322 void __ubsan_handle_nonnull_arg(void *data_raw
, intptr_t index_raw
)
324 const struct ubsan_nonnull_arg_data
*data
=
325 (struct ubsan_nonnull_arg_data
*)data_raw
;
326 ubsan_value_handle_t index
= (ubsan_value_handle_t
)index_raw
;
328 ubsan_abort(&data
->location
, "null argument");
331 ABORT_VARIANT_VP_IP(nonnull_arg
);
333 struct ubsan_cfi_bad_icall_data
{
334 struct ubsan_source_location location
;
335 struct ubsan_type_descriptor
*type
;
338 void __ubsan_handle_cfi_bad_icall(void *data_raw
, void *value_raw
)
340 static const char *abort_text
341 = "cfi: integrity failure during indirect call.";
342 const struct ubsan_cfi_bad_icall_data
*data
=
343 (struct ubsan_cfi_bad_icall_data
*)data_raw
;
344 ubsan_value_handle_t value
= (ubsan_value_handle_t
)value_raw
;
346 ubsan_abort(&data
->location
, abort_text
);
349 ABORT_VARIANT_VP_VP(cfi_bad_icall
);