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