2 * Copyright (c) 2014, 2015 Jonas 'Sortie' Termansen.
4 * Permission to use, copy, modify, and distribute this software for any
5 * purpose with or without fee is hereby granted, provided that the above
6 * copyright notice and this permission notice appear in all copies.
8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 * Undefined behavior sanitizer runtime support.
20 * https://gitlab.com/sortix/sortix/raw/master/libc/ubsan/ubsan.c
24 #include <console/console.h>
26 struct ubsan_source_location
{
32 struct ubsan_type_descriptor
{
38 typedef uintptr_t ubsan_value_handle_t
;
41 * Keep the compiler happy -- it wants prototypes but nobody
42 * except the compiler should be touching these functions.
44 #pragma GCC diagnostic ignored "-Wmissing-prototypes"
46 __attribute__((noreturn
))
47 static void ubsan_abort(const struct ubsan_source_location
*location
,
48 const char *violation
) {
49 static const struct ubsan_source_location unknown_location
= {
55 if (!location
|| !location
->filename
)
56 location
= &unknown_location
;
57 printk(BIOS_ERR
, "%s %s:%lu:%lu\n", violation
, location
->filename
,
58 (unsigned long int)location
->line
,
59 (unsigned long int)location
->column
);
60 die("ubsan: unrecoverable error.\n");
63 #define ABORT_VARIANT(name, params, call) \
64 __attribute__((noreturn)) \
65 void __ubsan_handle_##name##_abort params; \
66 __attribute__((noreturn)) \
67 void __ubsan_handle_##name##_abort params { \
68 __ubsan_handle_##name call; \
69 __builtin_unreachable(); \
72 #define ABORT_VARIANT_VP(name) \
73 ABORT_VARIANT(name, (void *a), (a))
74 #define ABORT_VARIANT_VP_VP(name) \
75 ABORT_VARIANT(name, (void *a, void *b), (a, b))
76 #define ABORT_VARIANT_VP_IP(name) \
77 ABORT_VARIANT(name, (void *a, intptr_t b), (a, b))
78 #define ABORT_VARIANT_VP_VP_VP(name) \
79 ABORT_VARIANT(name, (void *a, void *b, void *c), (a, b, c))
81 struct ubsan_type_mismatch_data
{
82 struct ubsan_source_location location
;
83 struct ubsan_type_descriptor
*type
;
85 unsigned char type_check_kind
;
88 void __ubsan_handle_type_mismatch(void *data_raw
, void *pointer_raw
)
90 const struct ubsan_type_mismatch_data
*data
=
91 (struct ubsan_type_mismatch_data
*)data_raw
;
92 ubsan_value_handle_t pointer
= (ubsan_value_handle_t
)pointer_raw
;
93 const char *violation
= "type mismatch";
95 violation
= "null pointer access";
96 else if (data
->alignment
&& (pointer
& (data
->alignment
- 1)))
97 violation
= "unaligned access";
98 ubsan_abort(&data
->location
, violation
);
101 ABORT_VARIANT_VP_VP(type_mismatch
);
103 struct ubsan_overflow_data
{
104 struct ubsan_source_location location
;
105 struct ubsan_type_descriptor
*type
;
108 void __ubsan_handle_add_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
, "addition overflow");
120 ABORT_VARIANT_VP_VP_VP(add_overflow
);
122 void __ubsan_handle_sub_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
, "subtraction overflow");
134 ABORT_VARIANT_VP_VP_VP(sub_overflow
);
136 void __ubsan_handle_mul_overflow(void *data_raw
, void *lhs_raw
,
139 const struct ubsan_overflow_data
*data
140 = (struct ubsan_overflow_data
*)data_raw
;
141 ubsan_value_handle_t lhs
= (ubsan_value_handle_t
)lhs_raw
;
142 ubsan_value_handle_t rhs
= (ubsan_value_handle_t
)rhs_raw
;
145 ubsan_abort(&data
->location
, "multiplication overflow");
148 ABORT_VARIANT_VP_VP_VP(mul_overflow
);
150 void __ubsan_handle_negate_overflow(void *data_raw
, void *old_value_raw
)
152 const struct ubsan_overflow_data
*data
153 = (struct ubsan_overflow_data
*)data_raw
;
154 ubsan_value_handle_t old_value
155 = (ubsan_value_handle_t
)old_value_raw
;
157 ubsan_abort(&data
->location
, "negation overflow");
160 ABORT_VARIANT_VP_VP(negate_overflow
);
162 void __ubsan_handle_divrem_overflow(void *data_raw
, void *lhs_raw
,
165 const struct ubsan_overflow_data
*data
166 = (struct ubsan_overflow_data
*)data_raw
;
167 ubsan_value_handle_t lhs
= (ubsan_value_handle_t
)lhs_raw
;
168 ubsan_value_handle_t rhs
= (ubsan_value_handle_t
)rhs_raw
;
171 ubsan_abort(&data
->location
, "division remainder overflow");
174 ABORT_VARIANT_VP_VP_VP(divrem_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 __attribute__((noreturn
))
218 void __ubsan_handle_builtin_unreachable(void *data_raw
)
220 struct ubsan_unreachable_data
*data
=
221 (struct ubsan_unreachable_data
*)data_raw
;
222 ubsan_abort(&data
->location
, "reached unreachable");
225 __attribute__((noreturn
))
226 void __ubsan_handle_missing_return(void *data_raw
)
228 const struct ubsan_unreachable_data
*data
=
229 (struct ubsan_unreachable_data
*)data_raw
;
230 ubsan_abort(&data
->location
, "missing return");
233 struct ubsan_vla_bound_data
{
234 struct ubsan_source_location location
;
235 struct ubsan_type_descriptor
*type
;
238 void __ubsan_handle_vla_bound_not_positive(void *data_raw
, void *bound_raw
)
240 const struct ubsan_vla_bound_data
*data
241 = (struct ubsan_vla_bound_data
*)data_raw
;
242 ubsan_value_handle_t bound
= (ubsan_value_handle_t
)bound_raw
;
244 ubsan_abort(&data
->location
, "negative variable array length");
247 ABORT_VARIANT_VP_VP(vla_bound_not_positive
);
249 struct ubsan_float_cast_overflow_data
{
251 * TODO: Remove this GCC 5.x compatibility after switching to GCC 6.x. The
252 * GCC developers accidentally forgot the source location. Their
253 * libubsan probes to see if it looks like a path, but we don't need
254 * to maintain compatibility with multiple gcc releases. See below.
256 #if !(defined(__GNUC__) && __GNUC__ < 6)
257 struct ubsan_source_location location
;
259 struct ubsan_type_descriptor
*from_type
;
260 struct ubsan_type_descriptor
*to_type
;
263 void __ubsan_handle_float_cast_overflow(void *data_raw
, void *from_raw
)
265 struct ubsan_float_cast_overflow_data
*data
=
266 (struct ubsan_float_cast_overflow_data
*)data_raw
;
267 ubsan_value_handle_t from
= (ubsan_value_handle_t
)from_raw
;
269 #if !(defined(__GNUC__) && __GNUC__ < 6)
270 ubsan_abort(&data
->location
, "float cast overflow");
272 ubsan_abort(((void) data
, &unknown_location
), "float cast overflow");
276 ABORT_VARIANT_VP_VP(float_cast_overflow
);
278 struct ubsan_invalid_value_data
{
279 struct ubsan_source_location location
;
280 struct ubsan_type_descriptor
*type
;
283 void __ubsan_handle_load_invalid_value(void *data_raw
, void *value_raw
)
285 const struct ubsan_invalid_value_data
*data
=
286 (struct ubsan_invalid_value_data
*)data_raw
;
287 ubsan_value_handle_t value
= (ubsan_value_handle_t
)value_raw
;
289 ubsan_abort(&data
->location
, "invalid value load");
292 ABORT_VARIANT_VP_VP(load_invalid_value
);
294 struct ubsan_function_type_mismatch_data
{
295 struct ubsan_source_location location
;
296 struct ubsan_type_descriptor
*type
;
299 void __ubsan_handle_function_type_mismatch(void *data_raw
, void *value_raw
)
301 const struct ubsan_function_type_mismatch_data
*data
=
302 (struct ubsan_function_type_mismatch_data
*)data_raw
;
303 ubsan_value_handle_t value
= (ubsan_value_handle_t
)value_raw
;
305 ubsan_abort(&data
->location
, "function type mismatch");
308 ABORT_VARIANT_VP_VP(function_type_mismatch
);
310 struct ubsan_nonnull_return_data
{
311 struct ubsan_source_location location
;
312 struct ubsan_source_location attr_location
;
315 void __ubsan_handle_nonnull_return(void *data_raw
)
317 const struct ubsan_nonnull_return_data
*data
=
318 (struct ubsan_nonnull_return_data
*)data_raw
;
319 ubsan_abort(&data
->location
, "null return");
322 ABORT_VARIANT_VP(nonnull_return
);
324 struct ubsan_nonnull_arg_data
{
325 struct ubsan_source_location location
;
326 struct ubsan_source_location attr_location
;
330 * TODO: GCC's libubsan does not have the second parameter, but its builtin
331 * somehow has it and conflict if we don't match it.
333 void __ubsan_handle_nonnull_arg(void *data_raw
, intptr_t index_raw
)
335 const struct ubsan_nonnull_arg_data
*data
=
336 (struct ubsan_nonnull_arg_data
*)data_raw
;
337 ubsan_value_handle_t index
= (ubsan_value_handle_t
)index_raw
;
339 ubsan_abort(&data
->location
, "null argument");
342 ABORT_VARIANT_VP_IP(nonnull_arg
);
344 struct ubsan_cfi_bad_icall_data
{
345 struct ubsan_source_location location
;
346 struct ubsan_type_descriptor
*type
;
349 void __ubsan_handle_cfi_bad_icall(void *data_raw
, void *value_raw
)
351 static const char *abort_text
352 = "cfi: integrity failure during indirect call.";
353 const struct ubsan_cfi_bad_icall_data
*data
=
354 (struct ubsan_cfi_bad_icall_data
*)data_raw
;
355 ubsan_value_handle_t value
= (ubsan_value_handle_t
)value_raw
;
357 ubsan_abort(&data
->location
, abort_text
);
360 ABORT_VARIANT_VP_VP(cfi_bad_icall
);