1*344aa361SAndroid Build Coastguard Worker /*
2*344aa361SAndroid Build Coastguard Worker * Copyright (c) 2019 Google Inc. All rights reserved
3*344aa361SAndroid Build Coastguard Worker *
4*344aa361SAndroid Build Coastguard Worker * Permission is hereby granted, free of charge, to any person obtaining
5*344aa361SAndroid Build Coastguard Worker * a copy of this software and associated documentation files
6*344aa361SAndroid Build Coastguard Worker * (the "Software"), to deal in the Software without restriction,
7*344aa361SAndroid Build Coastguard Worker * including without limitation the rights to use, copy, modify, merge,
8*344aa361SAndroid Build Coastguard Worker * publish, distribute, sublicense, and/or sell copies of the Software,
9*344aa361SAndroid Build Coastguard Worker * and to permit persons to whom the Software is furnished to do so,
10*344aa361SAndroid Build Coastguard Worker * subject to the following conditions:
11*344aa361SAndroid Build Coastguard Worker *
12*344aa361SAndroid Build Coastguard Worker * The above copyright notice and this permission notice shall be
13*344aa361SAndroid Build Coastguard Worker * included in all copies or substantial portions of the Software.
14*344aa361SAndroid Build Coastguard Worker *
15*344aa361SAndroid Build Coastguard Worker * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16*344aa361SAndroid Build Coastguard Worker * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17*344aa361SAndroid Build Coastguard Worker * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18*344aa361SAndroid Build Coastguard Worker * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19*344aa361SAndroid Build Coastguard Worker * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20*344aa361SAndroid Build Coastguard Worker * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21*344aa361SAndroid Build Coastguard Worker * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22*344aa361SAndroid Build Coastguard Worker */
23*344aa361SAndroid Build Coastguard Worker
24*344aa361SAndroid Build Coastguard Worker #include "ubsan.h"
25*344aa361SAndroid Build Coastguard Worker
26*344aa361SAndroid Build Coastguard Worker #include <assert.h>
27*344aa361SAndroid Build Coastguard Worker #include <inttypes.h>
28*344aa361SAndroid Build Coastguard Worker #include <stdbool.h>
29*344aa361SAndroid Build Coastguard Worker #include <stdint.h>
30*344aa361SAndroid Build Coastguard Worker #include <stdio.h>
31*344aa361SAndroid Build Coastguard Worker #include <string.h>
32*344aa361SAndroid Build Coastguard Worker #include <sys/types.h>
33*344aa361SAndroid Build Coastguard Worker #include <trusty/string.h>
34*344aa361SAndroid Build Coastguard Worker
35*344aa361SAndroid Build Coastguard Worker /*
36*344aa361SAndroid Build Coastguard Worker * in_ubsan_* is used to track whether we are currently processing a UBSan
37*344aa361SAndroid Build Coastguard Worker * report. This is useful information so that if UBSan gets tripped again
38*344aa361SAndroid Build Coastguard Worker * (due to e.g. a bug in printf, or the logging code) we don't sit in an
39*344aa361SAndroid Build Coastguard Worker * infinite recursion trying to report the bug over and over.
40*344aa361SAndroid Build Coastguard Worker */
41*344aa361SAndroid Build Coastguard Worker static bool in_ubsan_get(void);
42*344aa361SAndroid Build Coastguard Worker static void in_ubsan_set(bool);
43*344aa361SAndroid Build Coastguard Worker
44*344aa361SAndroid Build Coastguard Worker #ifdef TRUSTY_USERSPACE
45*344aa361SAndroid Build Coastguard Worker /* TODO Once TLS is available, make this __thread */
46*344aa361SAndroid Build Coastguard Worker static bool in_ubsan = false;
in_ubsan_get(void)47*344aa361SAndroid Build Coastguard Worker static inline bool in_ubsan_get(void) {
48*344aa361SAndroid Build Coastguard Worker return in_ubsan;
49*344aa361SAndroid Build Coastguard Worker }
in_ubsan_set(bool val)50*344aa361SAndroid Build Coastguard Worker static inline void in_ubsan_set(bool val) {
51*344aa361SAndroid Build Coastguard Worker in_ubsan = val;
52*344aa361SAndroid Build Coastguard Worker }
53*344aa361SAndroid Build Coastguard Worker #else
54*344aa361SAndroid Build Coastguard Worker /*
55*344aa361SAndroid Build Coastguard Worker * Single copy of in_ubsan for when we don't have a current thread, e.g.,
56*344aa361SAndroid Build Coastguard Worker * during early boot
57*344aa361SAndroid Build Coastguard Worker */
58*344aa361SAndroid Build Coastguard Worker static bool in_ubsan_early = false;
59*344aa361SAndroid Build Coastguard Worker
60*344aa361SAndroid Build Coastguard Worker #include <kernel/thread.h>
in_ubsan_get(void)61*344aa361SAndroid Build Coastguard Worker static inline bool in_ubsan_get(void) {
62*344aa361SAndroid Build Coastguard Worker thread_t* curr = get_current_thread();
63*344aa361SAndroid Build Coastguard Worker return curr ? thread_tls_get(curr, TLS_ENTRY_UBSAN) : in_ubsan_early;
64*344aa361SAndroid Build Coastguard Worker }
in_ubsan_set(bool val)65*344aa361SAndroid Build Coastguard Worker static inline void in_ubsan_set(bool val) {
66*344aa361SAndroid Build Coastguard Worker thread_t* curr = get_current_thread();
67*344aa361SAndroid Build Coastguard Worker if (curr) {
68*344aa361SAndroid Build Coastguard Worker thread_tls_set(curr, TLS_ENTRY_UBSAN, val);
69*344aa361SAndroid Build Coastguard Worker } else {
70*344aa361SAndroid Build Coastguard Worker in_ubsan_early = val;
71*344aa361SAndroid Build Coastguard Worker }
72*344aa361SAndroid Build Coastguard Worker }
73*344aa361SAndroid Build Coastguard Worker #endif
74*344aa361SAndroid Build Coastguard Worker
75*344aa361SAndroid Build Coastguard Worker #define VALUE_RENDER_SIZE 64
76*344aa361SAndroid Build Coastguard Worker #define DETAIL_RENDER_SIZE 1024
77*344aa361SAndroid Build Coastguard Worker
val_signed(const struct type_descriptor * type,value_handle_t val)78*344aa361SAndroid Build Coastguard Worker static int64_t val_signed(const struct type_descriptor* type,
79*344aa361SAndroid Build Coastguard Worker value_handle_t val) {
80*344aa361SAndroid Build Coastguard Worker if (type_is_inline(type)) {
81*344aa361SAndroid Build Coastguard Worker /* Sign extend if smaller than ssize_t-bits */
82*344aa361SAndroid Build Coastguard Worker size_t undefined_bits = sizeof(size_t) * 8 - type_width_bits(type);
83*344aa361SAndroid Build Coastguard Worker val <<= undefined_bits;
84*344aa361SAndroid Build Coastguard Worker ssize_t out = (ssize_t)val;
85*344aa361SAndroid Build Coastguard Worker out >>= undefined_bits;
86*344aa361SAndroid Build Coastguard Worker return out;
87*344aa361SAndroid Build Coastguard Worker } else {
88*344aa361SAndroid Build Coastguard Worker /*
89*344aa361SAndroid Build Coastguard Worker * This truncates, but we don't have a good way to deal with
90*344aa361SAndroid Build Coastguard Worker * ints larger than 64 bits and it at least gets *some* data.
91*344aa361SAndroid Build Coastguard Worker *
92*344aa361SAndroid Build Coastguard Worker * For values larger than 64 bits, this will also have the wrong
93*344aa361SAndroid Build Coastguard Worker * sign.
94*344aa361SAndroid Build Coastguard Worker */
95*344aa361SAndroid Build Coastguard Worker return *(int64_t*)val;
96*344aa361SAndroid Build Coastguard Worker }
97*344aa361SAndroid Build Coastguard Worker }
98*344aa361SAndroid Build Coastguard Worker
val_unsigned(const struct type_descriptor * type,value_handle_t val)99*344aa361SAndroid Build Coastguard Worker static uint64_t val_unsigned(const struct type_descriptor* type,
100*344aa361SAndroid Build Coastguard Worker value_handle_t val) {
101*344aa361SAndroid Build Coastguard Worker if (type_is_inline(type)) {
102*344aa361SAndroid Build Coastguard Worker return (uint64_t)val;
103*344aa361SAndroid Build Coastguard Worker } else {
104*344aa361SAndroid Build Coastguard Worker /* This truncates, but gets some data out */
105*344aa361SAndroid Build Coastguard Worker return *(uint64_t*)val;
106*344aa361SAndroid Build Coastguard Worker }
107*344aa361SAndroid Build Coastguard Worker }
108*344aa361SAndroid Build Coastguard Worker
render_val(char * out,size_t out_size,const struct type_descriptor * type,value_handle_t val)109*344aa361SAndroid Build Coastguard Worker static void render_val(char* out,
110*344aa361SAndroid Build Coastguard Worker size_t out_size,
111*344aa361SAndroid Build Coastguard Worker const struct type_descriptor* type,
112*344aa361SAndroid Build Coastguard Worker value_handle_t val) {
113*344aa361SAndroid Build Coastguard Worker size_t width = type_width_bits(type);
114*344aa361SAndroid Build Coastguard Worker if (type_is_signed_integer(type)) {
115*344aa361SAndroid Build Coastguard Worker if (width > sizeof(int64_t) * 8) {
116*344aa361SAndroid Build Coastguard Worker size_t warn_len = scnprintf(out, out_size,
117*344aa361SAndroid Build Coastguard Worker "~int%zu_t->int64_t:truncated ", width);
118*344aa361SAndroid Build Coastguard Worker out += warn_len;
119*344aa361SAndroid Build Coastguard Worker out_size -= warn_len;
120*344aa361SAndroid Build Coastguard Worker }
121*344aa361SAndroid Build Coastguard Worker scnprintf(out, out_size, "%" PRId64, val_signed(type, val));
122*344aa361SAndroid Build Coastguard Worker } else if (type_is_unsigned_integer(type)) {
123*344aa361SAndroid Build Coastguard Worker if (width > sizeof(uint64_t) * 8) {
124*344aa361SAndroid Build Coastguard Worker size_t warn_len = scnprintf(
125*344aa361SAndroid Build Coastguard Worker out, out_size, "~uint%zu_t->uint64_t:truncated ", width);
126*344aa361SAndroid Build Coastguard Worker out += warn_len;
127*344aa361SAndroid Build Coastguard Worker out_size -= warn_len;
128*344aa361SAndroid Build Coastguard Worker }
129*344aa361SAndroid Build Coastguard Worker scnprintf(out, out_size, "%" PRIu64, val_unsigned(type, val));
130*344aa361SAndroid Build Coastguard Worker } else if (type_is_float(type)) {
131*344aa361SAndroid Build Coastguard Worker /*
132*344aa361SAndroid Build Coastguard Worker * Printing floating point correctly requires a more powerful printf
133*344aa361SAndroid Build Coastguard Worker * which may not be available, and printing large floats will pull in
134*344aa361SAndroid Build Coastguard Worker * softfloat support.
135*344aa361SAndroid Build Coastguard Worker * Since it is unlikely the exact value of a float triggering a
136*344aa361SAndroid Build Coastguard Worker * sanitizer will be important, we don't format it.
137*344aa361SAndroid Build Coastguard Worker */
138*344aa361SAndroid Build Coastguard Worker scnprintf(out, out_size, "<floating point value>");
139*344aa361SAndroid Build Coastguard Worker } else {
140*344aa361SAndroid Build Coastguard Worker scnprintf(out, out_size, "<value with unknown type>");
141*344aa361SAndroid Build Coastguard Worker }
142*344aa361SAndroid Build Coastguard Worker }
143*344aa361SAndroid Build Coastguard Worker
log(struct source_location * location,const char * kind,const char * details)144*344aa361SAndroid Build Coastguard Worker static void log(struct source_location* location,
145*344aa361SAndroid Build Coastguard Worker const char* kind,
146*344aa361SAndroid Build Coastguard Worker const char* details) {
147*344aa361SAndroid Build Coastguard Worker fprintf(stderr, "UBSan: (%s) %s:%d:%d\nDetails: %s\n", kind,
148*344aa361SAndroid Build Coastguard Worker location->filename, location->line, location->column, details);
149*344aa361SAndroid Build Coastguard Worker }
150*344aa361SAndroid Build Coastguard Worker
ubsan_fail(const char * msg)151*344aa361SAndroid Build Coastguard Worker static void ubsan_fail(const char* msg) {
152*344aa361SAndroid Build Coastguard Worker #ifdef TRUSTY_USERSPACE
153*344aa361SAndroid Build Coastguard Worker fprintf(stderr, "ubsan panic: %s\n", msg);
154*344aa361SAndroid Build Coastguard Worker *(volatile char*)0 = 0;
155*344aa361SAndroid Build Coastguard Worker #else
156*344aa361SAndroid Build Coastguard Worker panic("%s\n", msg);
157*344aa361SAndroid Build Coastguard Worker #endif
158*344aa361SAndroid Build Coastguard Worker }
159*344aa361SAndroid Build Coastguard Worker
start(void)160*344aa361SAndroid Build Coastguard Worker static bool start(void) {
161*344aa361SAndroid Build Coastguard Worker if (in_ubsan_get()) {
162*344aa361SAndroid Build Coastguard Worker return false;
163*344aa361SAndroid Build Coastguard Worker }
164*344aa361SAndroid Build Coastguard Worker in_ubsan_set(true);
165*344aa361SAndroid Build Coastguard Worker return true;
166*344aa361SAndroid Build Coastguard Worker }
167*344aa361SAndroid Build Coastguard Worker
finish(void)168*344aa361SAndroid Build Coastguard Worker static void finish(void) {
169*344aa361SAndroid Build Coastguard Worker assert(in_ubsan_get());
170*344aa361SAndroid Build Coastguard Worker ubsan_fail("UBSan violation");
171*344aa361SAndroid Build Coastguard Worker }
172*344aa361SAndroid Build Coastguard Worker
173*344aa361SAndroid Build Coastguard Worker /*
174*344aa361SAndroid Build Coastguard Worker * UBSAN_START should be used at the beginning of each ubsan handler.
175*344aa361SAndroid Build Coastguard Worker * It will abort if we are already processing a UBSan report, and set the
176*344aa361SAndroid Build Coastguard Worker * flag if we are.
177*344aa361SAndroid Build Coastguard Worker */
178*344aa361SAndroid Build Coastguard Worker #define UBSAN_START \
179*344aa361SAndroid Build Coastguard Worker if (!start()) { \
180*344aa361SAndroid Build Coastguard Worker return; \
181*344aa361SAndroid Build Coastguard Worker }
182*344aa361SAndroid Build Coastguard Worker
183*344aa361SAndroid Build Coastguard Worker /*
184*344aa361SAndroid Build Coastguard Worker * UBSAN_FINISH should be used at the end of each ubsan handler.
185*344aa361SAndroid Build Coastguard Worker * It will mark us as having left the handler, and terminate due to the error
186*344aa361SAndroid Build Coastguard Worker * report.
187*344aa361SAndroid Build Coastguard Worker */
188*344aa361SAndroid Build Coastguard Worker #define UBSAN_FINISH finish();
189*344aa361SAndroid Build Coastguard Worker
handle_overflow(struct overflow_data * data,value_handle_t lhs,value_handle_t rhs,const char * op)190*344aa361SAndroid Build Coastguard Worker static void handle_overflow(struct overflow_data* data,
191*344aa361SAndroid Build Coastguard Worker value_handle_t lhs,
192*344aa361SAndroid Build Coastguard Worker value_handle_t rhs,
193*344aa361SAndroid Build Coastguard Worker const char* op) {
194*344aa361SAndroid Build Coastguard Worker UBSAN_START;
195*344aa361SAndroid Build Coastguard Worker char rendered_lhs[VALUE_RENDER_SIZE];
196*344aa361SAndroid Build Coastguard Worker char rendered_rhs[VALUE_RENDER_SIZE];
197*344aa361SAndroid Build Coastguard Worker char details[DETAIL_RENDER_SIZE];
198*344aa361SAndroid Build Coastguard Worker
199*344aa361SAndroid Build Coastguard Worker char overflow_kind[16];
200*344aa361SAndroid Build Coastguard Worker
201*344aa361SAndroid Build Coastguard Worker scnprintf(overflow_kind, sizeof(overflow_kind), "overflow:%s", op);
202*344aa361SAndroid Build Coastguard Worker
203*344aa361SAndroid Build Coastguard Worker const struct type_descriptor* type = data->type;
204*344aa361SAndroid Build Coastguard Worker
205*344aa361SAndroid Build Coastguard Worker render_val(rendered_lhs, sizeof(rendered_lhs), type, lhs);
206*344aa361SAndroid Build Coastguard Worker render_val(rendered_rhs, sizeof(rendered_rhs), type, rhs);
207*344aa361SAndroid Build Coastguard Worker
208*344aa361SAndroid Build Coastguard Worker scnprintf(details, sizeof(details),
209*344aa361SAndroid Build Coastguard Worker "%s integer overflow: %s %s %s cannot be represented in type"
210*344aa361SAndroid Build Coastguard Worker " %s\n",
211*344aa361SAndroid Build Coastguard Worker type_is_signed_integer(type) ? "signed" : "unsigned",
212*344aa361SAndroid Build Coastguard Worker rendered_lhs, op, rendered_rhs, type->name);
213*344aa361SAndroid Build Coastguard Worker
214*344aa361SAndroid Build Coastguard Worker log(&data->loc, overflow_kind, details);
215*344aa361SAndroid Build Coastguard Worker UBSAN_FINISH;
216*344aa361SAndroid Build Coastguard Worker }
217*344aa361SAndroid Build Coastguard Worker
UBSAN_HANDLER(add_overflow,struct overflow_data * data,value_handle_t lhs,value_handle_t rhs)218*344aa361SAndroid Build Coastguard Worker UBSAN_HANDLER(add_overflow,
219*344aa361SAndroid Build Coastguard Worker struct overflow_data* data,
220*344aa361SAndroid Build Coastguard Worker value_handle_t lhs,
221*344aa361SAndroid Build Coastguard Worker value_handle_t rhs) {
222*344aa361SAndroid Build Coastguard Worker handle_overflow(data, lhs, rhs, "+");
223*344aa361SAndroid Build Coastguard Worker }
224*344aa361SAndroid Build Coastguard Worker
UBSAN_HANDLER(sub_overflow,struct overflow_data * data,value_handle_t lhs,value_handle_t rhs)225*344aa361SAndroid Build Coastguard Worker UBSAN_HANDLER(sub_overflow,
226*344aa361SAndroid Build Coastguard Worker struct overflow_data* data,
227*344aa361SAndroid Build Coastguard Worker value_handle_t lhs,
228*344aa361SAndroid Build Coastguard Worker value_handle_t rhs) {
229*344aa361SAndroid Build Coastguard Worker handle_overflow(data, lhs, rhs, "-");
230*344aa361SAndroid Build Coastguard Worker }
231*344aa361SAndroid Build Coastguard Worker
UBSAN_HANDLER(mul_overflow,struct overflow_data * data,value_handle_t lhs,value_handle_t rhs)232*344aa361SAndroid Build Coastguard Worker UBSAN_HANDLER(mul_overflow,
233*344aa361SAndroid Build Coastguard Worker struct overflow_data* data,
234*344aa361SAndroid Build Coastguard Worker value_handle_t lhs,
235*344aa361SAndroid Build Coastguard Worker value_handle_t rhs) {
236*344aa361SAndroid Build Coastguard Worker handle_overflow(data, lhs, rhs, "*");
237*344aa361SAndroid Build Coastguard Worker }
238*344aa361SAndroid Build Coastguard Worker
UBSAN_HANDLER(divrem_overflow,struct overflow_data * data,value_handle_t lhs,value_handle_t rhs)239*344aa361SAndroid Build Coastguard Worker UBSAN_HANDLER(divrem_overflow,
240*344aa361SAndroid Build Coastguard Worker struct overflow_data* data,
241*344aa361SAndroid Build Coastguard Worker value_handle_t lhs,
242*344aa361SAndroid Build Coastguard Worker value_handle_t rhs) {
243*344aa361SAndroid Build Coastguard Worker handle_overflow(data, lhs, rhs, "/%");
244*344aa361SAndroid Build Coastguard Worker }
245*344aa361SAndroid Build Coastguard Worker
UBSAN_HANDLER(negate_overflow,struct overflow_data * data,value_handle_t val)246*344aa361SAndroid Build Coastguard Worker UBSAN_HANDLER(negate_overflow, struct overflow_data* data, value_handle_t val) {
247*344aa361SAndroid Build Coastguard Worker UBSAN_START;
248*344aa361SAndroid Build Coastguard Worker char rendered_val[VALUE_RENDER_SIZE];
249*344aa361SAndroid Build Coastguard Worker char details[DETAIL_RENDER_SIZE];
250*344aa361SAndroid Build Coastguard Worker
251*344aa361SAndroid Build Coastguard Worker render_val(rendered_val, sizeof(rendered_val), data->type, val);
252*344aa361SAndroid Build Coastguard Worker scnprintf(details, sizeof(details),
253*344aa361SAndroid Build Coastguard Worker "negation of %s cannot be represented in type %s", rendered_val,
254*344aa361SAndroid Build Coastguard Worker data->type->name);
255*344aa361SAndroid Build Coastguard Worker
256*344aa361SAndroid Build Coastguard Worker log(&data->loc, "negation overflow", details);
257*344aa361SAndroid Build Coastguard Worker UBSAN_FINISH;
258*344aa361SAndroid Build Coastguard Worker }
259*344aa361SAndroid Build Coastguard Worker
UBSAN_HANDLER(pointer_overflow,struct pointer_overflow_data * data,uintptr_t base,uintptr_t result)260*344aa361SAndroid Build Coastguard Worker UBSAN_HANDLER(pointer_overflow,
261*344aa361SAndroid Build Coastguard Worker struct pointer_overflow_data* data,
262*344aa361SAndroid Build Coastguard Worker uintptr_t base,
263*344aa361SAndroid Build Coastguard Worker uintptr_t result) {
264*344aa361SAndroid Build Coastguard Worker UBSAN_START;
265*344aa361SAndroid Build Coastguard Worker char details[DETAIL_RENDER_SIZE];
266*344aa361SAndroid Build Coastguard Worker snprintf_filtered(details, sizeof(details),
267*344aa361SAndroid Build Coastguard Worker "pointer arithmetic on %p overflowed resulting in %p",
268*344aa361SAndroid Build Coastguard Worker (void*)base, (void*)result);
269*344aa361SAndroid Build Coastguard Worker log(&data->loc, "pointer_overflow", details);
270*344aa361SAndroid Build Coastguard Worker UBSAN_FINISH;
271*344aa361SAndroid Build Coastguard Worker }
272*344aa361SAndroid Build Coastguard Worker
UBSAN_HANDLER(implicit_conversion,struct implicit_conversion_data * data,value_handle_t src,value_handle_t dst)273*344aa361SAndroid Build Coastguard Worker UBSAN_HANDLER(implicit_conversion,
274*344aa361SAndroid Build Coastguard Worker struct implicit_conversion_data* data,
275*344aa361SAndroid Build Coastguard Worker value_handle_t src,
276*344aa361SAndroid Build Coastguard Worker value_handle_t dst) {
277*344aa361SAndroid Build Coastguard Worker UBSAN_START;
278*344aa361SAndroid Build Coastguard Worker char rendered_src[VALUE_RENDER_SIZE];
279*344aa361SAndroid Build Coastguard Worker char rendered_dst[VALUE_RENDER_SIZE];
280*344aa361SAndroid Build Coastguard Worker char details[DETAIL_RENDER_SIZE];
281*344aa361SAndroid Build Coastguard Worker const char* kind_str;
282*344aa361SAndroid Build Coastguard Worker
283*344aa361SAndroid Build Coastguard Worker if (data->check_kind <
284*344aa361SAndroid Build Coastguard Worker sizeof(implicit_conversion_check_kinds) / sizeof(const char*)) {
285*344aa361SAndroid Build Coastguard Worker kind_str = implicit_conversion_check_kinds[data->check_kind];
286*344aa361SAndroid Build Coastguard Worker } else {
287*344aa361SAndroid Build Coastguard Worker kind_str = "unknown";
288*344aa361SAndroid Build Coastguard Worker }
289*344aa361SAndroid Build Coastguard Worker
290*344aa361SAndroid Build Coastguard Worker render_val(rendered_src, sizeof(rendered_src), data->from_type, src);
291*344aa361SAndroid Build Coastguard Worker render_val(rendered_dst, sizeof(rendered_dst), data->to_type, dst);
292*344aa361SAndroid Build Coastguard Worker scnprintf(details, sizeof(details),
293*344aa361SAndroid Build Coastguard Worker "implicit conversion (%s) from %s to %s\n", kind_str,
294*344aa361SAndroid Build Coastguard Worker rendered_src, rendered_dst);
295*344aa361SAndroid Build Coastguard Worker
296*344aa361SAndroid Build Coastguard Worker log(&data->loc, "implicit conversion", details);
297*344aa361SAndroid Build Coastguard Worker UBSAN_FINISH;
298*344aa361SAndroid Build Coastguard Worker }
299*344aa361SAndroid Build Coastguard Worker
UBSAN_HANDLER(invalid_builtin,struct invalid_builtin_data * data)300*344aa361SAndroid Build Coastguard Worker UBSAN_HANDLER(invalid_builtin, struct invalid_builtin_data* data) {
301*344aa361SAndroid Build Coastguard Worker UBSAN_START;
302*344aa361SAndroid Build Coastguard Worker const char* details;
303*344aa361SAndroid Build Coastguard Worker switch (data->check_kind) {
304*344aa361SAndroid Build Coastguard Worker case BCK_CTZ_PASSED_ZERO:
305*344aa361SAndroid Build Coastguard Worker details = "zero passed to ctz";
306*344aa361SAndroid Build Coastguard Worker break;
307*344aa361SAndroid Build Coastguard Worker case BCK_CLZ_PASSED_ZERO:
308*344aa361SAndroid Build Coastguard Worker details = "zero passed to clz";
309*344aa361SAndroid Build Coastguard Worker break;
310*344aa361SAndroid Build Coastguard Worker default:
311*344aa361SAndroid Build Coastguard Worker details = "unknown builtin misuse kind";
312*344aa361SAndroid Build Coastguard Worker }
313*344aa361SAndroid Build Coastguard Worker log(&data->loc, "invalid builtin usage", details);
314*344aa361SAndroid Build Coastguard Worker UBSAN_FINISH;
315*344aa361SAndroid Build Coastguard Worker }
316*344aa361SAndroid Build Coastguard Worker
UBSAN_HANDLER(type_mismatch_v1,struct type_mismatch_data * data,value_handle_t ptr)317*344aa361SAndroid Build Coastguard Worker UBSAN_HANDLER(type_mismatch_v1,
318*344aa361SAndroid Build Coastguard Worker struct type_mismatch_data* data,
319*344aa361SAndroid Build Coastguard Worker value_handle_t ptr) {
320*344aa361SAndroid Build Coastguard Worker UBSAN_START;
321*344aa361SAndroid Build Coastguard Worker char details[DETAIL_RENDER_SIZE];
322*344aa361SAndroid Build Coastguard Worker
323*344aa361SAndroid Build Coastguard Worker intptr_t alignment = 1 << data->log_alignment;
324*344aa361SAndroid Build Coastguard Worker if (!ptr) {
325*344aa361SAndroid Build Coastguard Worker scnprintf(details, sizeof(details), "%s null pointer type %s",
326*344aa361SAndroid Build Coastguard Worker type_check_kinds[data->type_check_kind], data->type->name);
327*344aa361SAndroid Build Coastguard Worker } else if (ptr & (alignment - 1)) {
328*344aa361SAndroid Build Coastguard Worker snprintf_filtered(
329*344aa361SAndroid Build Coastguard Worker details, sizeof(details),
330*344aa361SAndroid Build Coastguard Worker "%s misaligned pointer %p for type %s which requires %d byte alignment",
331*344aa361SAndroid Build Coastguard Worker type_check_kinds[data->type_check_kind], (void*)ptr,
332*344aa361SAndroid Build Coastguard Worker data->type->name, (int)alignment);
333*344aa361SAndroid Build Coastguard Worker } else {
334*344aa361SAndroid Build Coastguard Worker snprintf_filtered(
335*344aa361SAndroid Build Coastguard Worker details, sizeof(details),
336*344aa361SAndroid Build Coastguard Worker "%s pointer %p points at a region with insufficient space for a value of type %s",
337*344aa361SAndroid Build Coastguard Worker type_check_kinds[data->type_check_kind], (void*)ptr,
338*344aa361SAndroid Build Coastguard Worker data->type->name);
339*344aa361SAndroid Build Coastguard Worker }
340*344aa361SAndroid Build Coastguard Worker log(&data->loc, "type mismatch", details);
341*344aa361SAndroid Build Coastguard Worker UBSAN_FINISH;
342*344aa361SAndroid Build Coastguard Worker }
343*344aa361SAndroid Build Coastguard Worker
UBSAN_HANDLER(builtin_unreachable,struct unreachable_data * data)344*344aa361SAndroid Build Coastguard Worker UBSAN_HANDLER(builtin_unreachable, struct unreachable_data* data) {
345*344aa361SAndroid Build Coastguard Worker UBSAN_START;
346*344aa361SAndroid Build Coastguard Worker log(&data->loc, "hit a supposedly unreachable point", "");
347*344aa361SAndroid Build Coastguard Worker UBSAN_FINISH;
348*344aa361SAndroid Build Coastguard Worker ubsan_fail("executing through unreachable would be unwise");
349*344aa361SAndroid Build Coastguard Worker }
350*344aa361SAndroid Build Coastguard Worker
UBSAN_HANDLER(missing_return,struct unreachable_data * data)351*344aa361SAndroid Build Coastguard Worker UBSAN_HANDLER(missing_return, struct unreachable_data* data) {
352*344aa361SAndroid Build Coastguard Worker UBSAN_START;
353*344aa361SAndroid Build Coastguard Worker log(&data->loc, "hit a missing return statement", "");
354*344aa361SAndroid Build Coastguard Worker UBSAN_FINISH;
355*344aa361SAndroid Build Coastguard Worker ubsan_fail("executing past the end of a function would be unwise");
356*344aa361SAndroid Build Coastguard Worker }
357*344aa361SAndroid Build Coastguard Worker
is_negative(const struct type_descriptor * type,value_handle_t val)358*344aa361SAndroid Build Coastguard Worker static bool is_negative(const struct type_descriptor* type,
359*344aa361SAndroid Build Coastguard Worker value_handle_t val) {
360*344aa361SAndroid Build Coastguard Worker if (type_is_signed_integer(type)) {
361*344aa361SAndroid Build Coastguard Worker return val_signed(type, val) < 0;
362*344aa361SAndroid Build Coastguard Worker }
363*344aa361SAndroid Build Coastguard Worker return false;
364*344aa361SAndroid Build Coastguard Worker }
365*344aa361SAndroid Build Coastguard Worker
UBSAN_HANDLER(shift_out_of_bounds,struct shift_out_of_bounds_data * data,value_handle_t lhs,value_handle_t rhs)366*344aa361SAndroid Build Coastguard Worker UBSAN_HANDLER(shift_out_of_bounds,
367*344aa361SAndroid Build Coastguard Worker struct shift_out_of_bounds_data* data,
368*344aa361SAndroid Build Coastguard Worker value_handle_t lhs,
369*344aa361SAndroid Build Coastguard Worker value_handle_t rhs) {
370*344aa361SAndroid Build Coastguard Worker UBSAN_START;
371*344aa361SAndroid Build Coastguard Worker char rendered_lhs[VALUE_RENDER_SIZE];
372*344aa361SAndroid Build Coastguard Worker char rendered_rhs[VALUE_RENDER_SIZE];
373*344aa361SAndroid Build Coastguard Worker char details[DETAIL_RENDER_SIZE];
374*344aa361SAndroid Build Coastguard Worker
375*344aa361SAndroid Build Coastguard Worker render_val(rendered_lhs, sizeof(rendered_lhs), data->lhs_type, lhs);
376*344aa361SAndroid Build Coastguard Worker render_val(rendered_rhs, sizeof(rendered_rhs), data->rhs_type, rhs);
377*344aa361SAndroid Build Coastguard Worker
378*344aa361SAndroid Build Coastguard Worker uint64_t rhs_u64 = val_unsigned(data->rhs_type, rhs);
379*344aa361SAndroid Build Coastguard Worker
380*344aa361SAndroid Build Coastguard Worker if (is_negative(data->rhs_type, rhs)) {
381*344aa361SAndroid Build Coastguard Worker scnprintf(details, sizeof(details), "shift amount is negative: %s",
382*344aa361SAndroid Build Coastguard Worker rendered_rhs);
383*344aa361SAndroid Build Coastguard Worker } else if (type_width_bits(data->lhs_type) < rhs_u64) {
384*344aa361SAndroid Build Coastguard Worker scnprintf(details, sizeof(details),
385*344aa361SAndroid Build Coastguard Worker "shift amount %s is too large for type %s", rendered_rhs,
386*344aa361SAndroid Build Coastguard Worker data->lhs_type->name);
387*344aa361SAndroid Build Coastguard Worker } else if (is_negative(data->lhs_type, lhs)) {
388*344aa361SAndroid Build Coastguard Worker /* At this point, we know we are dealing with a left shift, as right
389*344aa361SAndroid Build Coastguard Worker * shift is covered by the above two cases */
390*344aa361SAndroid Build Coastguard Worker scnprintf(details, sizeof(details),
391*344aa361SAndroid Build Coastguard Worker "left shifting a negative value: %s", rendered_lhs);
392*344aa361SAndroid Build Coastguard Worker } else {
393*344aa361SAndroid Build Coastguard Worker scnprintf(details, sizeof(details), "%s << %s does not fit in %s",
394*344aa361SAndroid Build Coastguard Worker rendered_lhs, rendered_rhs, data->lhs_type->name);
395*344aa361SAndroid Build Coastguard Worker }
396*344aa361SAndroid Build Coastguard Worker
397*344aa361SAndroid Build Coastguard Worker log(&data->loc, "shift out of bounds", details);
398*344aa361SAndroid Build Coastguard Worker UBSAN_FINISH;
399*344aa361SAndroid Build Coastguard Worker }
400*344aa361SAndroid Build Coastguard Worker
UBSAN_HANDLER(out_of_bounds,struct out_of_bounds_data * data,value_handle_t index)401*344aa361SAndroid Build Coastguard Worker UBSAN_HANDLER(out_of_bounds,
402*344aa361SAndroid Build Coastguard Worker struct out_of_bounds_data* data,
403*344aa361SAndroid Build Coastguard Worker value_handle_t index) {
404*344aa361SAndroid Build Coastguard Worker UBSAN_START;
405*344aa361SAndroid Build Coastguard Worker char rendered_index[VALUE_RENDER_SIZE];
406*344aa361SAndroid Build Coastguard Worker char details[DETAIL_RENDER_SIZE];
407*344aa361SAndroid Build Coastguard Worker
408*344aa361SAndroid Build Coastguard Worker render_val(rendered_index, sizeof(rendered_index), data->index_type, index);
409*344aa361SAndroid Build Coastguard Worker scnprintf(details, sizeof(details), "index %s out of bounds for %s\n",
410*344aa361SAndroid Build Coastguard Worker rendered_index, data->array_type->name);
411*344aa361SAndroid Build Coastguard Worker
412*344aa361SAndroid Build Coastguard Worker log(&data->loc, "out of bounds access", details);
413*344aa361SAndroid Build Coastguard Worker UBSAN_FINISH;
414*344aa361SAndroid Build Coastguard Worker }
415*344aa361SAndroid Build Coastguard Worker
UBSAN_HANDLER(load_invalid_value,struct invalid_value_data * data,value_handle_t val)416*344aa361SAndroid Build Coastguard Worker UBSAN_HANDLER(load_invalid_value,
417*344aa361SAndroid Build Coastguard Worker struct invalid_value_data* data,
418*344aa361SAndroid Build Coastguard Worker value_handle_t val) {
419*344aa361SAndroid Build Coastguard Worker UBSAN_START;
420*344aa361SAndroid Build Coastguard Worker char rendered_val[VALUE_RENDER_SIZE];
421*344aa361SAndroid Build Coastguard Worker char details[DETAIL_RENDER_SIZE];
422*344aa361SAndroid Build Coastguard Worker
423*344aa361SAndroid Build Coastguard Worker render_val(rendered_val, sizeof(rendered_val), data->type, val);
424*344aa361SAndroid Build Coastguard Worker scnprintf(details, sizeof(details),
425*344aa361SAndroid Build Coastguard Worker "load of value %s outside of range for type %s", rendered_val,
426*344aa361SAndroid Build Coastguard Worker data->type->name);
427*344aa361SAndroid Build Coastguard Worker
428*344aa361SAndroid Build Coastguard Worker log(&data->loc, "invalid value", details);
429*344aa361SAndroid Build Coastguard Worker UBSAN_FINISH;
430*344aa361SAndroid Build Coastguard Worker }
431*344aa361SAndroid Build Coastguard Worker
UBSAN_HANDLER(float_cast_overflow,struct float_cast_overflow_data * data,value_handle_t val)432*344aa361SAndroid Build Coastguard Worker UBSAN_HANDLER(float_cast_overflow,
433*344aa361SAndroid Build Coastguard Worker struct float_cast_overflow_data* data,
434*344aa361SAndroid Build Coastguard Worker value_handle_t val) {
435*344aa361SAndroid Build Coastguard Worker UBSAN_START;
436*344aa361SAndroid Build Coastguard Worker /* Since we aren't rendering floats, there's not much point in details */
437*344aa361SAndroid Build Coastguard Worker log(&data->loc, "float cast overflow", "");
438*344aa361SAndroid Build Coastguard Worker UBSAN_FINISH;
439*344aa361SAndroid Build Coastguard Worker }
440*344aa361SAndroid Build Coastguard Worker
UBSAN_HANDLER(cfi_check_fail_abort,struct cfi_check_fail_data * data,value_handle_t val,uintptr_t vtable_is_valid)441*344aa361SAndroid Build Coastguard Worker UBSAN_HANDLER(cfi_check_fail_abort,
442*344aa361SAndroid Build Coastguard Worker struct cfi_check_fail_data* data,
443*344aa361SAndroid Build Coastguard Worker value_handle_t val,
444*344aa361SAndroid Build Coastguard Worker uintptr_t vtable_is_valid) {
445*344aa361SAndroid Build Coastguard Worker UBSAN_START;
446*344aa361SAndroid Build Coastguard Worker char rendered_val[VALUE_RENDER_SIZE];
447*344aa361SAndroid Build Coastguard Worker char details[DETAIL_RENDER_SIZE];
448*344aa361SAndroid Build Coastguard Worker
449*344aa361SAndroid Build Coastguard Worker render_val(rendered_val, sizeof(rendered_val), data->type, val);
450*344aa361SAndroid Build Coastguard Worker scnprintf(details, sizeof(details), "type of the value: %s type name: %s",
451*344aa361SAndroid Build Coastguard Worker rendered_val, data->type->name);
452*344aa361SAndroid Build Coastguard Worker log(&data->loc, "cfi check fail abort", details);
453*344aa361SAndroid Build Coastguard Worker UBSAN_FINISH;
454*344aa361SAndroid Build Coastguard Worker }
455*344aa361SAndroid Build Coastguard Worker
UBSAN_HANDLER(vla_bound_not_positive,struct vla_bound_data * data,value_handle_t val)456*344aa361SAndroid Build Coastguard Worker UBSAN_HANDLER(vla_bound_not_positive,
457*344aa361SAndroid Build Coastguard Worker struct vla_bound_data* data,
458*344aa361SAndroid Build Coastguard Worker value_handle_t val) {
459*344aa361SAndroid Build Coastguard Worker UBSAN_START;
460*344aa361SAndroid Build Coastguard Worker char rendered_val[VALUE_RENDER_SIZE];
461*344aa361SAndroid Build Coastguard Worker char details[DETAIL_RENDER_SIZE];
462*344aa361SAndroid Build Coastguard Worker
463*344aa361SAndroid Build Coastguard Worker render_val(rendered_val, sizeof(rendered_val), data->type, val);
464*344aa361SAndroid Build Coastguard Worker scnprintf(details, sizeof(details), "bound %s is not positive for type %s",
465*344aa361SAndroid Build Coastguard Worker rendered_val, data->type->name);
466*344aa361SAndroid Build Coastguard Worker log(&data->loc,
467*344aa361SAndroid Build Coastguard Worker "variable length array bound evaluates to non-positive value", details);
468*344aa361SAndroid Build Coastguard Worker UBSAN_FINISH;
469*344aa361SAndroid Build Coastguard Worker }
470*344aa361SAndroid Build Coastguard Worker
UBSAN_HANDLER(alignment_assumption,struct alignment_assumption_data * data,value_handle_t pointer,value_handle_t alignment,value_handle_t offset)471*344aa361SAndroid Build Coastguard Worker UBSAN_HANDLER(alignment_assumption,
472*344aa361SAndroid Build Coastguard Worker struct alignment_assumption_data* data,
473*344aa361SAndroid Build Coastguard Worker value_handle_t pointer,
474*344aa361SAndroid Build Coastguard Worker value_handle_t alignment,
475*344aa361SAndroid Build Coastguard Worker value_handle_t offset) {
476*344aa361SAndroid Build Coastguard Worker UBSAN_START;
477*344aa361SAndroid Build Coastguard Worker char details[DETAIL_RENDER_SIZE];
478*344aa361SAndroid Build Coastguard Worker
479*344aa361SAndroid Build Coastguard Worker if (location_is_valid(data->assumption_loc)) {
480*344aa361SAndroid Build Coastguard Worker log(&data->assumption_loc, "alignment assumption was specified here",
481*344aa361SAndroid Build Coastguard Worker /* Details: */ "below");
482*344aa361SAndroid Build Coastguard Worker }
483*344aa361SAndroid Build Coastguard Worker
484*344aa361SAndroid Build Coastguard Worker if (!offset) {
485*344aa361SAndroid Build Coastguard Worker scnprintf(details, sizeof(details),
486*344aa361SAndroid Build Coastguard Worker "assumption of %" PRIuPTR
487*344aa361SAndroid Build Coastguard Worker " byte alignment for pointer of type %s failed",
488*344aa361SAndroid Build Coastguard Worker alignment, data->type->name);
489*344aa361SAndroid Build Coastguard Worker } else {
490*344aa361SAndroid Build Coastguard Worker scnprintf(details, sizeof(details),
491*344aa361SAndroid Build Coastguard Worker "assumption of %" PRIuPTR
492*344aa361SAndroid Build Coastguard Worker " byte alignment (with offset of %" PRIuPTR
493*344aa361SAndroid Build Coastguard Worker " bytes) for pointer of type %s failed",
494*344aa361SAndroid Build Coastguard Worker alignment, offset, data->type->name);
495*344aa361SAndroid Build Coastguard Worker }
496*344aa361SAndroid Build Coastguard Worker
497*344aa361SAndroid Build Coastguard Worker log(&data->loc, "alignment assumption is incorrect", details);
498*344aa361SAndroid Build Coastguard Worker UBSAN_FINISH;
499*344aa361SAndroid Build Coastguard Worker }
500