1 /* UndefinedBehaviorSanitizer, undefined behavior detector.
2 Copyright (C) 2013-2021 Free Software Foundation, Inc.
3 Contributed by Marek Polacek <polacek@redhat.com>
4
5 This file is part of GCC.
6
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
11
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tm.h"
25 #include "c-family/c-common.h"
26 #include "ubsan.h"
27 #include "c-family/c-ubsan.h"
28 #include "stor-layout.h"
29 #include "builtins.h"
30 #include "gimplify.h"
31 #include "stringpool.h"
32 #include "attribs.h"
33 #include "asan.h"
34 #include "langhooks.h"
35
36 /* Instrument division by zero and INT_MIN / -1. If not instrumenting,
37 return NULL_TREE. */
38
39 tree
ubsan_instrument_division(location_t loc,tree op0,tree op1)40 ubsan_instrument_division (location_t loc, tree op0, tree op1)
41 {
42 tree t, tt;
43 tree type = TREE_TYPE (op0);
44 enum sanitize_code flag = SANITIZE_DIVIDE;
45
46 /* At this point both operands should have the same type,
47 because they are already converted to RESULT_TYPE.
48 Use TYPE_MAIN_VARIANT since typedefs can confuse us. */
49 tree top0 = TYPE_MAIN_VARIANT (type);
50 tree top1 = TYPE_MAIN_VARIANT (TREE_TYPE (op1));
51 gcc_checking_assert (lang_hooks.types_compatible_p (top0, top1));
52
53 op0 = unshare_expr (op0);
54 op1 = unshare_expr (op1);
55
56 if (TREE_CODE (type) == INTEGER_TYPE
57 && sanitize_flags_p (SANITIZE_DIVIDE))
58 t = fold_build2 (EQ_EXPR, boolean_type_node,
59 op1, build_int_cst (type, 0));
60 else if (TREE_CODE (type) == REAL_TYPE
61 && sanitize_flags_p (SANITIZE_FLOAT_DIVIDE))
62 {
63 t = fold_build2 (EQ_EXPR, boolean_type_node,
64 op1, build_real (type, dconst0));
65 flag = SANITIZE_FLOAT_DIVIDE;
66 }
67 else
68 return NULL_TREE;
69
70 /* We check INT_MIN / -1 only for signed types. */
71 if (TREE_CODE (type) == INTEGER_TYPE
72 && sanitize_flags_p (SANITIZE_DIVIDE)
73 && !TYPE_UNSIGNED (type))
74 {
75 tree x;
76 tt = fold_build2 (EQ_EXPR, boolean_type_node, unshare_expr (op1),
77 build_int_cst (type, -1));
78 x = fold_build2 (EQ_EXPR, boolean_type_node, op0,
79 TYPE_MIN_VALUE (type));
80 x = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, x, tt);
81 t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, x);
82 }
83
84 /* If the condition was folded to 0, no need to instrument
85 this expression. */
86 if (integer_zerop (t))
87 return NULL_TREE;
88
89 /* In case we have a SAVE_EXPR in a conditional context, we need to
90 make sure it gets evaluated before the condition. */
91 t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op0), t);
92 t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op1), t);
93 if (flag_sanitize_undefined_trap_on_error)
94 tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
95 else
96 {
97 tree data = ubsan_create_data ("__ubsan_overflow_data", 1, &loc,
98 ubsan_type_descriptor (type), NULL_TREE,
99 NULL_TREE);
100 data = build_fold_addr_expr_loc (loc, data);
101 enum built_in_function bcode
102 = (flag_sanitize_recover & flag)
103 ? BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW
104 : BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW_ABORT;
105 tt = builtin_decl_explicit (bcode);
106 op0 = unshare_expr (op0);
107 op1 = unshare_expr (op1);
108 tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0),
109 ubsan_encode_value (op1));
110 }
111 t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_node);
112
113 return t;
114 }
115
116 /* Instrument left and right shifts. */
117
118 tree
ubsan_instrument_shift(location_t loc,enum tree_code code,tree op0,tree op1)119 ubsan_instrument_shift (location_t loc, enum tree_code code,
120 tree op0, tree op1)
121 {
122 tree t, tt = NULL_TREE;
123 tree type0 = TREE_TYPE (op0);
124 tree type1 = TREE_TYPE (op1);
125 if (!INTEGRAL_TYPE_P (type0))
126 return NULL_TREE;
127
128 tree op1_utype = unsigned_type_for (type1);
129 HOST_WIDE_INT op0_prec = TYPE_PRECISION (type0);
130 tree uprecm1 = build_int_cst (op1_utype, op0_prec - 1);
131
132 op0 = unshare_expr (op0);
133 op1 = unshare_expr (op1);
134
135 t = fold_convert_loc (loc, op1_utype, op1);
136 t = fold_build2 (GT_EXPR, boolean_type_node, t, uprecm1);
137
138 /* If this is not a signed operation, don't perform overflow checks.
139 Also punt on bit-fields. */
140 if (TYPE_OVERFLOW_WRAPS (type0)
141 || maybe_ne (GET_MODE_BITSIZE (TYPE_MODE (type0)),
142 TYPE_PRECISION (type0))
143 || !sanitize_flags_p (SANITIZE_SHIFT_BASE)
144 /* In C++20 and later, shifts are well defined except when
145 the second operand is not within bounds. */
146 || cxx_dialect >= cxx20)
147 ;
148
149 /* For signed x << y, in C99/C11, the following:
150 (unsigned) x >> (uprecm1 - y)
151 if non-zero, is undefined. */
152 else if (code == LSHIFT_EXPR && flag_isoc99 && cxx_dialect < cxx11)
153 {
154 tree x = fold_build2 (MINUS_EXPR, op1_utype, uprecm1,
155 fold_convert (op1_utype, unshare_expr (op1)));
156 tt = fold_convert_loc (loc, unsigned_type_for (type0), op0);
157 tt = fold_build2 (RSHIFT_EXPR, TREE_TYPE (tt), tt, x);
158 tt = fold_build2 (NE_EXPR, boolean_type_node, tt,
159 build_int_cst (TREE_TYPE (tt), 0));
160 }
161
162 /* For signed x << y, in C++11 and later, the following:
163 x < 0 || ((unsigned) x >> (uprecm1 - y))
164 if > 1, is undefined. */
165 else if (code == LSHIFT_EXPR && cxx_dialect >= cxx11)
166 {
167 tree x = fold_build2 (MINUS_EXPR, op1_utype, uprecm1,
168 fold_convert (op1_utype, unshare_expr (op1)));
169 tt = fold_convert_loc (loc, unsigned_type_for (type0),
170 unshare_expr (op0));
171 tt = fold_build2 (RSHIFT_EXPR, TREE_TYPE (tt), tt, x);
172 tt = fold_build2 (GT_EXPR, boolean_type_node, tt,
173 build_int_cst (TREE_TYPE (tt), 1));
174 x = fold_build2 (LT_EXPR, boolean_type_node, unshare_expr (op0),
175 build_int_cst (type0, 0));
176 tt = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, x, tt);
177 }
178
179 /* If the condition was folded to 0, no need to instrument
180 this expression. */
181 if (integer_zerop (t) && (tt == NULL_TREE || integer_zerop (tt)))
182 return NULL_TREE;
183
184 /* In case we have a SAVE_EXPR in a conditional context, we need to
185 make sure it gets evaluated before the condition. */
186 t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op0), t);
187 t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op1), t);
188
189 enum sanitize_code recover_kind = SANITIZE_SHIFT_EXPONENT;
190 tree else_t = void_node;
191 if (tt)
192 {
193 if (!sanitize_flags_p (SANITIZE_SHIFT_EXPONENT))
194 {
195 t = fold_build1 (TRUTH_NOT_EXPR, boolean_type_node, t);
196 t = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, t, tt);
197 recover_kind = SANITIZE_SHIFT_BASE;
198 }
199 else
200 {
201 if (flag_sanitize_undefined_trap_on_error
202 || ((!(flag_sanitize_recover & SANITIZE_SHIFT_EXPONENT))
203 == (!(flag_sanitize_recover & SANITIZE_SHIFT_BASE))))
204 t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, tt);
205 else
206 else_t = tt;
207 }
208 }
209
210 if (flag_sanitize_undefined_trap_on_error)
211 tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
212 else
213 {
214 tree data = ubsan_create_data ("__ubsan_shift_data", 1, &loc,
215 ubsan_type_descriptor (type0),
216 ubsan_type_descriptor (type1), NULL_TREE,
217 NULL_TREE);
218 data = build_fold_addr_expr_loc (loc, data);
219
220 enum built_in_function bcode
221 = (flag_sanitize_recover & recover_kind)
222 ? BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS
223 : BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS_ABORT;
224 tt = builtin_decl_explicit (bcode);
225 op0 = unshare_expr (op0);
226 op1 = unshare_expr (op1);
227 tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0),
228 ubsan_encode_value (op1));
229 if (else_t != void_node)
230 {
231 bcode = (flag_sanitize_recover & SANITIZE_SHIFT_BASE)
232 ? BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS
233 : BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS_ABORT;
234 tree else_tt = builtin_decl_explicit (bcode);
235 op0 = unshare_expr (op0);
236 op1 = unshare_expr (op1);
237 else_tt = build_call_expr_loc (loc, else_tt, 3, data,
238 ubsan_encode_value (op0),
239 ubsan_encode_value (op1));
240 else_t = fold_build3 (COND_EXPR, void_type_node, else_t,
241 else_tt, void_node);
242 }
243 }
244 t = fold_build3 (COND_EXPR, void_type_node, t, tt, else_t);
245
246 return t;
247 }
248
249 /* Instrument variable length array bound. */
250
251 tree
ubsan_instrument_vla(location_t loc,tree size)252 ubsan_instrument_vla (location_t loc, tree size)
253 {
254 tree type = TREE_TYPE (size);
255 tree t, tt;
256
257 t = fold_build2 (LE_EXPR, boolean_type_node, size, build_int_cst (type, 0));
258 if (flag_sanitize_undefined_trap_on_error)
259 tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
260 else
261 {
262 tree data = ubsan_create_data ("__ubsan_vla_data", 1, &loc,
263 ubsan_type_descriptor (type), NULL_TREE,
264 NULL_TREE);
265 data = build_fold_addr_expr_loc (loc, data);
266 enum built_in_function bcode
267 = (flag_sanitize_recover & SANITIZE_VLA)
268 ? BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE
269 : BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE_ABORT;
270 tt = builtin_decl_explicit (bcode);
271 tt = build_call_expr_loc (loc, tt, 2, data, ubsan_encode_value (size));
272 }
273 t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_node);
274
275 return t;
276 }
277
278 /* Instrument missing return in C++ functions returning non-void. */
279
280 tree
ubsan_instrument_return(location_t loc)281 ubsan_instrument_return (location_t loc)
282 {
283 if (flag_sanitize_undefined_trap_on_error)
284 return build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
285
286 tree data = ubsan_create_data ("__ubsan_missing_return_data", 1, &loc,
287 NULL_TREE, NULL_TREE);
288 tree t = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_MISSING_RETURN);
289 return build_call_expr_loc (loc, t, 1, build_fold_addr_expr_loc (loc, data));
290 }
291
292 /* Instrument array bounds for ARRAY_REFs. We create special builtin,
293 that gets expanded in the sanopt pass, and make an array dimension
294 of it. ARRAY is the array, *INDEX is an index to the array.
295 Return NULL_TREE if no instrumentation is emitted.
296 IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside a ADDR_EXPR. */
297
298 tree
ubsan_instrument_bounds(location_t loc,tree array,tree * index,bool ignore_off_by_one)299 ubsan_instrument_bounds (location_t loc, tree array, tree *index,
300 bool ignore_off_by_one)
301 {
302 tree type = TREE_TYPE (array);
303 tree domain = TYPE_DOMAIN (type);
304
305 if (domain == NULL_TREE || TYPE_MAX_VALUE (domain) == NULL_TREE)
306 return NULL_TREE;
307
308 tree bound = TYPE_MAX_VALUE (domain);
309 if (ignore_off_by_one)
310 bound = fold_build2 (PLUS_EXPR, TREE_TYPE (bound), bound,
311 build_int_cst (TREE_TYPE (bound), 1));
312
313 /* Detect flexible array members and suchlike, unless
314 -fsanitize=bounds-strict. */
315 tree base = get_base_address (array);
316 if (!sanitize_flags_p (SANITIZE_BOUNDS_STRICT)
317 && TREE_CODE (array) == COMPONENT_REF
318 && base && (INDIRECT_REF_P (base) || TREE_CODE (base) == MEM_REF))
319 {
320 tree next = NULL_TREE;
321 tree cref = array;
322
323 /* Walk all structs/unions. */
324 while (TREE_CODE (cref) == COMPONENT_REF)
325 {
326 if (TREE_CODE (TREE_TYPE (TREE_OPERAND (cref, 0))) == RECORD_TYPE)
327 for (next = DECL_CHAIN (TREE_OPERAND (cref, 1));
328 next && TREE_CODE (next) != FIELD_DECL;
329 next = DECL_CHAIN (next))
330 ;
331 if (next)
332 /* Not a last element. Instrument it. */
333 break;
334 /* Ok, this is the last field of the structure/union. But the
335 aggregate containing the field must be the last field too,
336 recursively. */
337 cref = TREE_OPERAND (cref, 0);
338 }
339 if (!next)
340 /* Don't instrument this flexible array member-like array in non-strict
341 -fsanitize=bounds mode. */
342 return NULL_TREE;
343 }
344
345 /* Don't emit instrumentation in the most common cases. */
346 tree idx = NULL_TREE;
347 if (TREE_CODE (*index) == INTEGER_CST)
348 idx = *index;
349 else if (TREE_CODE (*index) == BIT_AND_EXPR
350 && TREE_CODE (TREE_OPERAND (*index, 1)) == INTEGER_CST)
351 idx = TREE_OPERAND (*index, 1);
352 if (idx
353 && TREE_CODE (bound) == INTEGER_CST
354 && tree_int_cst_sgn (idx) >= 0
355 && tree_int_cst_le (idx, bound))
356 return NULL_TREE;
357
358 *index = save_expr (*index);
359 /* Create a "(T *) 0" tree node to describe the array type. */
360 tree zero_with_type = build_int_cst (build_pointer_type (type), 0);
361 return build_call_expr_internal_loc (loc, IFN_UBSAN_BOUNDS,
362 void_type_node, 3, zero_with_type,
363 *index, bound);
364 }
365
366 /* Return true iff T is an array that was instrumented by SANITIZE_BOUNDS. */
367
368 bool
ubsan_array_ref_instrumented_p(const_tree t)369 ubsan_array_ref_instrumented_p (const_tree t)
370 {
371 if (TREE_CODE (t) != ARRAY_REF)
372 return false;
373
374 tree op1 = TREE_OPERAND (t, 1);
375 return TREE_CODE (op1) == COMPOUND_EXPR
376 && TREE_CODE (TREE_OPERAND (op1, 0)) == CALL_EXPR
377 && CALL_EXPR_FN (TREE_OPERAND (op1, 0)) == NULL_TREE
378 && CALL_EXPR_IFN (TREE_OPERAND (op1, 0)) == IFN_UBSAN_BOUNDS;
379 }
380
381 /* Instrument an ARRAY_REF, if it hasn't already been instrumented.
382 IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside a ADDR_EXPR. */
383
384 void
ubsan_maybe_instrument_array_ref(tree * expr_p,bool ignore_off_by_one)385 ubsan_maybe_instrument_array_ref (tree *expr_p, bool ignore_off_by_one)
386 {
387 if (!ubsan_array_ref_instrumented_p (*expr_p)
388 && sanitize_flags_p (SANITIZE_BOUNDS | SANITIZE_BOUNDS_STRICT)
389 && current_function_decl != NULL_TREE)
390 {
391 tree op0 = TREE_OPERAND (*expr_p, 0);
392 tree op1 = TREE_OPERAND (*expr_p, 1);
393 tree e = ubsan_instrument_bounds (EXPR_LOCATION (*expr_p), op0, &op1,
394 ignore_off_by_one);
395 if (e != NULL_TREE)
396 {
397 tree t = copy_node (*expr_p);
398 TREE_OPERAND (t, 1) = build2 (COMPOUND_EXPR, TREE_TYPE (op1),
399 e, op1);
400 *expr_p = t;
401 }
402 }
403 }
404
405 static tree
ubsan_maybe_instrument_reference_or_call(location_t loc,tree op,tree ptype,enum ubsan_null_ckind ckind)406 ubsan_maybe_instrument_reference_or_call (location_t loc, tree op, tree ptype,
407 enum ubsan_null_ckind ckind)
408 {
409 if (!sanitize_flags_p (SANITIZE_ALIGNMENT | SANITIZE_NULL)
410 || current_function_decl == NULL_TREE)
411 return NULL_TREE;
412
413 tree type = TREE_TYPE (ptype);
414 tree orig_op = op;
415 bool instrument = false;
416 unsigned int mina = 0;
417
418 if (sanitize_flags_p (SANITIZE_ALIGNMENT))
419 {
420 mina = min_align_of_type (type);
421 if (mina <= 1)
422 mina = 0;
423 }
424 while ((TREE_CODE (op) == NOP_EXPR
425 || TREE_CODE (op) == NON_LVALUE_EXPR)
426 && TREE_CODE (TREE_TYPE (op)) == POINTER_TYPE)
427 op = TREE_OPERAND (op, 0);
428 if (TREE_CODE (op) == NOP_EXPR
429 && TREE_CODE (TREE_TYPE (op)) == REFERENCE_TYPE)
430 {
431 if (mina && mina > min_align_of_type (TREE_TYPE (TREE_TYPE (op))))
432 instrument = true;
433 }
434 else
435 {
436 if (sanitize_flags_p (SANITIZE_NULL) && TREE_CODE (op) == ADDR_EXPR)
437 {
438 bool strict_overflow_p = false;
439 /* tree_single_nonzero_warnv_p will not return true for non-weak
440 non-automatic decls with -fno-delete-null-pointer-checks,
441 which is disabled during -fsanitize=null. We don't want to
442 instrument those, just weak vars though. */
443 int save_flag_delete_null_pointer_checks
444 = flag_delete_null_pointer_checks;
445 flag_delete_null_pointer_checks = 1;
446 if (!tree_single_nonzero_warnv_p (op, &strict_overflow_p)
447 || strict_overflow_p)
448 instrument = true;
449 flag_delete_null_pointer_checks
450 = save_flag_delete_null_pointer_checks;
451 }
452 else if (sanitize_flags_p (SANITIZE_NULL))
453 instrument = true;
454 if (mina && mina > 1)
455 {
456 if (!POINTER_TYPE_P (TREE_TYPE (op))
457 || mina > get_pointer_alignment (op) / BITS_PER_UNIT)
458 instrument = true;
459 }
460 }
461 if (!instrument)
462 return NULL_TREE;
463 op = save_expr (orig_op);
464 gcc_assert (POINTER_TYPE_P (ptype));
465 if (TREE_CODE (ptype) == REFERENCE_TYPE)
466 ptype = build_pointer_type (TREE_TYPE (ptype));
467 tree kind = build_int_cst (ptype, ckind);
468 tree align = build_int_cst (pointer_sized_int_node, mina);
469 tree call
470 = build_call_expr_internal_loc (loc, IFN_UBSAN_NULL, void_type_node,
471 3, op, kind, align);
472 TREE_SIDE_EFFECTS (call) = 1;
473 return fold_build2 (COMPOUND_EXPR, TREE_TYPE (op), call, op);
474 }
475
476 /* Instrument a NOP_EXPR to REFERENCE_TYPE or INTEGER_CST with REFERENCE_TYPE
477 type if needed. */
478
479 void
ubsan_maybe_instrument_reference(tree * stmt_p)480 ubsan_maybe_instrument_reference (tree *stmt_p)
481 {
482 tree stmt = *stmt_p;
483 tree op = stmt;
484 if (TREE_CODE (stmt) == NOP_EXPR)
485 op = TREE_OPERAND (stmt, 0);
486 op = ubsan_maybe_instrument_reference_or_call (EXPR_LOCATION (stmt), op,
487 TREE_TYPE (stmt),
488 UBSAN_REF_BINDING);
489 if (op)
490 {
491 if (TREE_CODE (stmt) == NOP_EXPR)
492 TREE_OPERAND (stmt, 0) = op;
493 else
494 *stmt_p = op;
495 }
496 }
497
498 /* Instrument a CALL_EXPR to a method if needed. */
499
500 void
ubsan_maybe_instrument_member_call(tree stmt,bool is_ctor)501 ubsan_maybe_instrument_member_call (tree stmt, bool is_ctor)
502 {
503 if (call_expr_nargs (stmt) == 0)
504 return;
505 tree op = CALL_EXPR_ARG (stmt, 0);
506 if (op == error_mark_node
507 || !POINTER_TYPE_P (TREE_TYPE (op)))
508 return;
509 op = ubsan_maybe_instrument_reference_or_call (EXPR_LOCATION (stmt), op,
510 TREE_TYPE (op),
511 is_ctor ? UBSAN_CTOR_CALL
512 : UBSAN_MEMBER_CALL);
513 if (op)
514 CALL_EXPR_ARG (stmt, 0) = op;
515 }
516