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