Branch data Line data Source code
1 : : /* UndefinedBehaviorSanitizer, undefined behavior detector.
2 : : Copyright (C) 2013-2025 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 : 1365 : ubsan_instrument_division (location_t loc, tree op0, tree op1)
41 : : {
42 : 1365 : tree t, tt, x = NULL_TREE;
43 : 1365 : tree type = TREE_TYPE (op0);
44 : 1365 : 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 : 1365 : tree top0 = TYPE_MAIN_VARIANT (type);
50 : 1365 : tree top1 = TYPE_MAIN_VARIANT (TREE_TYPE (op1));
51 : 1365 : gcc_checking_assert (lang_hooks.types_compatible_p (top0, top1));
52 : :
53 : 1365 : op0 = unshare_expr (op0);
54 : 1365 : op1 = unshare_expr (op1);
55 : :
56 : 1365 : if (INTEGRAL_TYPE_P (type)
57 : 1365 : && sanitize_flags_p (SANITIZE_DIVIDE))
58 : 889 : 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 : 1365 : if (INTEGRAL_TYPE_P (type)
72 : 1154 : && sanitize_flags_p (SANITIZE_SI_OVERFLOW)
73 : 2244 : && !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 : 470 : x = NULL_TREE;
96 : : }
97 : 606 : 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 : 1229 : 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 : 783 : t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op0), t);
108 : 783 : t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op1), t);
109 : 783 : 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 : 773 : tree data = ubsan_create_data ("__ubsan_overflow_data", 1, &loc,
114 : : ubsan_type_descriptor (type), NULL_TREE,
115 : : NULL_TREE);
116 : 773 : data = build_fold_addr_expr_loc (loc, data);
117 : 773 : 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 : 773 : = (flag_sanitize_recover & flag)
124 : 773 : ? BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW
125 : : : BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW_ABORT;
126 : 773 : tt = builtin_decl_explicit (bcode);
127 : 773 : op0 = unshare_expr (op0);
128 : 773 : op1 = unshare_expr (op1);
129 : 773 : tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0),
130 : : ubsan_encode_value (op1));
131 : : }
132 : 773 : 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 : 783 : t = fold_build3 (COND_EXPR, void_type_node, t, tt, x ? x : void_node);
156 : :
157 : 783 : return t;
158 : : }
159 : :
160 : : /* Instrument left and right shifts. */
161 : :
162 : : tree
163 : 2152 : ubsan_instrument_shift (location_t loc, enum tree_code code,
164 : : tree op0, tree op1)
165 : : {
166 : 2152 : tree t, tt = NULL_TREE;
167 : 2152 : tree type0 = TREE_TYPE (op0);
168 : 2152 : tree type1 = TREE_TYPE (op1);
169 : 2152 : if (!INTEGRAL_TYPE_P (type0))
170 : : return NULL_TREE;
171 : :
172 : 2138 : tree op1_utype = unsigned_type_for (type1);
173 : 2138 : HOST_WIDE_INT op0_prec = TYPE_PRECISION (type0);
174 : 2138 : tree uprecm1 = build_int_cst (op1_utype, op0_prec - 1);
175 : :
176 : 2138 : op0 = unshare_expr (op0);
177 : 2138 : op1 = unshare_expr (op1);
178 : :
179 : 2138 : 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 : 2110 : t = fold_convert_loc (loc, op1_utype, op1);
190 : 2110 : 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 : 2138 : if (TYPE_OVERFLOW_WRAPS (type0)
196 : 2764 : || maybe_ne (GET_MODE_BITSIZE (TYPE_MODE (type0)),
197 : 1382 : TYPE_PRECISION (type0))
198 : 1302 : || !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 : 1251 : || 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 : 1151 : 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 : 134 : else if (code == LSHIFT_EXPR && cxx_dialect >= cxx11)
221 : : {
222 : 74 : tree x = fold_build2 (MINUS_EXPR, op1_utype, uprecm1,
223 : : fold_convert (op1_utype, unshare_expr (op1)));
224 : 74 : tt = fold_convert_loc (loc, unsigned_type_for (type0),
225 : : unshare_expr (op0));
226 : 74 : tt = fold_build2 (RSHIFT_EXPR, TREE_TYPE (tt), tt, x);
227 : 74 : tt = fold_build2 (GT_EXPR, boolean_type_node, tt,
228 : : build_int_cst (TREE_TYPE (tt), 1));
229 : 74 : x = fold_build2 (LT_EXPR, boolean_type_node, unshare_expr (op0),
230 : : build_int_cst (type0, 0));
231 : 74 : 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 : 2138 : if (integer_zerop (t) && (tt == NULL_TREE || integer_zerop (tt)))
237 : 1107 : 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 : 1031 : t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op0), t);
242 : 1031 : t = fold_build2 (COMPOUND_EXPR, TREE_TYPE (t), unshare_expr (op1), t);
243 : :
244 : 1031 : enum sanitize_code recover_kind = SANITIZE_SHIFT_EXPONENT;
245 : 1031 : tree else_t = void_node;
246 : 1031 : if (tt)
247 : : {
248 : 530 : 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 : 502 : if (((!(flag_sanitize_trap & SANITIZE_SHIFT_EXPONENT))
257 : 502 : == (!(flag_sanitize_trap & SANITIZE_SHIFT_BASE)))
258 : 502 : && ((!(flag_sanitize_recover & SANITIZE_SHIFT_EXPONENT))
259 : 502 : == (!(flag_sanitize_recover & SANITIZE_SHIFT_BASE))))
260 : 435 : t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, tt);
261 : : else
262 : : else_t = tt;
263 : : }
264 : : }
265 : :
266 : 1031 : 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 : 1031 : if (TREE_CODE (type1) == BITINT_TYPE
271 : 1063 : && 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 : 1031 : tree utd0 = ubsan_type_descriptor (type0, UBSAN_PRINT_FORCE_INT);
297 : 1031 : tree data = ubsan_create_data ("__ubsan_shift_data", 1, &loc, utd0,
298 : : ubsan_type_descriptor (type1), NULL_TREE,
299 : : NULL_TREE);
300 : 1031 : data = build_fold_addr_expr_loc (loc, data);
301 : :
302 : 1031 : 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 : 1031 : = (flag_sanitize_recover & recover_kind)
308 : 1031 : ? BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS
309 : : : BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS_ABORT;
310 : 1031 : tt = builtin_decl_explicit (bcode);
311 : 1031 : op0 = unshare_expr (op0);
312 : 1031 : op1 = unshare_expr (op1);
313 : 1031 : tt = build_call_expr_loc (loc, tt, 3, data, ubsan_encode_value (op0),
314 : : ubsan_encode_value (op1));
315 : : }
316 : 1031 : 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 : 1031 : t = fold_build3 (COND_EXPR, void_type_node, t, tt, else_t);
341 : :
342 : 1031 : return t;
343 : : }
344 : :
345 : : /* Instrument variable length array bound. */
346 : :
347 : : tree
348 : 221 : ubsan_instrument_vla (location_t loc, tree size)
349 : : {
350 : 221 : tree type = TREE_TYPE (size);
351 : 221 : tree t, tt;
352 : :
353 : 221 : t = fold_build2 (LE_EXPR, boolean_type_node, size, build_int_cst (type, 0));
354 : 221 : 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 : 221 : tree data = ubsan_create_data ("__ubsan_vla_data", 1, &loc,
359 : : ubsan_type_descriptor (type), NULL_TREE,
360 : : NULL_TREE);
361 : 221 : data = build_fold_addr_expr_loc (loc, data);
362 : 12 : enum built_in_function bcode
363 : 221 : = (flag_sanitize_recover & SANITIZE_VLA)
364 : 221 : ? BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE
365 : : : BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE_ABORT;
366 : 221 : tt = builtin_decl_explicit (bcode);
367 : 221 : tt = build_call_expr_loc (loc, tt, 2, data, ubsan_encode_value (size));
368 : : }
369 : 221 : t = fold_build3 (COND_EXPR, void_type_node, t, tt, void_node);
370 : :
371 : 221 : return t;
372 : : }
373 : :
374 : : /* Instrument missing return in C++ functions returning non-void. */
375 : :
376 : : tree
377 : 1396 : ubsan_instrument_return (location_t loc)
378 : : {
379 : 1396 : 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 : 1393 : tree data = ubsan_create_data ("__ubsan_missing_return_data", 1, &loc,
385 : : NULL_TREE, NULL_TREE);
386 : 1393 : tree t = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_MISSING_RETURN);
387 : 1393 : 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 : 82 : get_bound_from_access_with_size (tree call)
395 : : {
396 : 82 : if (!is_access_with_size_p (call))
397 : : return NULL_TREE;
398 : :
399 : 82 : tree ref_to_size = CALL_EXPR_ARG (call, 1);
400 : 82 : tree type = TREE_TYPE (TREE_TYPE (CALL_EXPR_ARG (call, 2)));
401 : 82 : 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 : 82 : if (!TYPE_UNSIGNED (type))
405 : : {
406 : 82 : tree cond = fold_build2 (LT_EXPR, boolean_type_node,
407 : : unshare_expr (size), build_zero_cst (type));
408 : 82 : size = fold_build3 (COND_EXPR, type, cond,
409 : : build_zero_cst (type), size);
410 : : }
411 : :
412 : 82 : size = fold_convert (sizetype, size);
413 : :
414 : 82 : 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 : 4266 : ubsan_instrument_bounds (location_t loc, tree array, tree *index,
426 : : bool ignore_off_by_one)
427 : : {
428 : 4266 : tree type = TREE_TYPE (array);
429 : 4266 : tree domain = TYPE_DOMAIN (type);
430 : :
431 : 4266 : if (domain == NULL_TREE)
432 : : return NULL_TREE;
433 : :
434 : 4254 : tree bound = TYPE_MAX_VALUE (domain);
435 : 4254 : 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 : 228 : if (!c_dialect_cxx ()
440 : 228 : && COMPLETE_TYPE_P (type)
441 : 347 : && integer_zerop (TYPE_SIZE (type)))
442 : 119 : bound = build_int_cst (TREE_TYPE (TYPE_MIN_VALUE (domain)), -1);
443 : 109 : else if (INDIRECT_REF_P (array)
444 : 109 : && is_access_with_size_p ((TREE_OPERAND (array, 0))))
445 : : {
446 : 37 : bound = get_bound_from_access_with_size ((TREE_OPERAND (array, 0)));
447 : 37 : 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 : 4182 : 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 : 4182 : tree base = get_base_address (array);
462 : 4182 : if (!sanitize_flags_p (SANITIZE_BOUNDS_STRICT)
463 : 4150 : && TREE_CODE (array) == COMPONENT_REF
464 : 5102 : && 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 : 834 : while (TREE_CODE (cref) == COMPONENT_REF)
471 : : {
472 : 610 : if (TREE_CODE (TREE_TYPE (TREE_OPERAND (cref, 0))) == RECORD_TYPE)
473 : 603 : for (next = DECL_CHAIN (TREE_OPERAND (cref, 1));
474 : 2827 : next && TREE_CODE (next) != FIELD_DECL;
475 : 2224 : next = DECL_CHAIN (next))
476 : : ;
477 : 610 : if (next)
478 : : /* Not a last element. Instrument it. */
479 : : break;
480 : 369 : if (TREE_CODE (TREE_TYPE (TREE_OPERAND (cref, 1))) == ARRAY_TYPE
481 : 369 : && !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 : 297 : cref = TREE_OPERAND (cref, 0);
523 : : }
524 : 537 : 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 : 3958 : tree idx = NULL_TREE;
532 : 3958 : if (TREE_CODE (*index) == INTEGER_CST)
533 : : idx = *index;
534 : 749 : else if (TREE_CODE (*index) == BIT_AND_EXPR
535 : 749 : && TREE_CODE (TREE_OPERAND (*index, 1)) == INTEGER_CST)
536 : 26 : idx = TREE_OPERAND (*index, 1);
537 : 3235 : if (idx
538 : 3235 : && TREE_CODE (bound) == INTEGER_CST
539 : 2948 : && tree_int_cst_sgn (idx) >= 0
540 : 6161 : && tree_int_cst_lt (idx, bound))
541 : : return NULL_TREE;
542 : :
543 : 1513 : *index = save_expr (*index);
544 : : /* Create a "(T *) 0" tree node to describe the array type. */
545 : 1513 : tree zero_with_type = build_int_cst (build_pointer_type (type), 0);
546 : 1513 : return build_call_expr_internal_loc (loc, IFN_UBSAN_BOUNDS,
547 : : void_type_node, 3, zero_with_type,
548 : 1513 : *index, bound);
549 : : }
550 : :
551 : :
552 : : /* Instrument array bounds for the pointer array address which is
553 : : a call to .ACCESS_WITH_SIZE. We create special
554 : : builtin, that gets expanded in the sanopt pass, and make an array
555 : : dimention of it. POINTER_ADDR is the pointer array's base address.
556 : : *INDEX is an index to the array.
557 : : IGNORE_OFF_BY_ONE is true if the POINTER_ADDR is not inside an
558 : : INDIRECT_REF.
559 : : Return NULL_TREE if no instrumentation is emitted. */
560 : :
561 : : tree
562 : 45 : ubsan_instrument_bounds_pointer_address (location_t loc, tree pointer_addr,
563 : : tree *index,
564 : : bool ignore_off_by_one)
565 : : {
566 : 45 : tree call = pointer_addr;
567 : 45 : if (!is_access_with_size_p (call))
568 : : return NULL_TREE;
569 : 45 : tree bound = get_bound_from_access_with_size (call);
570 : :
571 : 45 : if (ignore_off_by_one)
572 : 0 : bound = fold_build2 (PLUS_EXPR, TREE_TYPE (bound), bound,
573 : : build_int_cst (TREE_TYPE (bound),
574 : : 1));
575 : :
576 : : /* Don't emit instrumentation in the most common cases. */
577 : 45 : tree idx = NULL_TREE;
578 : 45 : if (TREE_CODE (*index) == INTEGER_CST)
579 : : idx = *index;
580 : 45 : else if (TREE_CODE (*index) == BIT_AND_EXPR
581 : 45 : && TREE_CODE (TREE_OPERAND (*index, 1)) == INTEGER_CST)
582 : 0 : idx = TREE_OPERAND (*index, 1);
583 : 0 : if (idx
584 : 0 : && TREE_CODE (bound) == INTEGER_CST
585 : 0 : && tree_int_cst_sgn (idx) >= 0
586 : 0 : && tree_int_cst_lt (idx, bound))
587 : : return NULL_TREE;
588 : :
589 : 45 : *index = save_expr (*index);
590 : :
591 : : /* Create an array_type for the corresponding pointer array. */
592 : 45 : tree itype = build_range_type (sizetype, size_zero_node, NULL_TREE);
593 : : /* The array's element type can be get from the return type of the call to
594 : : .ACCESS_WITH_SIZE. */
595 : 45 : tree element_type = TREE_TYPE (TREE_TYPE (call));
596 : 45 : tree array_type = build_array_type (element_type, itype);
597 : : /* Create a "(T *) 0" tree node to describe the array type. */
598 : 45 : tree zero_with_type = build_int_cst (build_pointer_type (array_type), 0);
599 : 45 : return build_call_expr_internal_loc (loc, IFN_UBSAN_BOUNDS,
600 : : void_type_node, 3, zero_with_type,
601 : 45 : *index, bound);
602 : : }
603 : :
604 : : /* This structure is to combine a factor with its parent and its position
605 : : * in its parent tree. */
606 : : struct factor_t
607 : : {
608 : : tree factor;
609 : : tree parent; /* the parent tree of this factor. */
610 : : int pos; /* the position of this factor in its parent tree. */
611 : : };
612 : :
613 : : /* for a multiply expression like:
614 : : ((long unsigned int) m * (long unsigned int) SAVE_EXPR <n>) * 4
615 : :
616 : : locate all the factors, the parents of the factor and the position of
617 : : the factor in its parent, and put them to VEC_FACTORS. */
618 : :
619 : : static void
620 : 183 : get_factors_from_mul_expr (tree mult_expr, tree parent,
621 : : int pos, auto_vec<factor_t> *vec_factors)
622 : : {
623 : 276 : struct factor_t mult_factor = {0, 0, -1};
624 : 276 : mult_factor.factor = mult_expr;
625 : 276 : mult_factor.parent = parent;
626 : 276 : mult_factor.pos = pos;
627 : :
628 : 377 : while (CONVERT_EXPR_CODE_P (TREE_CODE (mult_expr)))
629 : : {
630 : 101 : mult_factor.parent = mult_expr;
631 : 101 : mult_factor.pos = 0;
632 : 101 : mult_expr = TREE_OPERAND (mult_expr, 0);
633 : 101 : mult_factor.factor = mult_expr;
634 : : }
635 : 276 : if (TREE_CODE (mult_expr) != MULT_EXPR)
636 : 183 : vec_factors->safe_push (mult_factor);
637 : : else
638 : : {
639 : 93 : get_factors_from_mul_expr (TREE_OPERAND (mult_expr, 0), mult_expr,
640 : : 0, vec_factors);
641 : 93 : get_factors_from_mul_expr (TREE_OPERAND (mult_expr, 1), mult_expr,
642 : : 1, vec_factors);
643 : : }
644 : 183 : }
645 : :
646 : : /* Given an OFFSET expression, and the ELEMENT_SIZE,
647 : : get the index expression from OFFSET and return it.
648 : : For example:
649 : : OFFSET:
650 : : ((long unsigned int) m * (long unsigned int) SAVE_EXPR <n>) * 4
651 : : ELEMENT_SIZE:
652 : : (sizetype) SAVE_EXPR <n> * 4
653 : : get the index as (long unsigned int) m, and return it.
654 : : The INDEX_P holds the pointer to the parent tree of the index,
655 : : INDEX_N holds the position of the index in its parent. */
656 : :
657 : : static tree
658 : 45 : get_index_from_offset (tree offset, tree *index_p,
659 : : int *index_n, tree element_size)
660 : : {
661 : 45 : if (TREE_CODE (offset) != MULT_EXPR)
662 : : return NULL_TREE;
663 : :
664 : 45 : auto_vec<factor_t> e_factors, o_factors;
665 : 45 : get_factors_from_mul_expr (element_size, NULL, -1, &e_factors);
666 : 45 : get_factors_from_mul_expr (offset, *index_p, *index_n, &o_factors);
667 : :
668 : 90 : if (e_factors.is_empty () || o_factors.is_empty ())
669 : : return NULL_TREE;
670 : :
671 : : bool all_found = true;
672 : 114 : for (unsigned i = 0; i < e_factors.length (); i++)
673 : : {
674 : 69 : factor_t e_size_factor = e_factors[i];
675 : 69 : bool found = false;
676 : 215 : for (unsigned j = 0; j < o_factors.length ();)
677 : : {
678 : 146 : factor_t o_exp_factor = o_factors[j];
679 : 146 : if (operand_equal_p (e_size_factor.factor, o_exp_factor.factor))
680 : : {
681 : 69 : o_factors.unordered_remove (j);
682 : 69 : found = true;
683 : 69 : break;
684 : : }
685 : : else
686 : 77 : j++;
687 : : }
688 : 69 : if (!found)
689 : : all_found = false;
690 : : }
691 : :
692 : 45 : if (!all_found)
693 : : return NULL_TREE;
694 : :
695 : 45 : if (o_factors.length () != 1)
696 : : return NULL_TREE;
697 : :
698 : 45 : *index_p = o_factors[0].parent;
699 : 45 : *index_n = o_factors[0].pos;
700 : 45 : return o_factors[0].factor;
701 : 45 : }
702 : :
703 : : /* For an pointer + offset computation expression, such as,
704 : : .ACCESS_WITH_SIZE (p->c, &p->b, 1, 0, -1, 0B)
705 : : + (sizetype) ((long unsigned int) index * 4
706 : : Return the index of this pointer array reference,
707 : : set the parent tree of INDEX to *INDEX_P.
708 : : set the operand position of the INDEX in the parent tree to *INDEX_N.
709 : : If failed, return NULL_TREE. */
710 : :
711 : : static tree
712 : 45 : get_index_from_pointer_addr_expr (tree pointer, tree *index_p, int *index_n)
713 : : {
714 : 45 : *index_p = NULL_TREE;
715 : 45 : *index_n = -1;
716 : 45 : tree call = TREE_OPERAND (pointer, 0);
717 : 45 : if (!is_access_with_size_p (call))
718 : : return NULL_TREE;
719 : :
720 : : /* Get the pointee type of the call to .ACCESS_WITH_SIZE.
721 : : This should be the element type of the pointer array. */
722 : 45 : tree pointee_type = TREE_TYPE (TREE_TYPE (call));
723 : 45 : tree pointee_size = TYPE_SIZE_UNIT (pointee_type);
724 : :
725 : 45 : tree index_exp = TREE_OPERAND (pointer, 1);
726 : 45 : *index_p = pointer;
727 : 45 : *index_n = 1;
728 : :
729 : 90 : if (!(TREE_CODE (index_exp) != MULT_EXPR
730 : 45 : && tree_int_cst_equal (pointee_size, integer_one_node)))
731 : : {
732 : 90 : while (CONVERT_EXPR_CODE_P (TREE_CODE (index_exp)))
733 : : {
734 : 45 : *index_p = index_exp;
735 : 45 : *index_n = 0;
736 : 45 : index_exp = TREE_OPERAND (index_exp, 0);
737 : : }
738 : 45 : index_exp = get_index_from_offset (index_exp, index_p,
739 : : index_n, pointee_size);
740 : :
741 : 45 : if (!index_exp)
742 : : return NULL_TREE;
743 : : }
744 : :
745 : 45 : while (CONVERT_EXPR_CODE_P (TREE_CODE (index_exp)))
746 : : {
747 : 0 : *index_p = index_exp;
748 : 0 : *index_n = 0;
749 : 0 : index_exp = TREE_OPERAND (index_exp, 0);
750 : : }
751 : :
752 : : return index_exp;
753 : : }
754 : :
755 : : /* Return TRUE when the EXPR is a pointer array address that could be
756 : : instrumented.
757 : : We only instrument an address computation similar as the following:
758 : : .ACCESS_WITH_SIZE (p->c, &p->b, 1, 0, -1, 0B)
759 : : + (sizetype) ((long unsigned int) index * 4)
760 : : if the EXPR is instrumentable, return TRUE and
761 : : set the index to *INDEX.
762 : : set the .ACCESS_WITH_SIZE to *BASE.
763 : : set the parent tree of INDEX to *INDEX_P.
764 : : set the operand position of the INDEX in the parent tree to INDEX_N. */
765 : :
766 : : static bool
767 : 45 : is_instrumentable_pointer_array_address (tree expr, tree *base,
768 : : tree *index, tree *index_p,
769 : : int *index_n)
770 : : {
771 : : /* For a pointer array address as:
772 : : .ACCESS_WITH_SIZE (p->c, &p->b, 1, 0, -1, 0B)
773 : : + (sizetype) ((long unsigned int) index * 4)
774 : : op0 is the call to .ACCESS_WITH_SIZE;
775 : : op1 is the index. */
776 : 45 : if (TREE_CODE (expr) != POINTER_PLUS_EXPR)
777 : : return false;
778 : :
779 : 45 : tree op0 = TREE_OPERAND (expr, 0);
780 : 45 : if (!is_access_with_size_p (op0))
781 : : return false;
782 : 45 : tree op1 = get_index_from_pointer_addr_expr (expr, index_p, index_n);
783 : 45 : if (op1 != NULL_TREE)
784 : : {
785 : 45 : *base = op0;
786 : 45 : *index = op1;
787 : 45 : return true;
788 : : }
789 : : return false;
790 : : }
791 : :
792 : : /* Return true iff T is an array or an indirect reference that was
793 : : instrumented by SANITIZE_BOUNDS. */
794 : :
795 : : bool
796 : 4318 : ubsan_array_ref_instrumented_p (tree t)
797 : : {
798 : 4318 : if (TREE_CODE (t) != ARRAY_REF
799 : 45 : && TREE_CODE (t) != MEM_REF)
800 : : return false;
801 : :
802 : 4273 : bool is_array = (TREE_CODE (t) == ARRAY_REF);
803 : 4273 : tree op0 = NULL_TREE;
804 : 4273 : tree op1 = NULL_TREE;
805 : 4273 : tree index_p = NULL_TREE;
806 : 4273 : int index_n = 0;
807 : 4273 : if (is_array)
808 : : {
809 : 4273 : op1 = TREE_OPERAND (t, 1);
810 : 4273 : return TREE_CODE (op1) == COMPOUND_EXPR
811 : 0 : && TREE_CODE (TREE_OPERAND (op1, 0)) == CALL_EXPR
812 : 0 : && CALL_EXPR_FN (TREE_OPERAND (op1, 0)) == NULL_TREE
813 : 4273 : && CALL_EXPR_IFN (TREE_OPERAND (op1, 0)) == IFN_UBSAN_BOUNDS;
814 : : }
815 : 0 : else if (is_instrumentable_pointer_array_address (t, &op0, &op1,
816 : : &index_p, &index_n))
817 : 0 : return TREE_CODE (op1) == COMPOUND_EXPR
818 : 0 : && TREE_CODE (TREE_OPERAND (op1, 0)) == CALL_EXPR
819 : 0 : && CALL_EXPR_FN (TREE_OPERAND (op1, 0)) == NULL_TREE
820 : 0 : && CALL_EXPR_IFN (TREE_OPERAND (op1, 0)) == IFN_UBSAN_BOUNDS;
821 : :
822 : : return false;
823 : : }
824 : :
825 : : /* Instrument an ARRAY_REF or an address computation whose base address is
826 : : a call to .ACCESS_WITH_SIZE, if it hasn't already been instrumented.
827 : : IGNORE_OFF_BY_ONE is true if the ARRAY_REF is inside a ADDR_EXPR, or the
828 : : address computation is not inside a INDIRECT_REF. */
829 : :
830 : : void
831 : 4318 : ubsan_maybe_instrument_array_ref (tree *expr_p, bool ignore_off_by_one)
832 : : {
833 : 4318 : tree e = NULL_TREE;
834 : 4318 : tree op0 = NULL_TREE;
835 : 4318 : tree op1 = NULL_TREE;
836 : 4318 : tree index_p = NULL_TREE; /* the parent tree of INDEX. */
837 : 4318 : int index_n = 0; /* the operand position of INDEX in the parent tree. */
838 : :
839 : 4318 : if (!ubsan_array_ref_instrumented_p (*expr_p)
840 : 4318 : && sanitize_flags_p (SANITIZE_BOUNDS | SANITIZE_BOUNDS_STRICT)
841 : 8626 : && current_function_decl != NULL_TREE)
842 : : {
843 : 4308 : if (TREE_CODE (*expr_p) == ARRAY_REF)
844 : : {
845 : 4263 : op0 = TREE_OPERAND (*expr_p, 0);
846 : 4263 : op1 = TREE_OPERAND (*expr_p, 1);
847 : 4263 : index_p = *expr_p;
848 : 4263 : index_n = 1;
849 : 4263 : e = ubsan_instrument_bounds (EXPR_LOCATION (*expr_p), op0,
850 : : &op1, ignore_off_by_one);
851 : : }
852 : 45 : else if (is_instrumentable_pointer_array_address (*expr_p, &op0, &op1,
853 : : &index_p, &index_n))
854 : 45 : e = ubsan_instrument_bounds_pointer_address (EXPR_LOCATION (*expr_p),
855 : : op0, &op1,
856 : : ignore_off_by_one);
857 : :
858 : : /* Replace the original INDEX with the instrumented INDEX. */
859 : 4308 : if (e != NULL_TREE)
860 : 1555 : TREE_OPERAND (index_p, index_n)
861 : 3110 : = build2 (COMPOUND_EXPR, TREE_TYPE (op1), e, op1);
862 : : }
863 : 4318 : }
864 : :
865 : : static tree
866 : 6823 : ubsan_maybe_instrument_reference_or_call (location_t loc, tree op, tree ptype,
867 : : enum ubsan_null_ckind ckind)
868 : : {
869 : 6823 : if (!sanitize_flags_p (SANITIZE_ALIGNMENT | SANITIZE_NULL)
870 : 6823 : || current_function_decl == NULL_TREE)
871 : : return NULL_TREE;
872 : :
873 : 6823 : tree type = TREE_TYPE (ptype);
874 : 6823 : tree orig_op = op;
875 : 6823 : bool instrument = false;
876 : 6823 : unsigned int mina = 0;
877 : :
878 : 6823 : if (sanitize_flags_p (SANITIZE_ALIGNMENT))
879 : : {
880 : 6593 : mina = min_align_of_type (type);
881 : 6593 : if (mina <= 1)
882 : 1073 : mina = 0;
883 : : }
884 : 9188 : while ((TREE_CODE (op) == NOP_EXPR
885 : 9188 : || TREE_CODE (op) == NON_LVALUE_EXPR)
886 : 9188 : && TREE_CODE (TREE_TYPE (op)) == POINTER_TYPE)
887 : 2365 : op = TREE_OPERAND (op, 0);
888 : 6823 : if (TREE_CODE (op) == NOP_EXPR
889 : 6823 : && TREE_CODE (TREE_TYPE (op)) == REFERENCE_TYPE)
890 : : {
891 : 0 : if (mina && mina > min_align_of_type (TREE_TYPE (TREE_TYPE (op))))
892 : : instrument = true;
893 : : }
894 : : else
895 : : {
896 : 6823 : if (sanitize_flags_p (SANITIZE_NULL) && TREE_CODE (op) == ADDR_EXPR)
897 : : {
898 : 3753 : bool strict_overflow_p = false;
899 : : /* tree_single_nonzero_warnv_p will not return true for non-weak
900 : : non-automatic decls with -fno-delete-null-pointer-checks,
901 : : which is disabled during -fsanitize=null. We don't want to
902 : : instrument those, just weak vars though. */
903 : 3753 : int save_flag_delete_null_pointer_checks
904 : : = flag_delete_null_pointer_checks;
905 : 3753 : flag_delete_null_pointer_checks = 1;
906 : 3753 : if (!tree_single_nonzero_warnv_p (op, &strict_overflow_p)
907 : 3753 : || strict_overflow_p)
908 : : instrument = true;
909 : 3753 : flag_delete_null_pointer_checks
910 : 3753 : = save_flag_delete_null_pointer_checks;
911 : : }
912 : 3070 : else if (sanitize_flags_p (SANITIZE_NULL))
913 : : instrument = true;
914 : 6823 : if (mina && mina > 1)
915 : : {
916 : 6791 : if (!POINTER_TYPE_P (TREE_TYPE (op))
917 : 6791 : || mina > get_pointer_alignment (op) / BITS_PER_UNIT)
918 : : instrument = true;
919 : : }
920 : : }
921 : 2929 : if (!instrument)
922 : 2246 : return NULL_TREE;
923 : 4577 : op = save_expr (orig_op);
924 : 4577 : gcc_assert (POINTER_TYPE_P (ptype));
925 : 4577 : if (TREE_CODE (ptype) == REFERENCE_TYPE)
926 : 1605 : ptype = build_pointer_type (TREE_TYPE (ptype));
927 : 4577 : tree kind = build_int_cst (ptype, ckind);
928 : 4577 : tree align = build_int_cst (pointer_sized_int_node, mina);
929 : 4577 : tree call
930 : 4577 : = build_call_expr_internal_loc (loc, IFN_UBSAN_NULL, void_type_node,
931 : : 3, op, kind, align);
932 : 4577 : TREE_SIDE_EFFECTS (call) = 1;
933 : 4577 : return fold_build2 (COMPOUND_EXPR, TREE_TYPE (op), call, op);
934 : : }
935 : :
936 : : /* Instrument a NOP_EXPR to REFERENCE_TYPE or INTEGER_CST with REFERENCE_TYPE
937 : : type if needed. */
938 : :
939 : : void
940 : 2186 : ubsan_maybe_instrument_reference (tree *stmt_p)
941 : : {
942 : 2186 : tree stmt = *stmt_p;
943 : 2186 : tree op = stmt;
944 : 2186 : if (TREE_CODE (stmt) == NOP_EXPR)
945 : 2176 : op = TREE_OPERAND (stmt, 0);
946 : 2186 : op = ubsan_maybe_instrument_reference_or_call (EXPR_LOCATION (stmt), op,
947 : 2186 : TREE_TYPE (stmt),
948 : : UBSAN_REF_BINDING);
949 : 2186 : if (op)
950 : : {
951 : 1605 : if (TREE_CODE (stmt) == NOP_EXPR)
952 : 1595 : TREE_OPERAND (stmt, 0) = op;
953 : : else
954 : 10 : *stmt_p = op;
955 : : }
956 : 2186 : }
957 : :
958 : : /* Instrument a CALL_EXPR to a method if needed. */
959 : :
960 : : void
961 : 4637 : ubsan_maybe_instrument_member_call (tree stmt, bool is_ctor)
962 : : {
963 : 4637 : if (call_expr_nargs (stmt) == 0)
964 : : return;
965 : 4637 : tree op = CALL_EXPR_ARG (stmt, 0);
966 : 4637 : if (op == error_mark_node
967 : 4637 : || !POINTER_TYPE_P (TREE_TYPE (op)))
968 : : return;
969 : 9274 : op = ubsan_maybe_instrument_reference_or_call (EXPR_LOCATION (stmt), op,
970 : 4637 : TREE_TYPE (op),
971 : : is_ctor ? UBSAN_CTOR_CALL
972 : : : UBSAN_MEMBER_CALL);
973 : 4637 : if (op)
974 : 2972 : CALL_EXPR_ARG (stmt, 0) = op;
975 : : }
|