1 /* UndefinedBehaviorSanitizer, undefined behavior detector.
2 Copyright (C) 2013-2014 Free Software Foundation, Inc.
3 Contributed by Marek Polacek <polacek@redhat.com>
5 This file is part of GCC.
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
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
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/>. */
23 #include "coretypes.h"
25 #include "alloc-pool.h"
30 #include "c-family/c-common.h"
31 #include "c-family/c-ubsan.h"
33 /* Instrument division by zero and INT_MIN / -1. If not instrumenting,
37 ubsan_instrument_division (location_t loc
, tree op0
, tree op1
)
40 tree type
= TREE_TYPE (op0
);
42 /* At this point both operands should have the same type,
43 because they are already converted to RESULT_TYPE.
44 Use TYPE_MAIN_VARIANT since typedefs can confuse us. */
45 gcc_assert (TYPE_MAIN_VARIANT (TREE_TYPE (op0
))
46 == TYPE_MAIN_VARIANT (TREE_TYPE (op1
)));
48 /* TODO: REAL_TYPE is not supported yet. */
49 if (TREE_CODE (type
) != INTEGER_TYPE
)
52 t
= fold_build2 (EQ_EXPR
, boolean_type_node
,
53 op1
, build_int_cst (type
, 0));
55 /* We check INT_MIN / -1 only for signed types. */
56 if (!TYPE_UNSIGNED (type
))
59 tt
= fold_build2 (EQ_EXPR
, boolean_type_node
, op1
,
60 build_int_cst (type
, -1));
61 x
= fold_build2 (EQ_EXPR
, boolean_type_node
, op0
,
62 TYPE_MIN_VALUE (type
));
63 x
= fold_build2 (TRUTH_AND_EXPR
, boolean_type_node
, x
, tt
);
64 t
= fold_build2 (TRUTH_OR_EXPR
, boolean_type_node
, t
, x
);
67 /* If the condition was folded to 0, no need to instrument
69 if (integer_zerop (t
))
72 /* In case we have a SAVE_EXPR in a conditional context, we need to
73 make sure it gets evaluated before the condition. */
74 t
= fold_build2 (COMPOUND_EXPR
, TREE_TYPE (t
), op0
, t
);
75 tree data
= ubsan_create_data ("__ubsan_overflow_data",
77 ubsan_type_descriptor (type
, false),
79 data
= build_fold_addr_expr_loc (loc
, data
);
80 tt
= builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_DIVREM_OVERFLOW
);
81 tt
= build_call_expr_loc (loc
, tt
, 3, data
, ubsan_encode_value (op0
),
82 ubsan_encode_value (op1
));
83 t
= fold_build3 (COND_EXPR
, void_type_node
, t
, tt
, void_zero_node
);
88 /* Instrument left and right shifts. */
91 ubsan_instrument_shift (location_t loc
, enum tree_code code
,
94 tree t
, tt
= NULL_TREE
;
95 tree type0
= TREE_TYPE (op0
);
96 tree type1
= TREE_TYPE (op1
);
97 tree op1_utype
= unsigned_type_for (type1
);
98 HOST_WIDE_INT op0_prec
= TYPE_PRECISION (type0
);
99 tree uprecm1
= build_int_cst (op1_utype
, op0_prec
- 1);
100 tree precm1
= build_int_cst (type1
, op0_prec
- 1);
102 t
= fold_convert_loc (loc
, op1_utype
, op1
);
103 t
= fold_build2 (GT_EXPR
, boolean_type_node
, t
, uprecm1
);
105 /* For signed x << y, in C99/C11, the following:
106 (unsigned) x >> (precm1 - y)
107 if non-zero, is undefined. */
108 if (code
== LSHIFT_EXPR
109 && !TYPE_UNSIGNED (type0
)
112 tree x
= fold_build2 (MINUS_EXPR
, integer_type_node
, precm1
, op1
);
113 tt
= fold_convert_loc (loc
, unsigned_type_for (type0
), op0
);
114 tt
= fold_build2 (RSHIFT_EXPR
, TREE_TYPE (tt
), tt
, x
);
115 tt
= fold_build2 (NE_EXPR
, boolean_type_node
, tt
,
116 build_int_cst (TREE_TYPE (tt
), 0));
119 /* For signed x << y, in C++11/C++14, the following:
120 x < 0 || ((unsigned) x >> (precm1 - y))
121 if > 1, is undefined. */
122 if (code
== LSHIFT_EXPR
123 && !TYPE_UNSIGNED (TREE_TYPE (op0
))
124 && (cxx_dialect
== cxx11
|| cxx_dialect
== cxx1y
))
126 tree x
= fold_build2 (MINUS_EXPR
, integer_type_node
, precm1
, op1
);
127 tt
= fold_convert_loc (loc
, unsigned_type_for (type0
), op0
);
128 tt
= fold_build2 (RSHIFT_EXPR
, TREE_TYPE (tt
), tt
, x
);
129 tt
= fold_build2 (GT_EXPR
, boolean_type_node
, tt
,
130 build_int_cst (TREE_TYPE (tt
), 1));
131 x
= fold_build2 (LT_EXPR
, boolean_type_node
, op0
,
132 build_int_cst (type0
, 0));
133 tt
= fold_build2 (TRUTH_OR_EXPR
, boolean_type_node
, x
, tt
);
136 /* If the condition was folded to 0, no need to instrument
138 if (integer_zerop (t
) && (tt
== NULL_TREE
|| integer_zerop (tt
)))
141 /* In case we have a SAVE_EXPR in a conditional context, we need to
142 make sure it gets evaluated before the condition. */
143 t
= fold_build2 (COMPOUND_EXPR
, TREE_TYPE (t
), op0
, t
);
144 tree data
= ubsan_create_data ("__ubsan_shift_data",
146 ubsan_type_descriptor (type0
, false),
147 ubsan_type_descriptor (type1
, false),
150 data
= build_fold_addr_expr_loc (loc
, data
);
152 t
= fold_build2 (TRUTH_OR_EXPR
, boolean_type_node
, t
,
153 tt
? tt
: integer_zero_node
);
154 tt
= builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_SHIFT_OUT_OF_BOUNDS
);
155 tt
= build_call_expr_loc (loc
, tt
, 3, data
, ubsan_encode_value (op0
),
156 ubsan_encode_value (op1
));
157 t
= fold_build3 (COND_EXPR
, void_type_node
, t
, tt
, void_zero_node
);
162 /* Instrument variable length array bound. */
165 ubsan_instrument_vla (location_t loc
, tree size
)
167 tree type
= TREE_TYPE (size
);
170 t
= fold_build2 (LE_EXPR
, boolean_type_node
, size
, build_int_cst (type
, 0));
171 tree data
= ubsan_create_data ("__ubsan_vla_data",
173 ubsan_type_descriptor (type
, false),
175 data
= build_fold_addr_expr_loc (loc
, data
);
176 tt
= builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_VLA_BOUND_NOT_POSITIVE
);
177 tt
= build_call_expr_loc (loc
, tt
, 2, data
, ubsan_encode_value (size
));
178 t
= fold_build3 (COND_EXPR
, void_type_node
, t
, tt
, void_zero_node
);
183 /* Instrument missing return in C++ functions returning non-void. */
186 ubsan_instrument_return (location_t loc
)
188 tree data
= ubsan_create_data ("__ubsan_missing_return_data", &loc
,
190 tree t
= builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_MISSING_RETURN
);
191 return build_call_expr_loc (loc
, t
, 1, build_fold_addr_expr_loc (loc
, data
));