1 // Copyright (c) 2016, Linaro Limited
2 // Modified for HelenOS use by Jiří Zárevúcky.
3 // Adaptations for ESP-IDF Copyright (c) 2020 Espressif Systems (Shanghai) Co. Ltd.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // 1. Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 //
11 // 2. Redistributions in binary form must reproduce the above copyright notice,
12 // this list of conditions and the following disclaimer in the documentation
13 // and/or other materials provided with the distribution.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
19 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 // POSSIBILITY OF SUCH DAMAGE.
26
27 #include <stdbool.h>
28 #include <inttypes.h>
29 #include <stdlib.h>
30 #include <stddef.h>
31 #include <stdio.h>
32 #include <string.h>
33 #include "esp_system.h"
34 #include "esp_rom_sys.h"
35 #include "hal/cpu_hal.h"
36
37
38 struct source_location {
39 const char *file_name;
40 uint32_t line;
41 uint32_t column;
42 };
43
44 struct type_descriptor {
45 uint16_t type_kind;
46 uint16_t type_info;
47 char type_name[];
48 };
49
50 struct type_mismatch_data {
51 struct source_location loc;
52 struct type_descriptor *type;
53 unsigned long alignment;
54 unsigned char type_check_kind;
55 };
56
57 struct type_mismatch_data_v1 {
58 struct source_location loc;
59 struct type_descriptor *type;
60 unsigned char log_alignment;
61 unsigned char type_check_kind;
62 };
63
64 struct overflow_data {
65 struct source_location loc;
66 struct type_descriptor *type;
67 };
68
69 struct shift_out_of_bounds_data {
70 struct source_location loc;
71 struct type_descriptor *lhs_type;
72 struct type_descriptor *rhs_type;
73 };
74
75 struct out_of_bounds_data {
76 struct source_location loc;
77 struct type_descriptor *array_type;
78 struct type_descriptor *index_type;
79 };
80
81 struct unreachable_data {
82 struct source_location loc;
83 };
84
85 struct vla_bound_data {
86 struct source_location loc;
87 struct type_descriptor *type;
88 };
89
90 struct invalid_value_data {
91 struct source_location loc;
92 struct type_descriptor *type;
93 };
94
95 struct nonnull_arg_data {
96 struct source_location loc;
97 };
98
99 struct nonnull_return_data {
100 struct source_location loc;
101 struct source_location attr_loc;
102 };
103
104 struct pointer_overflow_data {
105 struct source_location loc;
106 };
107
108 struct invalid_builtin_data {
109 struct source_location loc;
110 unsigned char kind;
111 };
112
113
114 static void __ubsan_default_handler(struct source_location *loc, const char *func) __attribute__((noreturn));
115
116 /*
117 * When compiling with -fsanitize=undefined the compiler expects functions
118 * with the following signatures. The functions are never called directly,
119 * only when undefined behavior is detected in instrumented code.
120 */
121 void __ubsan_handle_type_mismatch(struct type_mismatch_data *data, unsigned long ptr);
122 void __ubsan_handle_type_mismatch_v1(struct type_mismatch_data_v1 *data, unsigned long ptr);
123 void __ubsan_handle_add_overflow(struct overflow_data *data, unsigned long lhs, unsigned long rhs);
124 void __ubsan_handle_sub_overflow(struct overflow_data *data, unsigned long lhs, unsigned long rhs);
125 void __ubsan_handle_mul_overflow(struct overflow_data *data, unsigned long lhs, unsigned long rhs);
126 void __ubsan_handle_negate_overflow(struct overflow_data *data, unsigned long old_val);
127 void __ubsan_handle_divrem_overflow(struct overflow_data *data, unsigned long lhs, unsigned long rhs);
128 void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data, unsigned long lhs, unsigned long rhs);
129 void __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data, unsigned long idx);
130 void __ubsan_handle_missing_return(struct unreachable_data *data);
131 void __ubsan_handle_vla_bound_not_positive(struct vla_bound_data *data, unsigned long bound);
132 void __ubsan_handle_load_invalid_value(struct invalid_value_data *data, unsigned long val);
133 void __ubsan_handle_nonnull_arg(struct nonnull_arg_data *data);
134 void __ubsan_handle_nonnull_return(struct nonnull_return_data *data);
135 void __ubsan_handle_builtin_unreachable(struct unreachable_data *data);
136 void __ubsan_handle_pointer_overflow(struct pointer_overflow_data *data,
137 unsigned long base, unsigned long result);
138
__ubsan_maybe_debugbreak(void)139 static void __ubsan_maybe_debugbreak(void)
140 {
141 if (cpu_hal_is_debugger_attached()) {
142 cpu_hal_break();
143 }
144 }
145
__ubsan_default_handler(struct source_location * loc,const char * func)146 static void __ubsan_default_handler(struct source_location *loc, const char *func)
147 {
148 /* Although the source location is available here, it is not printed:
149 *
150 * - We could use "snprintf", but that uses a lot of stack, and may allocate memory,
151 * so is not safe from UBSAN handler.
152 * - Alternatively, "itoa" could be used. However itoa doesn't take the remaining
153 * string length as as argument and is therefore unsafe (nor does it return
154 * the number of characters written). itoa is also not present in ESP32-S2 ROM,
155 * and would need to be placed into IRAM on that chip.
156 * - Third option is to print the message using esp_rom_printf, and not pass anything
157 * to esp_system_abort. However we'd like to capture this information, e.g. for the
158 * purpose of including the abort reason into core dumps.
159 *
160 * Since the source file and line number are already printed while decoding
161 * the panic backtrace, not printing the line number here seems to be an okay choice.
162 */
163 char msg[60] = {};
164 (void) strlcat(msg, "Undefined behavior of type ", sizeof(msg));
165 (void) strlcat(msg, func + strlen("__ubsan_handle_"), sizeof(msg));
166 esp_system_abort(msg);
167 }
168
__ubsan_handle_type_mismatch(struct type_mismatch_data * data,unsigned long ptr)169 void __ubsan_handle_type_mismatch(struct type_mismatch_data *data,
170 unsigned long ptr)
171 {
172 __ubsan_maybe_debugbreak();
173 __ubsan_default_handler(&data->loc, __func__);
174 }
175
__ubsan_handle_type_mismatch_v1(struct type_mismatch_data_v1 * data,unsigned long ptr)176 void __ubsan_handle_type_mismatch_v1(struct type_mismatch_data_v1 *data,
177 unsigned long ptr)
178 {
179 __ubsan_maybe_debugbreak();
180 __ubsan_default_handler(&data->loc, __func__);
181 }
182
__ubsan_handle_add_overflow(struct overflow_data * data,unsigned long lhs,unsigned long rhs)183 void __ubsan_handle_add_overflow(struct overflow_data *data,
184 unsigned long lhs,
185 unsigned long rhs)
186 {
187 __ubsan_maybe_debugbreak();
188 __ubsan_default_handler(&data->loc, __func__);
189 }
190
__ubsan_handle_sub_overflow(struct overflow_data * data,unsigned long lhs,unsigned long rhs)191 void __ubsan_handle_sub_overflow(struct overflow_data *data,
192 unsigned long lhs,
193 unsigned long rhs)
194 {
195 __ubsan_maybe_debugbreak();
196 __ubsan_default_handler(&data->loc, __func__);
197 }
198
__ubsan_handle_mul_overflow(struct overflow_data * data,unsigned long lhs,unsigned long rhs)199 void __ubsan_handle_mul_overflow(struct overflow_data *data,
200 unsigned long lhs,
201 unsigned long rhs)
202 {
203 __ubsan_maybe_debugbreak();
204 __ubsan_default_handler(&data->loc, __func__);
205 }
206
__ubsan_handle_negate_overflow(struct overflow_data * data,unsigned long old_val)207 void __ubsan_handle_negate_overflow(struct overflow_data *data,
208 unsigned long old_val)
209 {
210 __ubsan_maybe_debugbreak();
211 __ubsan_default_handler(&data->loc, __func__);
212 }
213
__ubsan_handle_divrem_overflow(struct overflow_data * data,unsigned long lhs,unsigned long rhs)214 void __ubsan_handle_divrem_overflow(struct overflow_data *data,
215 unsigned long lhs,
216 unsigned long rhs)
217 {
218 __ubsan_maybe_debugbreak();
219 __ubsan_default_handler(&data->loc, __func__);
220 }
221
__ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data * data,unsigned long lhs,unsigned long rhs)222 void __ubsan_handle_shift_out_of_bounds(struct shift_out_of_bounds_data *data,
223 unsigned long lhs,
224 unsigned long rhs)
225 {
226 if (rhs == 32) {
227 return;
228 }
229 __ubsan_maybe_debugbreak();
230 __ubsan_default_handler(&data->loc, __func__);
231 }
232
__ubsan_handle_out_of_bounds(struct out_of_bounds_data * data,unsigned long idx)233 void __ubsan_handle_out_of_bounds(struct out_of_bounds_data *data,
234 unsigned long idx)
235 {
236 __ubsan_maybe_debugbreak();
237 __ubsan_default_handler(&data->loc, __func__);
238 }
239
__ubsan_handle_missing_return(struct unreachable_data * data)240 void __ubsan_handle_missing_return(struct unreachable_data *data)
241 {
242 __ubsan_maybe_debugbreak();
243 __ubsan_default_handler(&data->loc, __func__);
244 }
245
__ubsan_handle_vla_bound_not_positive(struct vla_bound_data * data,unsigned long bound)246 void __ubsan_handle_vla_bound_not_positive(struct vla_bound_data *data,
247 unsigned long bound)
248 {
249 __ubsan_maybe_debugbreak();
250 __ubsan_default_handler(&data->loc, __func__);
251 }
252
__ubsan_handle_load_invalid_value(struct invalid_value_data * data,unsigned long val)253 void __ubsan_handle_load_invalid_value(struct invalid_value_data *data,
254 unsigned long val)
255 {
256 __ubsan_maybe_debugbreak();
257 __ubsan_default_handler(&data->loc, __func__);
258 }
259
__ubsan_handle_nonnull_arg(struct nonnull_arg_data * data)260 void __ubsan_handle_nonnull_arg(struct nonnull_arg_data *data)
261 {
262 __ubsan_maybe_debugbreak();
263 __ubsan_default_handler(&data->loc, __func__);
264 }
265
__ubsan_handle_nonnull_return(struct nonnull_return_data * data)266 void __ubsan_handle_nonnull_return(struct nonnull_return_data *data)
267 {
268 __ubsan_maybe_debugbreak();
269 __ubsan_default_handler(&data->loc, __func__);
270 }
271
__ubsan_handle_builtin_unreachable(struct unreachable_data * data)272 void __ubsan_handle_builtin_unreachable(struct unreachable_data *data)
273 {
274 __ubsan_maybe_debugbreak();
275 __ubsan_default_handler(&data->loc, __func__);
276 }
277
__ubsan_handle_pointer_overflow(struct pointer_overflow_data * data,unsigned long base,unsigned long result)278 void __ubsan_handle_pointer_overflow(struct pointer_overflow_data *data,
279 unsigned long base, unsigned long result)
280 {
281 __ubsan_maybe_debugbreak();
282 __ubsan_default_handler(&data->loc, __func__);
283 }
284
__ubsan_handle_invalid_builtin(struct invalid_builtin_data * data)285 void __ubsan_handle_invalid_builtin(struct invalid_builtin_data *data)
286 {
287 __ubsan_maybe_debugbreak();
288 __ubsan_default_handler(&data->loc, __func__);
289 }
290
291 /* Hook for the linker to include this object file */
__ubsan_include(void)292 void __ubsan_include(void)
293 {
294 }
295