1 /*
2 * Copyright (c) 2018-2021 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #include <stdatomic.h>
30 #include <kern/debug.h>
31 #include <kern/assert.h>
32 #include <libkern/libkern.h>
33 #include "ubsan.h"
34
35 static const uint32_t line_acquired = 0x80000000UL;
36 static const char *get_mismatch_kind(uint8_t kind);
37
38 /*
39 * A simple JSON serializer. Character quoting is not supported.
40 */
41
42 static size_t
ubsan_buf_available(const ubsan_buf_t * ub)43 ubsan_buf_available(const ubsan_buf_t *ub)
44 {
45 assert(ub->ub_buf_size >= ub->ub_written);
46 return ub->ub_buf_size - ub->ub_written;
47 }
48
49 static void
ubsan_buf_rewind(ubsan_buf_t * ub,size_t mark)50 ubsan_buf_rewind(ubsan_buf_t *ub, size_t mark)
51 {
52 assert(mark < ub->ub_buf_size);
53 ub->ub_written = mark;
54 ub->ub_buf[ub->ub_written] = '\0';
55 }
56
57 static void
ubsan_json_log_ap(ubsan_buf_t * ub,const char * fmt,va_list ap)58 ubsan_json_log_ap(ubsan_buf_t *ub, const char *fmt, va_list ap)
59 {
60 const size_t available = ubsan_buf_available(ub);
61
62 if (available == 0) {
63 return;
64 }
65
66 int n = vsnprintf(&ub->ub_buf[ub->ub_written], available, fmt, ap);
67 assert(n >= 0);
68
69 if (n <= available) {
70 ub->ub_written += n;
71 } else {
72 ub->ub_err = true;
73 ub->ub_written = ub->ub_buf_size;
74 }
75 }
76
77 static void
ubsan_json_log(ubsan_buf_t * ub,const char * fmt,...)78 ubsan_json_log(ubsan_buf_t *ub, const char *fmt, ...)
79 {
80 va_list ap;
81
82 va_start(ap, fmt);
83 ubsan_json_log_ap(ub, fmt, ap);
84 va_end(ap);
85 }
86
87 static bool
ubsan_json_struct_is_empty(const ubsan_buf_t * ub)88 ubsan_json_struct_is_empty(const ubsan_buf_t *ub)
89 {
90 if (ub->ub_written == 0) {
91 return true;
92 }
93 char prev_c = ub->ub_buf[ub->ub_written - 1];
94 return prev_c == '{' || prev_c == '[';
95 }
96
97 static int64_t
signed_num(size_t bit_width,uint64_t value)98 signed_num(size_t bit_width, uint64_t value)
99 {
100 switch (bit_width / 8) {
101 case sizeof(int8_t):
102 return (int8_t)value;
103 case sizeof(int16_t):
104 return (int16_t)value;
105 case sizeof(int32_t):
106 return (int32_t)value;
107 case sizeof(int64_t):
108 return (int64_t)value;
109 default:
110 panic("Invalid bit width %lu", bit_width);
111 }
112 }
113
114 static void
ubsan_json_struct_begin(ubsan_buf_t * ub,const char * section_name,bool is_array)115 ubsan_json_struct_begin(ubsan_buf_t *ub, const char *section_name, bool is_array)
116 {
117 if (!ubsan_json_struct_is_empty(ub)) {
118 ubsan_json_log(ub, ",");
119 }
120
121 if (section_name) {
122 assert(section_name[0] != '\0');
123 ubsan_json_log(ub, "\"%s\":", section_name);
124 }
125
126 ubsan_json_log(ub, is_array ? "[" : "{");
127
128 if (ubsan_buf_available(ub) == 0 || ub->ub_err) {
129 ub->ub_err = true;
130 return;
131 }
132 ub->ub_buf_size--; // Reserve for ] or }
133 }
134
135 static void
ubsan_json_struct_end(ubsan_buf_t * ub,bool is_array)136 ubsan_json_struct_end(ubsan_buf_t *ub, bool is_array)
137 {
138 ub->ub_buf_size++; // Reserved for ] or }
139 assert(ub->ub_buf[ub->ub_written - 1] != ',');
140 ubsan_json_log(ub, is_array ? "]" : "}");
141 }
142
143 static void
ubsan_json_obj_begin(ubsan_buf_t * ub,const char * section_name)144 ubsan_json_obj_begin(ubsan_buf_t *ub, const char *section_name)
145 {
146 ubsan_json_struct_begin(ub, section_name, false);
147 }
148
149 static void
ubsan_json_obj_end(ubsan_buf_t * ub)150 ubsan_json_obj_end(ubsan_buf_t *ub)
151 {
152 ubsan_json_struct_end(ub, false);
153 }
154
155 static void
ubsan_json_array_begin(ubsan_buf_t * ub,const char * section_name)156 ubsan_json_array_begin(ubsan_buf_t *ub, const char *section_name)
157 {
158 ubsan_json_struct_begin(ub, section_name, true);
159 }
160
161 static void
ubsan_json_array_end(ubsan_buf_t * ub)162 ubsan_json_array_end(ubsan_buf_t *ub)
163 {
164 ubsan_json_struct_end(ub, true);
165 }
166
167 static void
ubsan_json_kv_ap(ubsan_buf_t * ub,bool quote,const char * key,const char * fmt,va_list ap)168 ubsan_json_kv_ap(ubsan_buf_t *ub, bool quote, const char *key, const char *fmt, va_list ap)
169 {
170 assert(key && key[0] != '\0');
171 assert(fmt && fmt[0] != '\0');
172
173 if (!ubsan_json_struct_is_empty(ub)) {
174 ubsan_json_log(ub, ",");
175 }
176
177 ubsan_json_log(ub, "\"%s\":", key);
178
179 if (quote) {
180 ubsan_json_log(ub, "\"");
181 ubsan_json_log_ap(ub, fmt, ap);
182 ubsan_json_log(ub, "\"");
183 } else {
184 ubsan_json_log_ap(ub, fmt, ap);
185 }
186 }
187
188 static void
ubsan_json_kv(ubsan_buf_t * ub,int quote,const char * key,const char * fmt,...)189 ubsan_json_kv(ubsan_buf_t *ub, int quote, const char *key, const char *fmt, ...)
190 {
191 va_list ap;
192
193 va_start(ap, fmt);
194 ubsan_json_kv_ap(ub, quote, key, fmt, ap);
195 va_end(ap);
196 }
197
198 static void
ubsan_json_fmt(ubsan_buf_t * ub,const char * key,const char * fmt,...)199 ubsan_json_fmt(ubsan_buf_t *ub, const char *key, const char *fmt, ...)
200 {
201 va_list ap;
202
203 va_start(ap, fmt);
204 ubsan_json_kv_ap(ub, true, key, fmt, ap);
205 va_end(ap);
206 }
207
208 static void
ubsan_json_unum(ubsan_buf_t * ub,const char * key,uint64_t number)209 ubsan_json_unum(ubsan_buf_t *ub, const char *key, uint64_t number)
210 {
211 ubsan_json_kv(ub, false, key, "%llu", number);
212 }
213
214 static void
ubsan_json_snum(ubsan_buf_t * ub,const char * key,int64_t number)215 ubsan_json_snum(ubsan_buf_t *ub, const char *key, int64_t number)
216 {
217 ubsan_json_kv(ub, false, key, "%lld", number);
218 }
219
220 static void
ubsan_json_num(ubsan_buf_t * ub,const char * key,struct san_type_desc * std,uint64_t value)221 ubsan_json_num(ubsan_buf_t *ub, const char *key, struct san_type_desc *std, uint64_t value)
222 {
223 if (std->issigned) {
224 ubsan_json_snum(ub, key, signed_num(1 << std->width, value));
225 } else {
226 ubsan_json_unum(ub, key, value);
227 }
228 }
229
230 static void
ubsan_json_bool(ubsan_buf_t * ub,const char * key,bool value)231 ubsan_json_bool(ubsan_buf_t *ub, const char *key, bool value)
232 {
233 ubsan_json_kv(ub, false, key, "%s", value ? "true" : "false");
234 }
235
236 static void
ubsan_json_str(ubsan_buf_t * ub,const char * key,const char * string)237 ubsan_json_str(ubsan_buf_t *ub, const char *key, const char *string)
238 {
239 const char *str_value = string;
240 bool quote = true;
241
242 if (!str_value) {
243 str_value = "null";
244 quote = false;
245 }
246
247 ubsan_json_kv(ub, quote, key, "%s", str_value);
248 }
249
250 static void
ubsan_json_loc(ubsan_buf_t * ub,const char * desc,struct san_src_loc * loc)251 ubsan_json_loc(ubsan_buf_t *ub, const char *desc, struct san_src_loc *loc)
252 {
253 ubsan_json_obj_begin(ub, desc);
254
255 ubsan_json_str(ub, "file", loc->filename);
256 ubsan_json_unum(ub, "line", loc->line & ~line_acquired);
257 ubsan_json_unum(ub, "column", loc->col);
258
259 ubsan_json_obj_end(ub);
260 }
261
262 static void
ubsan_json_type(ubsan_buf_t * ub,const char * section,uint64_t * value,struct san_type_desc * std)263 ubsan_json_type(ubsan_buf_t *ub, const char *section, uint64_t *value, struct san_type_desc *std)
264 {
265 if (section) {
266 ubsan_json_obj_begin(ub, section);
267 }
268
269 if (value) {
270 ubsan_json_num(ub, "value", std, *value);
271 }
272 ubsan_json_str(ub, "type", std->name);
273 ubsan_json_bool(ub, "signed", std->issigned);
274 ubsan_json_unum(ub, "width", 1 << std->width);
275
276 if (section) {
277 ubsan_json_obj_end(ub);
278 }
279 }
280
281 /*
282 * return true for the first visit to this loc, false every subsequent time
283 */
284 static bool
ubsan_loc_acquire(struct san_src_loc * loc)285 ubsan_loc_acquire(struct san_src_loc *loc)
286 {
287 uint32_t line = loc->line;
288 if (line & line_acquired) {
289 return false;
290 }
291 uint32_t acq = line | line_acquired;
292 return atomic_compare_exchange_strong((_Atomic uint32_t *)&loc->line, &line, acq);
293 }
294
295 static void
format_overflow(ubsan_violation_t * v,ubsan_buf_t * ub)296 format_overflow(ubsan_violation_t *v, ubsan_buf_t *ub)
297 {
298 static const char *const overflow_str[] = {
299 NULL,
300 "add",
301 "sub",
302 "mul",
303 "divrem",
304 "negate",
305 NULL
306 };
307 struct san_type_desc *ty = v->overflow->ty;
308
309 ubsan_json_fmt(ub, "problem", "type overflow");
310 ubsan_json_str(ub, "op", overflow_str[v->ubsan_type]);
311 ubsan_json_type(ub, "lhs", &v->lhs, ty);
312 ubsan_json_unum(ub, "rhs", v->rhs);
313 }
314
315 static void
format_shift(ubsan_violation_t * v,ubsan_buf_t * ub)316 format_shift(ubsan_violation_t *v, ubsan_buf_t *ub)
317 {
318 ubsan_json_str(ub, "problem", "bad shift");
319 ubsan_json_type(ub, "lhs", &v->lhs, v->shift->lhs_t);
320 ubsan_json_type(ub, "rhs", &v->rhs, v->shift->rhs_t);
321 }
322
323 static const char *
get_mismatch_kind(uint8_t kind)324 get_mismatch_kind(uint8_t kind)
325 {
326 static const char *const mismatch_kinds[] = {
327 "load of",
328 "store to",
329 "reference binding to",
330 "member access within",
331 "member call on",
332 "constructor call on",
333 "downcast of",
334 "downcast of",
335 "upcast of",
336 "cast to virtual base of",
337 "_Nonnull binding to"
338 };
339
340 return (kind < (sizeof(mismatch_kinds) / sizeof(mismatch_kinds[0])))
341 ? mismatch_kinds[kind]
342 : "some";
343 }
344
345 static void
format_type_mismatch(ubsan_violation_t * v,ubsan_buf_t * ub)346 format_type_mismatch(ubsan_violation_t *v, ubsan_buf_t *ub)
347 {
348 const char *kind = get_mismatch_kind(v->align->kind);
349 const size_t alignment = 1 << v->align->align;
350 uintptr_t addr = (uintptr_t)v->lhs;
351
352 ubsan_json_str(ub, "problem", "type mismatch");
353
354 if (!addr) {
355 ubsan_json_fmt(ub, "kind", "%s NULL pointer", kind);
356 ubsan_json_str(ub, "type", v->align->ty->name);
357 return;
358 }
359
360 if (alignment && (addr & (alignment - 1))) {
361 ubsan_json_fmt(ub, "kind", "%s misaligned", kind);
362 ubsan_json_unum(ub, "required", alignment);
363 } else {
364 ubsan_json_fmt(ub, "kind", "%s insufficient size", kind);
365 }
366 ubsan_json_type(ub, NULL, (uint64_t *)&addr, v->align->ty);
367 }
368
369 static void
format_oob(ubsan_violation_t * v,ubsan_buf_t * ub)370 format_oob(ubsan_violation_t *v, ubsan_buf_t *ub)
371 {
372 ubsan_json_str(ub, "problem", "OOB array indexing");
373 ubsan_json_type(ub, "array", NULL, v->oob->array_ty);
374 ubsan_json_type(ub, "idx", &v->lhs, v->oob->index_ty);
375 }
376
377 static void
format_nullability_arg(ubsan_violation_t * v,ubsan_buf_t * ub)378 format_nullability_arg(ubsan_violation_t *v, ubsan_buf_t *ub)
379 {
380 struct ubsan_nullability_arg_desc *data = v->nonnull_arg;
381
382 ubsan_json_str(ub, "problem", "nullability");
383 ubsan_json_snum(ub, "arg", data->arg_index);
384 ubsan_json_str(ub, "attr", v->lhs ? "nonnull" : "_Nonnull");
385 ubsan_json_loc(ub, "declared", &data->attr_loc);
386 }
387
388 static void
format_nonnull_return(ubsan_violation_t * v,ubsan_buf_t * ub)389 format_nonnull_return(ubsan_violation_t *v, ubsan_buf_t *ub)
390 {
391 ubsan_json_str(ub, "problem", "nonnull return");
392 ubsan_json_str(ub, "attr", v->lhs ? "returns_nonnull" : "_Nonnull");
393 ubsan_json_loc(ub, "declared", (struct san_src_loc *)v->rhs);
394 }
395
396 static void
format_load_invalid_value(ubsan_violation_t * v,ubsan_buf_t * ub)397 format_load_invalid_value(ubsan_violation_t *v, ubsan_buf_t *ub)
398 {
399 ubsan_json_str(ub, "problem", "invalid load");
400 ubsan_json_type(ub, NULL, &v->lhs, v->invalid->type);
401 }
402
403 static void
format_missing_return(ubsan_violation_t * v __unused,ubsan_buf_t * ub)404 format_missing_return(ubsan_violation_t *v __unused, ubsan_buf_t *ub)
405 {
406 ubsan_json_str(ub, "problem", "missing return");
407 }
408
409 static void
format_float_cast_overflow(ubsan_violation_t * v,ubsan_buf_t * ub)410 format_float_cast_overflow(ubsan_violation_t *v, ubsan_buf_t *ub)
411 {
412 struct ubsan_float_desc *data = v->flt;
413 /*
414 * Cannot print out offending value (e.g. using %A, %f and so on) as kernel logging
415 * does not support float types (yet).
416 */
417 ubsan_json_str(ub, "problem", "cast overflow");
418 ubsan_json_str(ub, "src", data->type_from->name);
419 ubsan_json_str(ub, "to", data->type_to->name);
420 }
421
422 static const char *
get_implicit_conv_type(unsigned char kind)423 get_implicit_conv_type(unsigned char kind)
424 {
425 static const char * const conv_types[] = {
426 "integer truncation",
427 "unsigned integer truncation",
428 "signed integer truncation",
429 "integer sign change",
430 "signed integer truncation or sign change"
431 };
432 static const size_t conv_types_cnt = sizeof(conv_types) / sizeof(conv_types[0]);
433
434 return kind < conv_types_cnt ? conv_types[kind] : "unknown implicit integer conversion";
435 }
436
437 static void
format_implicit_conversion(ubsan_violation_t * v,ubsan_buf_t * ub)438 format_implicit_conversion(ubsan_violation_t *v, ubsan_buf_t *ub)
439 {
440 struct ubsan_implicit_conv_desc *data = v->implicit;
441
442 ubsan_json_str(ub, "problem", get_implicit_conv_type(data->kind));
443 ubsan_json_type(ub, "lhs", &v->lhs, data->type_to);
444 ubsan_json_type(ub, "rhs", &v->rhs, data->type_from);
445 }
446
447 static void
format_function_type_mismatch(ubsan_violation_t * v,ubsan_buf_t * ub)448 format_function_type_mismatch(ubsan_violation_t *v, ubsan_buf_t *ub)
449 {
450 ubsan_json_str(ub, "problem", "bad indirect call");
451 ubsan_json_type(ub, NULL, &v->lhs, v->func_mismatch->type);
452 }
453
454 static void
format_vla_bound_not_positive(ubsan_violation_t * v,ubsan_buf_t * ub)455 format_vla_bound_not_positive(ubsan_violation_t *v, ubsan_buf_t *ub)
456 {
457 ubsan_json_str(ub, "problem", "non-positive VLA bound");
458 ubsan_json_type(ub, NULL, &v->lhs, v->vla_bound->type);
459 }
460
461 static void
format_invalid_builtin(ubsan_violation_t * v,ubsan_buf_t * ub)462 format_invalid_builtin(ubsan_violation_t *v, ubsan_buf_t *ub)
463 {
464 ubsan_json_str(ub, "problem", "invalid builtin");
465 ubsan_json_str(ub, "op", v->invalid_builtin->kind == 0 ? "ctz()" : "clz()");
466 }
467
468 static void
format_ptr_overflow(ubsan_violation_t * v,ubsan_buf_t * ub)469 format_ptr_overflow(ubsan_violation_t *v, ubsan_buf_t *ub)
470 {
471 ubsan_json_str(ub, "problem", "pointer overflow");
472 ubsan_json_unum(ub, "lhs", v->lhs);
473 ubsan_json_unum(ub, "rhs", v->rhs);
474 }
475
476 static void
format_unreachable(ubsan_buf_t * ub)477 format_unreachable(ubsan_buf_t *ub)
478 {
479 ubsan_json_str(ub, "problem", "unreachable");
480 }
481
482 void
ubsan_json_init(ubsan_buf_t * ub,char * buf,size_t bufsize)483 ubsan_json_init(ubsan_buf_t *ub, char *buf, size_t bufsize)
484 {
485 assert(bufsize > sizeof("{\"count\":9999,\"violations\":[]}"));
486 assert(buf);
487
488 ub->ub_buf = buf;
489 ub->ub_buf_size = bufsize;
490 ub->ub_written = 0;
491 ub->ub_err = false;
492 }
493
494 void
ubsan_json_begin(ubsan_buf_t * ub,size_t nentries)495 ubsan_json_begin(ubsan_buf_t *ub, size_t nentries)
496 {
497 ub->ub_buf_size--; // for '\0'
498
499 ubsan_json_obj_begin(ub, NULL);
500 ubsan_json_unum(ub, "count", nentries);
501 ubsan_json_array_begin(ub, "violations");
502
503 assert(!ub->ub_err);
504 }
505
506 size_t
ubsan_json_finish(ubsan_buf_t * ub)507 ubsan_json_finish(ubsan_buf_t *ub)
508 {
509 ub->ub_buf_size++; // for '\0'
510 ub->ub_err = false;
511
512 ubsan_json_array_end(ub);
513 ubsan_json_obj_end(ub);
514
515 assert(!ub->ub_err);
516 return ub->ub_written;
517 }
518
519 bool
ubsan_json_format(ubsan_violation_t * v,ubsan_buf_t * ub)520 ubsan_json_format(ubsan_violation_t *v, ubsan_buf_t *ub)
521 {
522 const size_t mark = ub->ub_written;
523
524 ubsan_json_obj_begin(ub, NULL);
525
526 switch (v->ubsan_type) {
527 case UBSAN_OVERFLOW_add ... UBSAN_OVERFLOW_negate:
528 format_overflow(v, ub);
529 break;
530 case UBSAN_UNREACHABLE:
531 format_unreachable(ub);
532 break;
533 case UBSAN_SHIFT:
534 format_shift(v, ub);
535 break;
536 case UBSAN_TYPE_MISMATCH:
537 format_type_mismatch(v, ub);
538 break;
539 case UBSAN_POINTER_OVERFLOW:
540 format_ptr_overflow(v, ub);
541 break;
542 case UBSAN_OOB:
543 format_oob(v, ub);
544 break;
545 case UBSAN_NULLABILITY_ARG:
546 format_nullability_arg(v, ub);
547 break;
548 case UBSAN_NULLABILITY_RETURN:
549 format_nonnull_return(v, ub);
550 break;
551 case UBSAN_MISSING_RETURN:
552 format_missing_return(v, ub);
553 break;
554 case UBSAN_FLOAT_CAST_OVERFLOW:
555 format_float_cast_overflow(v, ub);
556 break;
557 case UBSAN_IMPLICIT_CONVERSION:
558 format_implicit_conversion(v, ub);
559 break;
560 case UBSAN_FUNCTION_TYPE_MISMATCH:
561 format_function_type_mismatch(v, ub);
562 break;
563 case UBSAN_VLA_BOUND_NOT_POSITIVE:
564 format_vla_bound_not_positive(v, ub);
565 break;
566 case UBSAN_INVALID_BUILTIN:
567 format_invalid_builtin(v, ub);
568 break;
569 case UBSAN_LOAD_INVALID_VALUE:
570 format_load_invalid_value(v, ub);
571 break;
572 default:
573 panic("unknown violation");
574 }
575
576 ubsan_json_loc(ub, "source", v->loc);
577 ubsan_json_obj_end(ub);
578
579 if (ub->ub_err) {
580 ubsan_buf_rewind(ub, mark);
581 }
582 assert(ub->ub_buf[ub->ub_written] == '\0');
583
584 return !ub->ub_err;
585 }
586
587 enum UBFatality { Fatal, FleshWound };
588
589 static void
ubsan_handle(ubsan_violation_t * v,enum UBFatality fatality)590 ubsan_handle(ubsan_violation_t *v, enum UBFatality fatality)
591 {
592 if (!ubsan_loc_acquire(v->loc)) {
593 /* violation site already reported */
594 return;
595 }
596 ubsan_log_append(v);
597
598 if (fatality != Fatal) {
599 return;
600 }
601
602 static char buf[512] = { 0 };
603 ubsan_buf_t ubsan_buf;
604
605 ubsan_json_init(&ubsan_buf, buf, sizeof(buf));
606
607 if (ubsan_json_format(v, &ubsan_buf)) {
608 printf("UBSan: %s", buf);
609 }
610 }
611
612 void
__ubsan_handle_builtin_unreachable(struct ubsan_unreachable_desc * desc)613 __ubsan_handle_builtin_unreachable(struct ubsan_unreachable_desc *desc)
614 {
615 ubsan_violation_t v = { UBSAN_UNREACHABLE, 0, 0, .unreachable = desc, &desc->loc };
616 ubsan_handle(&v, Fatal);
617 }
618
619 void
__ubsan_handle_shift_out_of_bounds(struct ubsan_shift_desc * desc,uint64_t lhs,uint64_t rhs)620 __ubsan_handle_shift_out_of_bounds(struct ubsan_shift_desc *desc, uint64_t lhs, uint64_t rhs)
621 {
622 ubsan_violation_t v = { UBSAN_SHIFT, lhs, rhs, .shift = desc, &desc->loc };
623 ubsan_handle(&v, FleshWound);
624 }
625
626 void
__ubsan_handle_shift_out_of_bounds_abort(struct ubsan_shift_desc * desc,uint64_t lhs,uint64_t rhs)627 __ubsan_handle_shift_out_of_bounds_abort(struct ubsan_shift_desc *desc, uint64_t lhs, uint64_t rhs)
628 {
629 ubsan_violation_t v = { UBSAN_SHIFT, lhs, rhs, .shift = desc, &desc->loc };
630 ubsan_handle(&v, Fatal);
631 }
632
633 #define DEFINE_OVERFLOW(op) \
634 void __ubsan_handle_##op##_overflow(struct ubsan_overflow_desc *desc, uint64_t lhs, uint64_t rhs) { \
635 ubsan_violation_t v = { UBSAN_OVERFLOW_##op, lhs, rhs, .overflow = desc, &desc->loc }; \
636 ubsan_handle(&v, FleshWound); \
637 } \
638 void __ubsan_handle_##op##_overflow_abort(struct ubsan_overflow_desc *desc, uint64_t lhs, uint64_t rhs) { \
639 ubsan_violation_t v = { UBSAN_OVERFLOW_##op, lhs, rhs, .overflow = desc, &desc->loc }; \
640 ubsan_handle(&v, Fatal); \
641 }
642
643 DEFINE_OVERFLOW(add)
DEFINE_OVERFLOW(sub)644 DEFINE_OVERFLOW(sub)
645 DEFINE_OVERFLOW(mul)
646 DEFINE_OVERFLOW(divrem)
647 DEFINE_OVERFLOW(negate)
648
649 void
650 __ubsan_handle_type_mismatch_v1(struct ubsan_align_desc *desc, uint64_t val)
651 {
652 ubsan_violation_t v = { UBSAN_TYPE_MISMATCH, val, 0, .align = desc, &desc->loc };
653 ubsan_handle(&v, FleshWound);
654 }
655
656 void
__ubsan_handle_type_mismatch_v1_abort(struct ubsan_align_desc * desc,uint64_t val)657 __ubsan_handle_type_mismatch_v1_abort(struct ubsan_align_desc *desc, uint64_t val)
658 {
659 ubsan_violation_t v = { UBSAN_TYPE_MISMATCH, val, 0, .align = desc, &desc->loc };
660 ubsan_handle(&v, Fatal);
661 }
662
663 void
__ubsan_handle_pointer_overflow(struct ubsan_ptroverflow_desc * desc,uint64_t before,uint64_t after)664 __ubsan_handle_pointer_overflow(struct ubsan_ptroverflow_desc *desc, uint64_t before, uint64_t after)
665 {
666 ubsan_violation_t v = { UBSAN_POINTER_OVERFLOW, before, after, .ptroverflow = desc, &desc->loc };
667 ubsan_handle(&v, FleshWound);
668 }
669
670 void
__ubsan_handle_pointer_overflow_abort(struct ubsan_ptroverflow_desc * desc,uint64_t before,uint64_t after)671 __ubsan_handle_pointer_overflow_abort(struct ubsan_ptroverflow_desc *desc, uint64_t before, uint64_t after)
672 {
673 ubsan_violation_t v = { UBSAN_POINTER_OVERFLOW, before, after, .ptroverflow = desc, &desc->loc };
674 ubsan_handle(&v, Fatal);
675 }
676
677 void
__ubsan_handle_out_of_bounds(struct ubsan_oob_desc * desc,uint64_t idx)678 __ubsan_handle_out_of_bounds(struct ubsan_oob_desc *desc, uint64_t idx)
679 {
680 ubsan_violation_t v = { UBSAN_OOB, idx, 0, .oob = desc, &desc->loc };
681 ubsan_handle(&v, FleshWound);
682 }
683
684 void
__ubsan_handle_out_of_bounds_abort(struct ubsan_oob_desc * desc,uint64_t idx)685 __ubsan_handle_out_of_bounds_abort(struct ubsan_oob_desc *desc, uint64_t idx)
686 {
687 ubsan_violation_t v = { UBSAN_OOB, idx, 0, .oob = desc, &desc->loc };
688 ubsan_handle(&v, Fatal);
689 }
690
691 void
__ubsan_handle_nullability_arg(struct ubsan_nullability_arg_desc * desc)692 __ubsan_handle_nullability_arg(struct ubsan_nullability_arg_desc *desc)
693 {
694 ubsan_violation_t v = { UBSAN_NULLABILITY_ARG, 0, 0, .nonnull_arg = desc, &desc->loc };
695 ubsan_handle(&v, FleshWound);
696 }
697
698 void
__ubsan_handle_nullability_arg_abort(struct ubsan_nullability_arg_desc * desc)699 __ubsan_handle_nullability_arg_abort(struct ubsan_nullability_arg_desc *desc)
700 {
701 ubsan_violation_t v = { UBSAN_NULLABILITY_ARG, 0, 0, .nonnull_arg = desc, &desc->loc };
702 ubsan_handle(&v, Fatal);
703 }
704
705 void
__ubsan_handle_nonnull_arg(struct ubsan_nullability_arg_desc * desc)706 __ubsan_handle_nonnull_arg(struct ubsan_nullability_arg_desc *desc)
707 {
708 ubsan_violation_t v = { UBSAN_NULLABILITY_ARG, 1, 0, .nonnull_arg = desc, &desc->loc };
709 ubsan_handle(&v, FleshWound);
710 }
711
712 void
__ubsan_handle_nonnull_arg_abort(struct ubsan_nullability_arg_desc * desc)713 __ubsan_handle_nonnull_arg_abort(struct ubsan_nullability_arg_desc *desc)
714 {
715 ubsan_violation_t v = { UBSAN_NULLABILITY_ARG, 1, 0, .nonnull_arg = desc, &desc->loc };
716 ubsan_handle(&v, Fatal);
717 }
718
719 void
__ubsan_handle_nullability_return_v1(struct ubsan_nullability_ret_desc * desc,uint64_t declaration)720 __ubsan_handle_nullability_return_v1(struct ubsan_nullability_ret_desc *desc, uint64_t declaration)
721 {
722 ubsan_violation_t v = { UBSAN_NULLABILITY_RETURN, 0, (uint64_t)&desc->loc, .nonnull_ret = desc, (struct san_src_loc *)declaration };
723 ubsan_handle(&v, FleshWound);
724 }
725
726 void
__ubsan_handle_nullability_return_v1_abort(struct ubsan_nullability_ret_desc * desc,uint64_t declaration)727 __ubsan_handle_nullability_return_v1_abort(struct ubsan_nullability_ret_desc *desc, uint64_t declaration)
728 {
729 ubsan_violation_t v = { UBSAN_NULLABILITY_RETURN, 0, (uint64_t)&desc->loc, .nonnull_ret = desc, (struct san_src_loc *)declaration };
730 ubsan_handle(&v, Fatal);
731 }
732
733 void
__ubsan_handle_nonnull_return_v1(struct ubsan_nullability_ret_desc * desc,uint64_t declaration)734 __ubsan_handle_nonnull_return_v1(struct ubsan_nullability_ret_desc *desc, uint64_t declaration)
735 {
736 ubsan_violation_t v = { UBSAN_NULLABILITY_RETURN, 1, (uint64_t)&desc->loc, .nonnull_ret = desc, (struct san_src_loc *)declaration };
737 ubsan_handle(&v, FleshWound);
738 }
739
740 void
__ubsan_handle_nonnull_return_v1_abort(struct ubsan_nullability_ret_desc * desc,uint64_t declaration)741 __ubsan_handle_nonnull_return_v1_abort(struct ubsan_nullability_ret_desc *desc, uint64_t declaration)
742 {
743 ubsan_violation_t v = { UBSAN_NULLABILITY_RETURN, 1, (uint64_t)&desc->loc, .nonnull_ret = desc, (struct san_src_loc *)declaration };
744 ubsan_handle(&v, Fatal);
745 }
746
747 void
__ubsan_handle_missing_return(struct ubsan_missing_ret_desc * desc)748 __ubsan_handle_missing_return(struct ubsan_missing_ret_desc *desc)
749 {
750 ubsan_violation_t v = { UBSAN_MISSING_RETURN, 0, 0, .missing_ret = desc, &desc->loc };
751 ubsan_handle(&v, Fatal);
752 }
753
754 void
__ubsan_handle_missing_return_abort(struct ubsan_missing_ret_desc * desc)755 __ubsan_handle_missing_return_abort(struct ubsan_missing_ret_desc *desc)
756 {
757 ubsan_violation_t v = { UBSAN_MISSING_RETURN, 0, 0, .missing_ret = desc, &desc->loc };
758 ubsan_handle(&v, Fatal);
759 }
760
761 void
__ubsan_handle_float_cast_overflow(struct ubsan_float_desc * desc,uint64_t value)762 __ubsan_handle_float_cast_overflow(struct ubsan_float_desc *desc, uint64_t value)
763 {
764 ubsan_violation_t v = { UBSAN_FLOAT_CAST_OVERFLOW, value, 0, .flt = desc, &desc->loc };
765 ubsan_handle(&v, Fatal);
766 }
767
768 void
__ubsan_handle_float_cast_overflow_abort(struct ubsan_float_desc * desc,uint64_t value)769 __ubsan_handle_float_cast_overflow_abort(struct ubsan_float_desc *desc, uint64_t value)
770 {
771 ubsan_violation_t v = { UBSAN_FLOAT_CAST_OVERFLOW, value, 0, .flt = desc, &desc->loc };
772 ubsan_handle(&v, Fatal);
773 }
774
775 void
__ubsan_handle_implicit_conversion(struct ubsan_implicit_conv_desc * desc,uint64_t from,uint64_t to)776 __ubsan_handle_implicit_conversion(struct ubsan_implicit_conv_desc *desc, uint64_t from, uint64_t to)
777 {
778 ubsan_violation_t v = { UBSAN_IMPLICIT_CONVERSION, from, to, .implicit = desc, &desc->loc };
779 ubsan_handle(&v, Fatal);
780 }
781
782 void
__ubsan_handle_implicit_conversion_abort(struct ubsan_implicit_conv_desc * desc,uint64_t from,uint64_t to)783 __ubsan_handle_implicit_conversion_abort(struct ubsan_implicit_conv_desc *desc, uint64_t from, uint64_t to)
784 {
785 ubsan_violation_t v = { UBSAN_IMPLICIT_CONVERSION, from, to, .implicit = desc, &desc->loc };
786 ubsan_handle(&v, Fatal);
787 }
788
789 void
__ubsan_handle_function_type_mismatch(struct ubsan_func_type_mismatch_desc * desc,uint64_t func)790 __ubsan_handle_function_type_mismatch(struct ubsan_func_type_mismatch_desc *desc, uint64_t func)
791 {
792 ubsan_violation_t v = { UBSAN_FUNCTION_TYPE_MISMATCH, func, 0, .func_mismatch = desc, &desc->loc };
793 ubsan_handle(&v, Fatal);
794 }
795
796 void
__ubsan_handle_function_type_mismatch_abort(struct ubsan_func_type_mismatch_desc * desc,uint64_t func)797 __ubsan_handle_function_type_mismatch_abort(struct ubsan_func_type_mismatch_desc *desc, uint64_t func)
798 {
799 ubsan_violation_t v = { UBSAN_FUNCTION_TYPE_MISMATCH, func, 0, .func_mismatch = desc, &desc->loc };
800 ubsan_handle(&v, Fatal);
801 }
802
803 void
__ubsan_handle_vla_bound_not_positive(struct ubsan_vla_bound_desc * desc,uint64_t length)804 __ubsan_handle_vla_bound_not_positive(struct ubsan_vla_bound_desc *desc, uint64_t length)
805 {
806 ubsan_violation_t v = { UBSAN_VLA_BOUND_NOT_POSITIVE, length, 0, .vla_bound = desc, &desc->loc };
807 ubsan_handle(&v, Fatal);
808 }
809
810 void
__ubsan_handle_vla_bound_not_positive_abort(struct ubsan_vla_bound_desc * desc,uint64_t length)811 __ubsan_handle_vla_bound_not_positive_abort(struct ubsan_vla_bound_desc *desc, uint64_t length)
812 {
813 ubsan_violation_t v = { UBSAN_VLA_BOUND_NOT_POSITIVE, length, 0, .vla_bound = desc, &desc->loc };
814 ubsan_handle(&v, Fatal);
815 }
816
817 void
__ubsan_handle_invalid_builtin(struct ubsan_invalid_builtin * desc)818 __ubsan_handle_invalid_builtin(struct ubsan_invalid_builtin *desc)
819 {
820 ubsan_violation_t v = { UBSAN_INVALID_BUILTIN, 0, 0, .invalid_builtin = desc, &desc->loc };
821 ubsan_handle(&v, Fatal);
822 }
823
824 void
__ubsan_handle_invalid_builtin_abort(struct ubsan_invalid_builtin * desc)825 __ubsan_handle_invalid_builtin_abort(struct ubsan_invalid_builtin *desc)
826 {
827 ubsan_violation_t v = { UBSAN_INVALID_BUILTIN, 0, 0, .invalid_builtin = desc, &desc->loc };
828 ubsan_handle(&v, Fatal);
829 }
830
831 void
__ubsan_handle_load_invalid_value(struct ubsan_load_invalid_desc * desc,uint64_t invalid_value)832 __ubsan_handle_load_invalid_value(struct ubsan_load_invalid_desc *desc, uint64_t invalid_value)
833 {
834 ubsan_violation_t v = { UBSAN_LOAD_INVALID_VALUE, invalid_value, 0, .invalid = desc, &desc->loc };
835 ubsan_handle(&v, Fatal);
836 }
837
838 void
__ubsan_handle_load_invalid_value_abort(struct ubsan_load_invalid_desc * desc,uint64_t invalid_value)839 __ubsan_handle_load_invalid_value_abort(struct ubsan_load_invalid_desc *desc, uint64_t invalid_value)
840 {
841 ubsan_violation_t v = { UBSAN_LOAD_INVALID_VALUE, invalid_value, 0, .invalid = desc, &desc->loc };
842 ubsan_handle(&v, Fatal);
843 }
844