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