Rename __attribute__((packed)) --> __packed
[coreboot.git] / src / lib / ubsan.c
blob1cd0612cf4d44f3cfe125a770af3525353b67bcc
1 /*
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.
16 * ubsan/ubsan.c
17 * Undefined behavior sanitizer runtime support.
19 * Adapted from:
20 * https://gitlab.com/sortix/sortix/raw/master/libc/ubsan/ubsan.c
23 #include <stdint.h>
24 #include <console/console.h>
26 struct ubsan_source_location {
27 const char *filename;
28 uint32_t line;
29 uint32_t column;
32 struct ubsan_type_descriptor {
33 uint16_t type_kind;
34 uint16_t type_info;
35 char type_name[];
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 = {
50 "<unknown file>",
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;
84 uintptr_t alignment;
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";
94 if (!pointer)
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,
109 void *rhs_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;
115 (void)lhs;
116 (void)rhs;
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,
123 void *rhs_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;
129 (void)lhs;
130 (void)rhs;
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,
137 void *rhs_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;
143 (void)lhs;
144 (void)rhs;
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;
156 (void) old_value;
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,
163 void *rhs_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;
169 (void)lhs;
170 (void)rhs;
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,
183 void *rhs_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;
189 (void)lhs;
190 (void)rhs;
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;
207 (void)index;
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;
243 (void)bound;
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;
258 #endif
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;
268 (void) from;
269 #if !(defined(__GNUC__) && __GNUC__ < 6)
270 ubsan_abort(&data->location, "float cast overflow");
271 #else
272 ubsan_abort(((void) data, &unknown_location), "float cast overflow");
273 #endif
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;
288 (void)value;
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;
304 (void)value;
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;
338 (void)index;
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;
356 (void)value;
357 ubsan_abort(&data->location, abort_text);
360 ABORT_VARIANT_VP_VP(cfi_bad_icall);