Line data Source code
1 : /* UndefinedBehaviorSanitizer, undefined behavior detector.
2 : Copyright (C) 2013-2026 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
40 1377 : ubsan_instrument_division (location_t loc, tree op0, tree op1)
41 : {
42 1377 : tree t, tt, x = NULL_TREE;
43 1377 : tree type = TREE_TYPE (op0);
44 1377 : 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 1377 : tree top0 = TYPE_MAIN_VARIANT (type);
50 1377 : tree top1 = TYPE_MAIN_VARIANT (TREE_TYPE (op1));
51 1377 : gcc_checking_assert (lang_hooks.types_compatible_p (top0, top1));
52 :
53 1377 : op0 = unshare_expr (op0);
54 1377 : op1 = unshare_expr (op1);
55 :
56 1377 : if (INTEGRAL_TYPE_P (type)
57 1377 : && sanitize_flags_p (SANITIZE_DIVIDE))
58 901 : t = fold_build2 (EQ_EXPR, boolean_type_node,
59 : op1, build_int_cst (type, 0));
60 476 : else if (SCALAR_FLOAT_TYPE_P (type)
61 476 : && sanitize_flags_p (SANITIZE_FLOAT_DIVIDE))
62 : {
63 96 : t = fold_build2 (EQ_EXPR, boolean_type_node,
64 : op1, build_real (type, dconst0));
65 96 : flag = SANITIZE_FLOAT_DIVIDE;
66 : }
67 : else
68 : t = NULL_TREE;
69 :
70 : /* We check INT_MIN / -1 only for signed types. */
71 1377 : if (INTEGRAL_TYPE_P (type)
72 1166 : && sanitize_flags_p (SANITIZE_SI_OVERFLOW)
73 2268 : && !TYPE_UNSIGNED (type))
74 : {
75 759 : tt = fold_build2 (EQ_EXPR, boolean_type_node, unshare_expr (op1),
76 : build_int_cst (type, -1));
77 759 : x = fold_build2 (EQ_EXPR, boolean_type_node, op0,
78 : TYPE_MIN_VALUE (type));
79 759 : x = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, x, tt);
80 759 : if (t == NULL_TREE || integer_zerop (t))
81 : {
82 : t = x;
83 : x = NULL_TREE;
84 : flag = SANITIZE_SI_OVERFLOW;
85 : }
86 301 : else if ((((flag_sanitize_trap & SANITIZE_DIVIDE) == 0)
87 301 : == ((flag_sanitize_trap & SANITIZE_SI_OVERFLOW) == 0))
88 301 : && (((flag_sanitize_recover & SANITIZE_DIVIDE) == 0)
89 301 : == ((flag_sanitize_recover & SANITIZE_SI_OVERFLOW) == 0)))
90 : {
91 260 : t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, x);
92 260 : x = NULL_TREE;
93 : }
94 41 : else if (integer_zerop (x))
95 482 : x = NULL_TREE;
96 : }
97 618 : else if (t == NULL_TREE)
98 : return NULL_TREE;
99 :
100 : /* If the condition was folded to 0, no need to instrument
101 : this expression. */
102 1241 : if (integer_zerop (t))
103 : return NULL_TREE;
104 :
105 : /* In case we have a SAVE_EXPR in a conditional context, we need to
106 : make sure it gets evaluated before the condition. */
107 786 : t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op0), t);
108 786 : t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op1), t);
109 786 : if ((flag_sanitize_trap & flag) && x == NULL_TREE)
110 10 : tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
111 : else
112 : {
113 776 : tree data = ubsan_create_data ("__ubsan_overflow_data", 1, &loc,
114 : ubsan_type_descriptor (type), NULL_TREE,
115 : NULL_TREE);
116 776 : data = build_fold_addr_expr_loc (loc, data);
117 776 : if (flag_sanitize_trap & flag)
118 0 : tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP),
119 : 0);
120 : else
121 : {
122 115 : enum built_in_function bcode
123 776 : = (flag_sanitize_recover & flag)
124 776 : ? BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW
125 : : BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW_ABORT;
126 776 : tt = builtin_decl_explicit (bcode);
127 776 : op0 = unshare_expr (op0);
128 776 : op1 = unshare_expr (op1);
129 776 : tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0),
130 : ubsan_encode_value (op1));
131 : }
132 776 : if (x)
133 : {
134 41 : tree xt;
135 41 : if (flag_sanitize_trap & SANITIZE_SI_OVERFLOW)
136 0 : xt = build_call_expr_loc (loc,
137 : builtin_decl_explicit (BUILT_IN_TRAP),
138 : 0);
139 : else
140 : {
141 16 : enum built_in_function bcode
142 41 : = (flag_sanitize_recover & SANITIZE_SI_OVERFLOW)
143 41 : ? BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW
144 : : BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW_ABORT;
145 41 : xt = builtin_decl_explicit (bcode);
146 41 : op0 = unshare_expr (op0);
147 41 : op1 = unshare_expr (op1);
148 41 : xt = build_call_expr_loc (loc, xt, 3, data,
149 : ubsan_encode_value (op0),
150 : ubsan_encode_value (op1));
151 : }
152 41 : x = fold_build3 (COND_EXPR, void_type_node, x, xt, void_node);
153 : }
154 : }
155 786 : t = fold_build3 (COND_EXPR, void_type_node, t, tt, x ? x : void_node);
156 :
157 786 : return t;
158 : }
159 :
160 : /* Instrument left and right shifts. */
161 :
162 : tree
163 2183 : ubsan_instrument_shift (location_t loc, enum tree_code code,
164 : tree op0, tree op1)
165 : {
166 2183 : tree t, tt = NULL_TREE;
167 2183 : tree type0 = TREE_TYPE (op0);
168 2183 : tree type1 = TREE_TYPE (op1);
169 2183 : if (!INTEGRAL_TYPE_P (type0))
170 : return NULL_TREE;
171 :
172 2169 : tree op1_utype = unsigned_type_for (type1);
173 2169 : HOST_WIDE_INT op0_prec = TYPE_PRECISION (type0);
174 2169 : tree uprecm1 = build_int_cst (op1_utype, op0_prec - 1);
175 :
176 2169 : op0 = unshare_expr (op0);
177 2169 : op1 = unshare_expr (op1);
178 :
179 2169 : if (code == LROTATE_EXPR || code == RROTATE_EXPR)
180 : {
181 : /* For rotates just check for negative op1. */
182 28 : if (TYPE_UNSIGNED (type1))
183 : return NULL_TREE;
184 28 : t = fold_build2 (LT_EXPR, boolean_type_node, op1,
185 : build_int_cst (type1, 0));
186 : }
187 : else
188 : {
189 2141 : t = fold_convert_loc (loc, op1_utype, op1);
190 2141 : t = fold_build2 (GT_EXPR, boolean_type_node, t, uprecm1);
191 : }
192 :
193 : /* If this is not a signed operation, don't perform overflow checks.
194 : Also punt on bit-fields. */
195 2169 : if (TYPE_OVERFLOW_WRAPS (type0)
196 2804 : || maybe_ne (GET_MODE_BITSIZE (TYPE_MODE (type0)),
197 1402 : TYPE_PRECISION (type0))
198 1322 : || !sanitize_flags_p (SANITIZE_SHIFT_BASE)
199 : /* In C++20 and later, shifts are well defined except when
200 : the second operand is not within bounds. */
201 1271 : || cxx_dialect >= cxx20)
202 : ;
203 :
204 : /* For signed x << y, in C99 and later, the following:
205 : (unsigned) x >> (uprecm1 - y)
206 : if non-zero, is undefined. */
207 1082 : else if (code == LSHIFT_EXPR && flag_isoc99 && cxx_dialect < cxx11)
208 : {
209 766 : tree x = fold_build2 (MINUS_EXPR, op1_utype, uprecm1,
210 : fold_convert (op1_utype, unshare_expr (op1)));
211 766 : tt = fold_convert_loc (loc, unsigned_type_for (type0), op0);
212 766 : tt = fold_build2 (RSHIFT_EXPR, TREE_TYPE (tt), tt, x);
213 766 : tt = fold_build2 (NE_EXPR, boolean_type_node, tt,
214 : build_int_cst (TREE_TYPE (tt), 0));
215 766 : }
216 :
217 : /* For signed x << y, in C++11 to C++17, the following:
218 : x < 0 || ((unsigned) x >> (uprecm1 - y))
219 : if > 1, is undefined. */
220 82 : else if (code == LSHIFT_EXPR && cxx_dialect >= cxx11)
221 : {
222 22 : tree x = fold_build2 (MINUS_EXPR, op1_utype, uprecm1,
223 : fold_convert (op1_utype, unshare_expr (op1)));
224 22 : tt = fold_convert_loc (loc, unsigned_type_for (type0),
225 : unshare_expr (op0));
226 22 : tt = fold_build2 (RSHIFT_EXPR, TREE_TYPE (tt), tt, x);
227 22 : tt = fold_build2 (GT_EXPR, boolean_type_node, tt,
228 : build_int_cst (TREE_TYPE (tt), 1));
229 22 : x = fold_build2 (LT_EXPR, boolean_type_node, unshare_expr (op0),
230 : build_int_cst (type0, 0));
231 22 : tt = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, x, tt);
232 : }
233 :
234 : /* If the condition was folded to 0, no need to instrument
235 : this expression. */
236 2169 : if (integer_zerop (t) && (tt == NULL_TREE || integer_zerop (tt)))
237 1145 : return NULL_TREE;
238 :
239 : /* In case we have a SAVE_EXPR in a conditional context, we need to
240 : make sure it gets evaluated before the condition. */
241 1024 : t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op0), t);
242 1024 : t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op1), t);
243 :
244 1024 : enum sanitize_code recover_kind = SANITIZE_SHIFT_EXPONENT;
245 1024 : tree else_t = void_node;
246 1024 : if (tt)
247 : {
248 487 : if (!sanitize_flags_p (SANITIZE_SHIFT_EXPONENT))
249 : {
250 28 : t = fold_build1 (TRUTH_NOT_EXPR, boolean_type_node, t);
251 28 : t = fold_build2 (TRUTH_AND_EXPR, boolean_type_node, t, tt);
252 28 : recover_kind = SANITIZE_SHIFT_BASE;
253 : }
254 : else
255 : {
256 459 : if (((!(flag_sanitize_trap & SANITIZE_SHIFT_EXPONENT))
257 459 : == (!(flag_sanitize_trap & SANITIZE_SHIFT_BASE)))
258 459 : && ((!(flag_sanitize_recover & SANITIZE_SHIFT_EXPONENT))
259 459 : == (!(flag_sanitize_recover & SANITIZE_SHIFT_BASE))))
260 392 : t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, tt);
261 : else
262 : else_t = tt;
263 : }
264 : }
265 :
266 1024 : if ((flag_sanitize_trap & recover_kind) && else_t == void_node)
267 0 : tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
268 : else
269 : {
270 1024 : if (TREE_CODE (type1) == BITINT_TYPE
271 1056 : && TYPE_PRECISION (type1) > MAX_FIXED_MODE_SIZE)
272 : {
273 : /* Workaround for missing _BitInt support in libsanitizer.
274 : Instead of crashing in the library, pretend values above
275 : maximum value of normal integral type or below minimum value
276 : of that type are those extremes. */
277 32 : tree type2 = build_nonstandard_integer_type (MAX_FIXED_MODE_SIZE,
278 32 : TYPE_UNSIGNED (type1));
279 32 : tree op2 = op1;
280 32 : if (!TYPE_UNSIGNED (type1))
281 : {
282 32 : op2 = fold_build2 (LT_EXPR, boolean_type_node, unshare_expr (op1),
283 : fold_convert (type1, TYPE_MIN_VALUE (type2)));
284 32 : op2 = fold_build3 (COND_EXPR, type2, op2, TYPE_MIN_VALUE (type2),
285 : fold_convert (type2, unshare_expr (op1)));
286 : }
287 : else
288 0 : op2 = fold_convert (type2, op1);
289 32 : tree op3
290 32 : = fold_build2 (GT_EXPR, boolean_type_node, unshare_expr (op1),
291 : fold_convert (type1, TYPE_MAX_VALUE (type2)));
292 32 : op1 = fold_build3 (COND_EXPR, type2, op3, TYPE_MAX_VALUE (type2),
293 : op2);
294 32 : type1 = type2;
295 : }
296 1024 : tree utd0 = ubsan_type_descriptor (type0, UBSAN_PRINT_FORCE_INT);
297 1024 : tree data = ubsan_create_data ("__ubsan_shift_data", 1, &loc, utd0,
298 : ubsan_type_descriptor (type1), NULL_TREE,
299 : NULL_TREE);
300 1024 : data = build_fold_addr_expr_loc (loc, data);
301 :
302 1024 : if (flag_sanitize_trap & recover_kind)
303 0 : tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
304 : else
305 : {
306 152 : enum built_in_function bcode
307 1024 : = (flag_sanitize_recover & recover_kind)
308 1024 : ? BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS
309 : : BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS_ABORT;
310 1024 : tt = builtin_decl_explicit (bcode);
311 1024 : op0 = unshare_expr (op0);
312 1024 : op1 = unshare_expr (op1);
313 1024 : tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0),
314 : ubsan_encode_value (op1));
315 : }
316 1024 : if (else_t != void_node)
317 : {
318 67 : tree else_tt;
319 67 : if (flag_sanitize_trap & SANITIZE_SHIFT_BASE)
320 0 : else_tt
321 0 : = build_call_expr_loc (loc,
322 : builtin_decl_explicit (BUILT_IN_TRAP), 0);
323 : else
324 : {
325 32 : enum built_in_function bcode
326 67 : = (flag_sanitize_recover & SANITIZE_SHIFT_BASE)
327 67 : ? BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS
328 : : BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS_ABORT;
329 67 : else_tt = builtin_decl_explicit (bcode);
330 67 : op0 = unshare_expr (op0);
331 67 : op1 = unshare_expr (op1);
332 67 : else_tt = build_call_expr_loc (loc, else_tt, 3, data,
333 : ubsan_encode_value (op0),
334 : ubsan_encode_value (op1));
335 : }
336 67 : else_t = fold_build3 (COND_EXPR, void_type_node, else_t,
337 : else_tt, void_node);
338 : }
339 : }
340 1024 : t = fold_build3 (COND_EXPR, void_type_node, t, tt, else_t);
341 :
342 1024 : return t;
343 : }
344 :
345 : /* Instrument variable length array bound. */
346 :
347 : tree
348 233 : ubsan_instrument_vla (location_t loc, tree size)
349 : {
350 233 : tree type = TREE_TYPE (size);
351 233 : tree t, tt;
352 :
353 233 : t = fold_build2 (LE_EXPR, boolean_type_node, size, build_int_cst (type, 0));
354 233 : if (flag_sanitize_trap & SANITIZE_VLA)
355 0 : tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
356 : else
357 : {
358 233 : tree data = ubsan_create_data ("__ubsan_vla_data", 1, &loc,
359 : ubsan_type_descriptor (type), NULL_TREE,
360 : NULL_TREE);
361 233 : data = build_fold_addr_expr_loc (loc, data);
362 12 : enum built_in_function bcode
363 233 : = (flag_sanitize_recover & SANITIZE_VLA)
364 233 : ? BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE
365 : : BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE_ABORT;
366 233 : tt = builtin_decl_explicit (bcode);
367 233 : tt = build_call_expr_loc (loc, tt, 2, data, ubsan_encode_value (size));
368 : }
369 233 : t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_node);
370 :
371 233 : return t;
372 : }
373 :
374 : /* Instrument missing return in C++ functions returning non-void. */
375 :
376 : tree
377 1799 : ubsan_instrument_return (location_t loc)
378 : {
379 1799 : if (flag_sanitize_trap & SANITIZE_RETURN)
380 : /* pass_warn_function_return checks for BUILTINS_LOCATION. */
381 3 : return build_call_expr_loc (BUILTINS_LOCATION,
382 3 : builtin_decl_explicit (BUILT_IN_TRAP), 0);
383 :
384 1796 : tree data = ubsan_create_data ("__ubsan_missing_return_data", 1, &loc,
385 : NULL_TREE, NULL_TREE);
386 1796 : tree t = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_MISSING_RETURN);
387 1796 : return build_call_expr_loc (loc, t, 1, build_fold_addr_expr_loc (loc, data));
388 : }
389 :
390 : /* Get the tree that represented the number of counted_by, i.e, the maximum
391 : number of the elements of the object that the call to .ACCESS_WITH_SIZE
392 : points to, this number will be the bound of the corresponding array. */
393 : static tree
394 226 : get_bound_from_access_with_size (tree call)
395 : {
396 226 : if (!is_access_with_size_p (call))
397 : return NULL_TREE;
398 :
399 226 : tree ref_to_size = CALL_EXPR_ARG (call, 1);
400 226 : tree type = TREE_TYPE (TREE_TYPE (CALL_EXPR_ARG (call, 2)));
401 226 : tree size = fold_build2 (MEM_REF, type, unshare_expr (ref_to_size),
402 : build_int_cst (ptr_type_node, 0));
403 : /* If size is negative value, treat it as zero. */
404 226 : if (!TYPE_UNSIGNED (type))
405 : {
406 226 : tree cond = fold_build2 (LT_EXPR, boolean_type_node,
407 : unshare_expr (size), build_zero_cst (type));
408 226 : size = fold_build3 (COND_EXPR, type, cond,
409 : build_zero_cst (type), size);
410 : }
411 :
412 226 : size = fold_convert (sizetype, size);
413 :
414 226 : return size;
415 : }
416 :
417 :
418 : /* Instrument array bounds for ARRAY_REFs. We create special builtin,
419 : that gets expanded in the sanopt pass, and make an array dimension
420 : of it. ARRAY is the array, *INDEX is an index to the array.
421 : Return NULL_TREE if no instrumentation is emitted.
422 : IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside an ADDR_EXPR. */
423 :
424 : tree
425 4314 : ubsan_instrument_bounds (location_t loc, tree array, tree *index,
426 : bool ignore_off_by_one)
427 : {
428 4314 : tree type = TREE_TYPE (array);
429 4314 : tree domain = TYPE_DOMAIN (type);
430 :
431 4314 : if (domain == NULL_TREE)
432 : return NULL_TREE;
433 :
434 4302 : tree bound = TYPE_MAX_VALUE (domain);
435 4302 : if (!bound)
436 : {
437 : /* Handle C [0] arrays, which have TYPE_MAX_VALUE NULL, like
438 : C++ [0] arrays which have TYPE_MIN_VALUE 0 TYPE_MAX_VALUE -1. */
439 260 : if (!c_dialect_cxx ()
440 260 : && COMPLETE_TYPE_P (type)
441 379 : && integer_zerop (TYPE_SIZE (type)))
442 119 : bound = build_int_cst (TREE_TYPE (TYPE_MIN_VALUE (domain)), -1);
443 141 : else if (INDIRECT_REF_P (array)
444 141 : && is_access_with_size_p ((TREE_OPERAND (array, 0))))
445 : {
446 69 : bound = get_bound_from_access_with_size ((TREE_OPERAND (array, 0)));
447 69 : bound = fold_build2 (MINUS_EXPR, TREE_TYPE (bound),
448 : bound,
449 : build_int_cst (TREE_TYPE (bound), 1));
450 : }
451 : else
452 72 : return NULL_TREE;
453 : }
454 :
455 4230 : bound = fold_build2 (PLUS_EXPR, TREE_TYPE (bound), bound,
456 : build_int_cst (TREE_TYPE (bound),
457 : 1 + ignore_off_by_one));
458 :
459 : /* Detect flexible array members and suchlike, unless
460 : -fsanitize=bounds-strict. */
461 4230 : tree base = get_base_address (array);
462 4230 : if (!sanitize_flags_p (SANITIZE_BOUNDS_STRICT)
463 4198 : && TREE_CODE (array) == COMPONENT_REF
464 5153 : && base && (INDIRECT_REF_P (base) || TREE_CODE (base) == MEM_REF))
465 : {
466 : tree next = NULL_TREE;
467 : tree cref = array;
468 :
469 : /* Walk all structs/unions. */
470 845 : while (TREE_CODE (cref) == COMPONENT_REF)
471 : {
472 618 : if (TREE_CODE (TREE_TYPE (TREE_OPERAND (cref, 0))) == RECORD_TYPE)
473 606 : for (next = DECL_CHAIN (TREE_OPERAND (cref, 1));
474 4193 : next && TREE_CODE (next) != FIELD_DECL;
475 3587 : next = DECL_CHAIN (next))
476 : ;
477 618 : if (next)
478 : /* Not a last element. Instrument it. */
479 : break;
480 377 : if (TREE_CODE (TREE_TYPE (TREE_OPERAND (cref, 1))) == ARRAY_TYPE
481 377 : && !c_dialect_cxx ())
482 : {
483 268 : unsigned l
484 268 : = c_strict_flex_array_level_of (TREE_OPERAND (cref, 1));
485 268 : tree type2 = TREE_TYPE (TREE_OPERAND (cref, 1));
486 268 : if (TYPE_DOMAIN (type2) != NULL_TREE)
487 : {
488 268 : tree max = TYPE_MAX_VALUE (TYPE_DOMAIN (type2));
489 268 : if (max == NULL_TREE)
490 : {
491 : /* C [0] */
492 47 : if (COMPLETE_TYPE_P (type2)
493 47 : && integer_zerop (TYPE_SIZE (type2))
494 94 : && l == 3)
495 8 : next = TREE_OPERAND (cref, 1);
496 : }
497 221 : else if (TREE_CODE (max) == INTEGER_CST)
498 : {
499 221 : if (c_dialect_cxx ()
500 221 : && integer_all_onesp (max))
501 : {
502 : /* C++ [0] */
503 0 : if (l == 3)
504 0 : next = TREE_OPERAND (cref, 1);
505 : }
506 221 : else if (integer_zerop (max))
507 : {
508 : /* C/C++ [1] */
509 95 : if (l >= 2)
510 16 : next = TREE_OPERAND (cref, 1);
511 : }
512 126 : else if (l >= 1)
513 48 : next = TREE_OPERAND (cref, 1);
514 : }
515 : }
516 268 : if (next)
517 : break;
518 : }
519 : /* Ok, this is the last field of the structure/union. But the
520 : aggregate containing the field must be the last field too,
521 : recursively. */
522 305 : cref = TREE_OPERAND (cref, 0);
523 : }
524 540 : if (!next)
525 : /* Don't instrument this flexible array member-like array in non-strict
526 : -fsanitize=bounds mode. */
527 : return NULL_TREE;
528 : }
529 :
530 : /* Don't emit instrumentation in the most common cases. */
531 4003 : tree idx = NULL_TREE;
532 4003 : if (TREE_CODE (*index) == INTEGER_CST)
533 : idx = *index;
534 759 : else if (TREE_CODE (*index) == BIT_AND_EXPR
535 759 : && TREE_CODE (TREE_OPERAND (*index, 1)) == INTEGER_CST)
536 26 : idx = TREE_OPERAND (*index, 1);
537 3270 : if (idx
538 3270 : && TREE_CODE (bound) == INTEGER_CST
539 2951 : && tree_int_cst_sgn (idx) >= 0
540 6199 : && tree_int_cst_lt (idx, bound))
541 : return NULL_TREE;
542 :
543 1567 : *index = save_expr (*index);
544 : /* If TYPE is a VLA, use 1 instead of 0 as the first argument and
545 : use just the addend to TYPE_MAX_VALUE (domain) as the third argument
546 : temporarily, so that gimplification can use TYPE_MAX_VALUE (domain)
547 : after gimplify_type_sizes. See PR120052. */
548 1567 : bool is_vla = (TYPE_MAX_VALUE (domain)
549 1567 : && TREE_CODE (TYPE_MAX_VALUE (domain)) != INTEGER_CST);
550 406 : if (is_vla)
551 406 : bound = build_int_cst (TREE_TYPE (bound), 1 + ignore_off_by_one);
552 : /* Create a "(T *) 0" (or 1) tree node to describe the array type. */
553 1567 : tree zero_with_type = build_int_cst (build_pointer_type (type), is_vla);
554 1567 : return build_call_expr_internal_loc (loc, IFN_UBSAN_BOUNDS,
555 : void_type_node, 3, zero_with_type,
556 1567 : *index, bound);
557 : }
558 :
559 :
560 : /* Instrument array bounds for the pointer array address which is
561 : a call to .ACCESS_WITH_SIZE. We create special
562 : builtin, that gets expanded in the sanopt pass, and make an array
563 : dimention of it. POINTER_ADDR is the pointer array's base address.
564 : *INDEX is an index to the array.
565 : IGNORE_OFF_BY_ONE is true if the POINTER_ADDR is not inside an
566 : INDIRECT_REF.
567 : Return NULL_TREE if no instrumentation is emitted. */
568 :
569 : tree
570 157 : ubsan_instrument_bounds_pointer_address (location_t loc, tree pointer_addr,
571 : tree *index,
572 : bool ignore_off_by_one)
573 : {
574 157 : tree call = pointer_addr;
575 157 : if (!is_access_with_size_p (call))
576 : return NULL_TREE;
577 157 : tree bound = get_bound_from_access_with_size (call);
578 :
579 157 : if (ignore_off_by_one)
580 0 : bound = fold_build2 (PLUS_EXPR, TREE_TYPE (bound), bound,
581 : build_int_cst (TREE_TYPE (bound),
582 : 1));
583 :
584 : /* Don't emit instrumentation in the most common cases. */
585 157 : tree idx = NULL_TREE;
586 157 : if (TREE_CODE (*index) == INTEGER_CST)
587 : idx = *index;
588 45 : else if (TREE_CODE (*index) == BIT_AND_EXPR
589 45 : && TREE_CODE (TREE_OPERAND (*index, 1)) == INTEGER_CST)
590 0 : idx = TREE_OPERAND (*index, 1);
591 112 : if (idx
592 112 : && TREE_CODE (bound) == INTEGER_CST
593 0 : && tree_int_cst_sgn (idx) >= 0
594 112 : && tree_int_cst_lt (idx, bound))
595 : return NULL_TREE;
596 :
597 157 : *index = save_expr (*index);
598 :
599 : /* Create an array_type for the corresponding pointer array. */
600 157 : tree itype = build_range_type (sizetype, size_zero_node, NULL_TREE);
601 : /* The array's element type can be get from the return type of the call to
602 : .ACCESS_WITH_SIZE. */
603 157 : tree element_type = TREE_TYPE (TREE_TYPE (call));
604 157 : tree array_type = build_array_type (element_type, itype);
605 : /* Create a "(T *) 0" tree node to describe the array type. */
606 157 : tree zero_with_type = build_int_cst (build_pointer_type (array_type), 0);
607 157 : return build_call_expr_internal_loc (loc, IFN_UBSAN_BOUNDS,
608 : void_type_node, 3, zero_with_type,
609 157 : *index, bound);
610 : }
611 :
612 : /* This structure is to combine a factor with its parent and its position
613 : * in its parent tree. */
614 : struct factor_t
615 : {
616 : tree factor;
617 : tree parent; /* the parent tree of this factor. */
618 : int pos; /* the position of this factor in its parent tree. */
619 : };
620 :
621 : /* for a multiply expression like:
622 : ((long unsigned int) m * (long unsigned int) SAVE_EXPR <n>) * 4
623 :
624 : locate all the factors, the parents of the factor and the position of
625 : the factor in its parent, and put them to VEC_FACTORS. */
626 :
627 : static void
628 183 : get_factors_from_mul_expr (tree mult_expr, tree parent,
629 : int pos, auto_vec<factor_t> *vec_factors)
630 : {
631 276 : struct factor_t mult_factor = {0, 0, -1};
632 276 : mult_factor.factor = mult_expr;
633 276 : mult_factor.parent = parent;
634 276 : mult_factor.pos = pos;
635 :
636 377 : while (CONVERT_EXPR_CODE_P (TREE_CODE (mult_expr)))
637 : {
638 101 : mult_factor.parent = mult_expr;
639 101 : mult_factor.pos = 0;
640 101 : mult_expr = TREE_OPERAND (mult_expr, 0);
641 101 : mult_factor.factor = mult_expr;
642 : }
643 276 : if (TREE_CODE (mult_expr) != MULT_EXPR)
644 183 : vec_factors->safe_push (mult_factor);
645 : else
646 : {
647 93 : get_factors_from_mul_expr (TREE_OPERAND (mult_expr, 0), mult_expr,
648 : 0, vec_factors);
649 93 : get_factors_from_mul_expr (TREE_OPERAND (mult_expr, 1), mult_expr,
650 : 1, vec_factors);
651 : }
652 183 : }
653 :
654 : /* Given an OFFSET expression, and the ELEMENT_SIZE,
655 : get the index expression from OFFSET and return it.
656 : For example:
657 : OFFSET:
658 : ((long unsigned int) m * (long unsigned int) SAVE_EXPR <n>) * 4
659 : ELEMENT_SIZE:
660 : (sizetype) SAVE_EXPR <n> * 4
661 : get the index as (long unsigned int) m, and return it.
662 : One special case is when the OFFSET is an integer constant, and the
663 : element_size is also an integer constant, we should get the index
664 : as OFFSET/element_size.
665 : The INDEX_P holds the pointer to the parent tree of the index,
666 : INDEX_N holds the position of the index in its parent. */
667 :
668 : static tree
669 109 : get_index_from_offset (tree offset, tree *index_p,
670 : int *index_n, tree element_size)
671 : {
672 109 : if (TREE_CODE (offset) != MULT_EXPR
673 64 : && TREE_CODE (offset) != INTEGER_CST)
674 : return NULL_TREE;
675 :
676 109 : if (TREE_CODE (offset) == INTEGER_CST
677 64 : && TREE_CODE (element_size) != INTEGER_CST)
678 : return NULL_TREE;
679 :
680 109 : if (TREE_CODE (offset) == INTEGER_CST
681 64 : && TREE_CODE (element_size) == INTEGER_CST)
682 64 : return fold_build2 (EXACT_DIV_EXPR, TREE_TYPE (offset),
683 : offset, element_size);
684 :
685 45 : auto_vec<factor_t> e_factors, o_factors;
686 45 : get_factors_from_mul_expr (element_size, NULL, -1, &e_factors);
687 45 : get_factors_from_mul_expr (offset, *index_p, *index_n, &o_factors);
688 :
689 90 : if (e_factors.is_empty () || o_factors.is_empty ())
690 : return NULL_TREE;
691 :
692 : bool all_found = true;
693 114 : for (unsigned i = 0; i < e_factors.length (); i++)
694 : {
695 69 : factor_t e_size_factor = e_factors[i];
696 69 : bool found = false;
697 215 : for (unsigned j = 0; j < o_factors.length ();)
698 : {
699 146 : factor_t o_exp_factor = o_factors[j];
700 146 : if (operand_equal_p (e_size_factor.factor, o_exp_factor.factor))
701 : {
702 69 : o_factors.unordered_remove (j);
703 69 : found = true;
704 69 : break;
705 : }
706 : else
707 77 : j++;
708 : }
709 69 : if (!found)
710 : all_found = false;
711 : }
712 :
713 45 : if (!all_found)
714 : return NULL_TREE;
715 :
716 45 : if (o_factors.length () != 1)
717 : return NULL_TREE;
718 :
719 45 : *index_p = o_factors[0].parent;
720 45 : *index_n = o_factors[0].pos;
721 45 : return o_factors[0].factor;
722 45 : }
723 :
724 : /* For an pointer + offset computation expression, such as,
725 : .ACCESS_WITH_SIZE (p->c, &p->b, 1, 0, -1, 0B)
726 : + (sizetype) ((long unsigned int) index * 4
727 : Return the index of this pointer array reference,
728 : set the parent tree of INDEX to *INDEX_P.
729 : set the operand position of the INDEX in the parent tree to *INDEX_N.
730 : If failed, return NULL_TREE. */
731 :
732 : static tree
733 157 : get_index_from_pointer_addr_expr (tree pointer, tree *index_p, int *index_n)
734 : {
735 157 : *index_p = NULL_TREE;
736 157 : *index_n = -1;
737 157 : tree call = TREE_OPERAND (pointer, 0);
738 157 : if (!is_access_with_size_p (call))
739 : return NULL_TREE;
740 :
741 : /* Get the pointee type of the call to .ACCESS_WITH_SIZE.
742 : This should be the element type of the pointer array. */
743 157 : tree pointee_type = TREE_TYPE (TREE_TYPE (call));
744 157 : tree pointee_size = TYPE_SIZE_UNIT (pointee_type);
745 :
746 157 : tree index_exp = TREE_OPERAND (pointer, 1);
747 157 : *index_p = pointer;
748 157 : *index_n = 1;
749 :
750 314 : if (!(TREE_CODE (index_exp) != MULT_EXPR
751 157 : && tree_int_cst_equal (pointee_size, integer_one_node)))
752 : {
753 154 : while (CONVERT_EXPR_CODE_P (TREE_CODE (index_exp)))
754 : {
755 45 : *index_p = index_exp;
756 45 : *index_n = 0;
757 45 : index_exp = TREE_OPERAND (index_exp, 0);
758 : }
759 109 : index_exp = get_index_from_offset (index_exp, index_p,
760 : index_n, pointee_size);
761 :
762 109 : if (!index_exp)
763 : return NULL_TREE;
764 : }
765 :
766 157 : while (CONVERT_EXPR_CODE_P (TREE_CODE (index_exp)))
767 : {
768 0 : *index_p = index_exp;
769 0 : *index_n = 0;
770 0 : index_exp = TREE_OPERAND (index_exp, 0);
771 : }
772 :
773 : return index_exp;
774 : }
775 :
776 : /* Return TRUE when the EXPR is a pointer array address that could be
777 : instrumented.
778 : We only instrument an address computation similar as the following:
779 : .ACCESS_WITH_SIZE (p->c, &p->b, 1, 0, -1, 0B)
780 : + (sizetype) ((long unsigned int) index * 4)
781 : if the EXPR is instrumentable, return TRUE and
782 : set the index to *INDEX.
783 : set the .ACCESS_WITH_SIZE to *BASE.
784 : set the parent tree of INDEX to *INDEX_P.
785 : set the operand position of the INDEX in the parent tree to INDEX_N. */
786 :
787 : static bool
788 157 : is_instrumentable_pointer_array_address (tree expr, tree *base,
789 : tree *index, tree *index_p,
790 : int *index_n)
791 : {
792 : /* For a pointer array address as:
793 : .ACCESS_WITH_SIZE (p->c, &p->b, 1, 0, -1, 0B)
794 : + (sizetype) ((long unsigned int) index * 4)
795 : op0 is the call to .ACCESS_WITH_SIZE;
796 : op1 is the index. */
797 157 : if (TREE_CODE (expr) != POINTER_PLUS_EXPR)
798 : return false;
799 :
800 157 : tree op0 = TREE_OPERAND (expr, 0);
801 157 : if (!is_access_with_size_p (op0))
802 : return false;
803 157 : tree op1 = get_index_from_pointer_addr_expr (expr, index_p, index_n);
804 157 : if (op1 != NULL_TREE)
805 : {
806 157 : *base = op0;
807 157 : *index = op1;
808 157 : return true;
809 : }
810 : return false;
811 : }
812 :
813 : /* Return true iff T is an array or an indirect reference that was
814 : instrumented by SANITIZE_BOUNDS. */
815 :
816 : bool
817 4478 : ubsan_array_ref_instrumented_p (tree t)
818 : {
819 4478 : if (TREE_CODE (t) != ARRAY_REF
820 157 : && TREE_CODE (t) != MEM_REF)
821 : return false;
822 :
823 4321 : bool is_array = (TREE_CODE (t) == ARRAY_REF);
824 4321 : tree op0 = NULL_TREE;
825 4321 : tree op1 = NULL_TREE;
826 4321 : tree index_p = NULL_TREE;
827 4321 : int index_n = 0;
828 4321 : if (is_array)
829 : {
830 4321 : op1 = TREE_OPERAND (t, 1);
831 4321 : return TREE_CODE (op1) == COMPOUND_EXPR
832 0 : && TREE_CODE (TREE_OPERAND (op1, 0)) == CALL_EXPR
833 0 : && CALL_EXPR_FN (TREE_OPERAND (op1, 0)) == NULL_TREE
834 4321 : && CALL_EXPR_IFN (TREE_OPERAND (op1, 0)) == IFN_UBSAN_BOUNDS;
835 : }
836 0 : else if (is_instrumentable_pointer_array_address (t, &op0, &op1,
837 : &index_p, &index_n))
838 0 : return TREE_CODE (op1) == COMPOUND_EXPR
839 0 : && TREE_CODE (TREE_OPERAND (op1, 0)) == CALL_EXPR
840 0 : && CALL_EXPR_FN (TREE_OPERAND (op1, 0)) == NULL_TREE
841 0 : && CALL_EXPR_IFN (TREE_OPERAND (op1, 0)) == IFN_UBSAN_BOUNDS;
842 :
843 : return false;
844 : }
845 :
846 : /* Instrument an ARRAY_REF or an address computation whose base address is
847 : a call to .ACCESS_WITH_SIZE, if it hasn't already been instrumented.
848 : IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside a ADDR_EXPR, or the
849 : address computation is not inside a INDIRECT_REF. */
850 :
851 : void
852 4478 : ubsan_maybe_instrument_array_ref (tree *expr_p, bool ignore_off_by_one)
853 : {
854 4478 : tree e = NULL_TREE;
855 4478 : tree op0 = NULL_TREE;
856 4478 : tree op1 = NULL_TREE;
857 4478 : tree index_p = NULL_TREE; /* the parent tree of INDEX. */
858 4478 : int index_n = 0; /* the operand position of INDEX in the parent tree. */
859 :
860 4478 : if (!ubsan_array_ref_instrumented_p (*expr_p)
861 4478 : && sanitize_flags_p (SANITIZE_BOUNDS | SANITIZE_BOUNDS_STRICT)
862 8946 : && current_function_decl != NULL_TREE)
863 : {
864 4468 : if (TREE_CODE (*expr_p) == ARRAY_REF)
865 : {
866 4311 : op0 = TREE_OPERAND (*expr_p, 0);
867 4311 : op1 = TREE_OPERAND (*expr_p, 1);
868 4311 : index_p = *expr_p;
869 4311 : index_n = 1;
870 4311 : e = ubsan_instrument_bounds (EXPR_LOCATION (*expr_p), op0,
871 : &op1, ignore_off_by_one);
872 : }
873 157 : else if (is_instrumentable_pointer_array_address (*expr_p, &op0, &op1,
874 : &index_p, &index_n))
875 157 : e = ubsan_instrument_bounds_pointer_address (EXPR_LOCATION (*expr_p),
876 : op0, &op1,
877 : ignore_off_by_one);
878 :
879 : /* Replace the original INDEX with the instrumented INDEX. */
880 4468 : if (e != NULL_TREE)
881 1721 : TREE_OPERAND (index_p, index_n)
882 3442 : = build2 (COMPOUND_EXPR, TREE_TYPE (op1), e, op1);
883 : }
884 4478 : }
885 :
886 : static tree
887 7169 : ubsan_maybe_instrument_reference_or_call (location_t loc, tree op, tree ptype,
888 : enum ubsan_null_ckind ckind)
889 : {
890 7169 : if (!sanitize_flags_p (SANITIZE_ALIGNMENT | SANITIZE_NULL)
891 7169 : || current_function_decl == NULL_TREE)
892 : return NULL_TREE;
893 :
894 7169 : tree type = TREE_TYPE (ptype);
895 7169 : tree orig_op = op;
896 7169 : bool instrument = false;
897 7169 : unsigned int mina = 0;
898 :
899 7169 : if (sanitize_flags_p (SANITIZE_ALIGNMENT))
900 : {
901 6938 : mina = min_align_of_type (type);
902 6938 : if (mina <= 1)
903 1121 : mina = 0;
904 : }
905 9607 : while ((TREE_CODE (op) == NOP_EXPR
906 9607 : || TREE_CODE (op) == NON_LVALUE_EXPR)
907 9607 : && TREE_CODE (TREE_TYPE (op)) == POINTER_TYPE)
908 2438 : op = TREE_OPERAND (op, 0);
909 7169 : if (TREE_CODE (op) == NOP_EXPR
910 7169 : && TREE_CODE (TREE_TYPE (op)) == REFERENCE_TYPE)
911 : {
912 0 : if (mina && mina > min_align_of_type (TREE_TYPE (TREE_TYPE (op))))
913 : instrument = true;
914 : }
915 : else
916 : {
917 7169 : if (sanitize_flags_p (SANITIZE_NULL) && TREE_CODE (op) == ADDR_EXPR)
918 : {
919 3955 : bool strict_overflow_p = false;
920 : /* tree_single_nonzero_warnv_p will not return true for non-weak
921 : non-automatic decls with -fno-delete-null-pointer-checks,
922 : which is disabled during -fsanitize=null. We don't want to
923 : instrument those, just weak vars though. */
924 3955 : int save_flag_delete_null_pointer_checks
925 : = flag_delete_null_pointer_checks;
926 3955 : flag_delete_null_pointer_checks = 1;
927 3955 : if (!tree_single_nonzero_warnv_p (op, &strict_overflow_p)
928 3955 : || strict_overflow_p)
929 : instrument = true;
930 3955 : flag_delete_null_pointer_checks
931 3955 : = save_flag_delete_null_pointer_checks;
932 : }
933 3214 : else if (sanitize_flags_p (SANITIZE_NULL))
934 : instrument = true;
935 7169 : if (mina && mina > 1)
936 : {
937 7084 : if (!POINTER_TYPE_P (TREE_TYPE (op))
938 7084 : || mina > get_pointer_alignment (op) / BITS_PER_UNIT)
939 : instrument = true;
940 : }
941 : }
942 3020 : if (!instrument)
943 2294 : return NULL_TREE;
944 4875 : op = save_expr (orig_op);
945 4875 : gcc_assert (POINTER_TYPE_P (ptype));
946 4875 : if (TREE_CODE (ptype) == REFERENCE_TYPE)
947 1756 : ptype = build_pointer_type (TREE_TYPE (ptype));
948 4875 : tree kind = build_int_cst (ptype, ckind);
949 4875 : tree align = build_int_cst (pointer_sized_int_node, mina);
950 4875 : tree call
951 4875 : = build_call_expr_internal_loc (loc, IFN_UBSAN_NULL, void_type_node,
952 : 3, op, kind, align);
953 4875 : TREE_SIDE_EFFECTS (call) = 1;
954 4875 : return fold_build2 (COMPOUND_EXPR, TREE_TYPE (op), call, op);
955 : }
956 :
957 : /* Instrument a NOP_EXPR to REFERENCE_TYPE or INTEGER_CST with REFERENCE_TYPE
958 : type if needed. */
959 :
960 : void
961 2345 : ubsan_maybe_instrument_reference (tree *stmt_p)
962 : {
963 2345 : tree stmt = *stmt_p;
964 2345 : tree op = stmt;
965 2345 : if (TREE_CODE (stmt) == NOP_EXPR)
966 2335 : op = TREE_OPERAND (stmt, 0);
967 2345 : op = ubsan_maybe_instrument_reference_or_call (EXPR_LOCATION (stmt), op,
968 2345 : TREE_TYPE (stmt),
969 : UBSAN_REF_BINDING);
970 2345 : if (op)
971 : {
972 1756 : if (TREE_CODE (stmt) == NOP_EXPR)
973 1746 : TREE_OPERAND (stmt, 0) = op;
974 : else
975 10 : *stmt_p = op;
976 : }
977 2345 : }
978 :
979 : /* Instrument a CALL_EXPR to a method if needed. */
980 :
981 : void
982 4824 : ubsan_maybe_instrument_member_call (tree stmt, bool is_ctor)
983 : {
984 4824 : if (call_expr_nargs (stmt) == 0)
985 : return;
986 4824 : tree op = CALL_EXPR_ARG (stmt, 0);
987 4824 : if (op == error_mark_node
988 4824 : || !POINTER_TYPE_P (TREE_TYPE (op)))
989 : return;
990 9648 : op = ubsan_maybe_instrument_reference_or_call (EXPR_LOCATION (stmt), op,
991 4824 : TREE_TYPE (op),
992 : is_ctor ? UBSAN_CTOR_CALL
993 : : UBSAN_MEMBER_CALL);
994 4824 : if (op)
995 3119 : CALL_EXPR_ARG (stmt, 0) = op;
996 : }
|