annotate gcc/ubsan.c @ 127:4c56639505ff

fix function.c and add CbC-example Makefile
author mir3636
date Wed, 11 Apr 2018 18:46:58 +0900
parents 04ced10e8804
children 84e7813d76e9
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /* UndefinedBehaviorSanitizer, undefined behavior detector.
kono
parents:
diff changeset
2 Copyright (C) 2013-2017 Free Software Foundation, Inc.
kono
parents:
diff changeset
3 Contributed by Marek Polacek <polacek@redhat.com>
kono
parents:
diff changeset
4
kono
parents:
diff changeset
5 This file is part of GCC.
kono
parents:
diff changeset
6
kono
parents:
diff changeset
7 GCC is free software; you can redistribute it and/or modify it under
kono
parents:
diff changeset
8 the terms of the GNU General Public License as published by the Free
kono
parents:
diff changeset
9 Software Foundation; either version 3, or (at your option) any later
kono
parents:
diff changeset
10 version.
kono
parents:
diff changeset
11
kono
parents:
diff changeset
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
kono
parents:
diff changeset
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
kono
parents:
diff changeset
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
kono
parents:
diff changeset
15 for more details.
kono
parents:
diff changeset
16
kono
parents:
diff changeset
17 You should have received a copy of the GNU General Public License
kono
parents:
diff changeset
18 along with GCC; see the file COPYING3. If not see
kono
parents:
diff changeset
19 <http://www.gnu.org/licenses/>. */
kono
parents:
diff changeset
20
kono
parents:
diff changeset
21 #include "config.h"
kono
parents:
diff changeset
22 #include "system.h"
kono
parents:
diff changeset
23 #include "coretypes.h"
kono
parents:
diff changeset
24 #include "backend.h"
kono
parents:
diff changeset
25 #include "rtl.h"
kono
parents:
diff changeset
26 #include "c-family/c-common.h"
kono
parents:
diff changeset
27 #include "gimple.h"
kono
parents:
diff changeset
28 #include "cfghooks.h"
kono
parents:
diff changeset
29 #include "tree-pass.h"
kono
parents:
diff changeset
30 #include "memmodel.h"
kono
parents:
diff changeset
31 #include "tm_p.h"
kono
parents:
diff changeset
32 #include "ssa.h"
kono
parents:
diff changeset
33 #include "cgraph.h"
kono
parents:
diff changeset
34 #include "tree-pretty-print.h"
kono
parents:
diff changeset
35 #include "stor-layout.h"
kono
parents:
diff changeset
36 #include "cfganal.h"
kono
parents:
diff changeset
37 #include "gimple-iterator.h"
kono
parents:
diff changeset
38 #include "output.h"
kono
parents:
diff changeset
39 #include "cfgloop.h"
kono
parents:
diff changeset
40 #include "ubsan.h"
kono
parents:
diff changeset
41 #include "expr.h"
kono
parents:
diff changeset
42 #include "stringpool.h"
kono
parents:
diff changeset
43 #include "attribs.h"
kono
parents:
diff changeset
44 #include "asan.h"
kono
parents:
diff changeset
45 #include "gimplify-me.h"
kono
parents:
diff changeset
46 #include "dfp.h"
kono
parents:
diff changeset
47 #include "builtins.h"
kono
parents:
diff changeset
48 #include "tree-object-size.h"
kono
parents:
diff changeset
49 #include "tree-cfg.h"
kono
parents:
diff changeset
50 #include "gimple-fold.h"
kono
parents:
diff changeset
51 #include "varasm.h"
kono
parents:
diff changeset
52
kono
parents:
diff changeset
53 /* Map from a tree to a VAR_DECL tree. */
kono
parents:
diff changeset
54
kono
parents:
diff changeset
55 struct GTY((for_user)) tree_type_map {
kono
parents:
diff changeset
56 struct tree_map_base type;
kono
parents:
diff changeset
57 tree decl;
kono
parents:
diff changeset
58 };
kono
parents:
diff changeset
59
kono
parents:
diff changeset
60 struct tree_type_map_cache_hasher : ggc_cache_ptr_hash<tree_type_map>
kono
parents:
diff changeset
61 {
kono
parents:
diff changeset
62 static inline hashval_t
kono
parents:
diff changeset
63 hash (tree_type_map *t)
kono
parents:
diff changeset
64 {
kono
parents:
diff changeset
65 return TYPE_UID (t->type.from);
kono
parents:
diff changeset
66 }
kono
parents:
diff changeset
67
kono
parents:
diff changeset
68 static inline bool
kono
parents:
diff changeset
69 equal (tree_type_map *a, tree_type_map *b)
kono
parents:
diff changeset
70 {
kono
parents:
diff changeset
71 return a->type.from == b->type.from;
kono
parents:
diff changeset
72 }
kono
parents:
diff changeset
73
kono
parents:
diff changeset
74 static int
kono
parents:
diff changeset
75 keep_cache_entry (tree_type_map *&m)
kono
parents:
diff changeset
76 {
kono
parents:
diff changeset
77 return ggc_marked_p (m->type.from);
kono
parents:
diff changeset
78 }
kono
parents:
diff changeset
79 };
kono
parents:
diff changeset
80
kono
parents:
diff changeset
81 static GTY ((cache))
kono
parents:
diff changeset
82 hash_table<tree_type_map_cache_hasher> *decl_tree_for_type;
kono
parents:
diff changeset
83
kono
parents:
diff changeset
84 /* Lookup a VAR_DECL for TYPE, and return it if we find one. */
kono
parents:
diff changeset
85
kono
parents:
diff changeset
86 static tree
kono
parents:
diff changeset
87 decl_for_type_lookup (tree type)
kono
parents:
diff changeset
88 {
kono
parents:
diff changeset
89 /* If the hash table is not initialized yet, create it now. */
kono
parents:
diff changeset
90 if (decl_tree_for_type == NULL)
kono
parents:
diff changeset
91 {
kono
parents:
diff changeset
92 decl_tree_for_type
kono
parents:
diff changeset
93 = hash_table<tree_type_map_cache_hasher>::create_ggc (10);
kono
parents:
diff changeset
94 /* That also means we don't have to bother with the lookup. */
kono
parents:
diff changeset
95 return NULL_TREE;
kono
parents:
diff changeset
96 }
kono
parents:
diff changeset
97
kono
parents:
diff changeset
98 struct tree_type_map *h, in;
kono
parents:
diff changeset
99 in.type.from = type;
kono
parents:
diff changeset
100
kono
parents:
diff changeset
101 h = decl_tree_for_type->find_with_hash (&in, TYPE_UID (type));
kono
parents:
diff changeset
102 return h ? h->decl : NULL_TREE;
kono
parents:
diff changeset
103 }
kono
parents:
diff changeset
104
kono
parents:
diff changeset
105 /* Insert a mapping TYPE->DECL in the VAR_DECL for type hashtable. */
kono
parents:
diff changeset
106
kono
parents:
diff changeset
107 static void
kono
parents:
diff changeset
108 decl_for_type_insert (tree type, tree decl)
kono
parents:
diff changeset
109 {
kono
parents:
diff changeset
110 struct tree_type_map *h;
kono
parents:
diff changeset
111
kono
parents:
diff changeset
112 h = ggc_alloc<tree_type_map> ();
kono
parents:
diff changeset
113 h->type.from = type;
kono
parents:
diff changeset
114 h->decl = decl;
kono
parents:
diff changeset
115 *decl_tree_for_type->find_slot_with_hash (h, TYPE_UID (type), INSERT) = h;
kono
parents:
diff changeset
116 }
kono
parents:
diff changeset
117
kono
parents:
diff changeset
118 /* Helper routine, which encodes a value in the pointer_sized_int_node.
kono
parents:
diff changeset
119 Arguments with precision <= POINTER_SIZE are passed directly,
kono
parents:
diff changeset
120 the rest is passed by reference. T is a value we are to encode.
kono
parents:
diff changeset
121 PHASE determines when this function is called. */
kono
parents:
diff changeset
122
kono
parents:
diff changeset
123 tree
kono
parents:
diff changeset
124 ubsan_encode_value (tree t, enum ubsan_encode_value_phase phase)
kono
parents:
diff changeset
125 {
kono
parents:
diff changeset
126 tree type = TREE_TYPE (t);
kono
parents:
diff changeset
127 scalar_mode mode = SCALAR_TYPE_MODE (type);
kono
parents:
diff changeset
128 const unsigned int bitsize = GET_MODE_BITSIZE (mode);
kono
parents:
diff changeset
129 if (bitsize <= POINTER_SIZE)
kono
parents:
diff changeset
130 switch (TREE_CODE (type))
kono
parents:
diff changeset
131 {
kono
parents:
diff changeset
132 case BOOLEAN_TYPE:
kono
parents:
diff changeset
133 case ENUMERAL_TYPE:
kono
parents:
diff changeset
134 case INTEGER_TYPE:
kono
parents:
diff changeset
135 return fold_build1 (NOP_EXPR, pointer_sized_int_node, t);
kono
parents:
diff changeset
136 case REAL_TYPE:
kono
parents:
diff changeset
137 {
kono
parents:
diff changeset
138 tree itype = build_nonstandard_integer_type (bitsize, true);
kono
parents:
diff changeset
139 t = fold_build1 (VIEW_CONVERT_EXPR, itype, t);
kono
parents:
diff changeset
140 return fold_convert (pointer_sized_int_node, t);
kono
parents:
diff changeset
141 }
kono
parents:
diff changeset
142 default:
kono
parents:
diff changeset
143 gcc_unreachable ();
kono
parents:
diff changeset
144 }
kono
parents:
diff changeset
145 else
kono
parents:
diff changeset
146 {
kono
parents:
diff changeset
147 if (!DECL_P (t) || !TREE_ADDRESSABLE (t))
kono
parents:
diff changeset
148 {
kono
parents:
diff changeset
149 /* The reason for this is that we don't want to pessimize
kono
parents:
diff changeset
150 code by making vars unnecessarily addressable. */
kono
parents:
diff changeset
151 tree var;
kono
parents:
diff changeset
152 if (phase != UBSAN_ENCODE_VALUE_GENERIC)
kono
parents:
diff changeset
153 {
kono
parents:
diff changeset
154 var = create_tmp_var (type);
kono
parents:
diff changeset
155 mark_addressable (var);
kono
parents:
diff changeset
156 }
kono
parents:
diff changeset
157 else
kono
parents:
diff changeset
158 {
kono
parents:
diff changeset
159 var = create_tmp_var_raw (type);
kono
parents:
diff changeset
160 TREE_ADDRESSABLE (var) = 1;
kono
parents:
diff changeset
161 DECL_CONTEXT (var) = current_function_decl;
kono
parents:
diff changeset
162 }
kono
parents:
diff changeset
163 if (phase == UBSAN_ENCODE_VALUE_RTL)
kono
parents:
diff changeset
164 {
kono
parents:
diff changeset
165 rtx mem = assign_stack_temp_for_type (mode, GET_MODE_SIZE (mode),
kono
parents:
diff changeset
166 type);
kono
parents:
diff changeset
167 SET_DECL_RTL (var, mem);
kono
parents:
diff changeset
168 expand_assignment (var, t, false);
kono
parents:
diff changeset
169 return build_fold_addr_expr (var);
kono
parents:
diff changeset
170 }
kono
parents:
diff changeset
171 if (phase != UBSAN_ENCODE_VALUE_GENERIC)
kono
parents:
diff changeset
172 {
kono
parents:
diff changeset
173 tree tem = build2 (MODIFY_EXPR, void_type_node, var, t);
kono
parents:
diff changeset
174 t = build_fold_addr_expr (var);
kono
parents:
diff changeset
175 return build2 (COMPOUND_EXPR, TREE_TYPE (t), tem, t);
kono
parents:
diff changeset
176 }
kono
parents:
diff changeset
177 else
kono
parents:
diff changeset
178 {
kono
parents:
diff changeset
179 var = build4 (TARGET_EXPR, type, var, t, NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
180 return build_fold_addr_expr (var);
kono
parents:
diff changeset
181 }
kono
parents:
diff changeset
182 }
kono
parents:
diff changeset
183 else
kono
parents:
diff changeset
184 return build_fold_addr_expr (t);
kono
parents:
diff changeset
185 }
kono
parents:
diff changeset
186 }
kono
parents:
diff changeset
187
kono
parents:
diff changeset
188 /* Cached ubsan_get_type_descriptor_type () return value. */
kono
parents:
diff changeset
189 static GTY(()) tree ubsan_type_descriptor_type;
kono
parents:
diff changeset
190
kono
parents:
diff changeset
191 /* Build
kono
parents:
diff changeset
192 struct __ubsan_type_descriptor
kono
parents:
diff changeset
193 {
kono
parents:
diff changeset
194 unsigned short __typekind;
kono
parents:
diff changeset
195 unsigned short __typeinfo;
kono
parents:
diff changeset
196 char __typename[];
kono
parents:
diff changeset
197 }
kono
parents:
diff changeset
198 type. */
kono
parents:
diff changeset
199
kono
parents:
diff changeset
200 static tree
kono
parents:
diff changeset
201 ubsan_get_type_descriptor_type (void)
kono
parents:
diff changeset
202 {
kono
parents:
diff changeset
203 static const char *field_names[3]
kono
parents:
diff changeset
204 = { "__typekind", "__typeinfo", "__typename" };
kono
parents:
diff changeset
205 tree fields[3], ret;
kono
parents:
diff changeset
206
kono
parents:
diff changeset
207 if (ubsan_type_descriptor_type)
kono
parents:
diff changeset
208 return ubsan_type_descriptor_type;
kono
parents:
diff changeset
209
kono
parents:
diff changeset
210 tree itype = build_range_type (sizetype, size_zero_node, NULL_TREE);
kono
parents:
diff changeset
211 tree flex_arr_type = build_array_type (char_type_node, itype);
kono
parents:
diff changeset
212
kono
parents:
diff changeset
213 ret = make_node (RECORD_TYPE);
kono
parents:
diff changeset
214 for (int i = 0; i < 3; i++)
kono
parents:
diff changeset
215 {
kono
parents:
diff changeset
216 fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
kono
parents:
diff changeset
217 get_identifier (field_names[i]),
kono
parents:
diff changeset
218 (i == 2) ? flex_arr_type
kono
parents:
diff changeset
219 : short_unsigned_type_node);
kono
parents:
diff changeset
220 DECL_CONTEXT (fields[i]) = ret;
kono
parents:
diff changeset
221 if (i)
kono
parents:
diff changeset
222 DECL_CHAIN (fields[i - 1]) = fields[i];
kono
parents:
diff changeset
223 }
kono
parents:
diff changeset
224 tree type_decl = build_decl (input_location, TYPE_DECL,
kono
parents:
diff changeset
225 get_identifier ("__ubsan_type_descriptor"),
kono
parents:
diff changeset
226 ret);
kono
parents:
diff changeset
227 DECL_IGNORED_P (type_decl) = 1;
kono
parents:
diff changeset
228 DECL_ARTIFICIAL (type_decl) = 1;
kono
parents:
diff changeset
229 TYPE_FIELDS (ret) = fields[0];
kono
parents:
diff changeset
230 TYPE_NAME (ret) = type_decl;
kono
parents:
diff changeset
231 TYPE_STUB_DECL (ret) = type_decl;
kono
parents:
diff changeset
232 layout_type (ret);
kono
parents:
diff changeset
233 ubsan_type_descriptor_type = ret;
kono
parents:
diff changeset
234 return ret;
kono
parents:
diff changeset
235 }
kono
parents:
diff changeset
236
kono
parents:
diff changeset
237 /* Cached ubsan_get_source_location_type () return value. */
kono
parents:
diff changeset
238 static GTY(()) tree ubsan_source_location_type;
kono
parents:
diff changeset
239
kono
parents:
diff changeset
240 /* Build
kono
parents:
diff changeset
241 struct __ubsan_source_location
kono
parents:
diff changeset
242 {
kono
parents:
diff changeset
243 const char *__filename;
kono
parents:
diff changeset
244 unsigned int __line;
kono
parents:
diff changeset
245 unsigned int __column;
kono
parents:
diff changeset
246 }
kono
parents:
diff changeset
247 type. */
kono
parents:
diff changeset
248
kono
parents:
diff changeset
249 tree
kono
parents:
diff changeset
250 ubsan_get_source_location_type (void)
kono
parents:
diff changeset
251 {
kono
parents:
diff changeset
252 static const char *field_names[3]
kono
parents:
diff changeset
253 = { "__filename", "__line", "__column" };
kono
parents:
diff changeset
254 tree fields[3], ret;
kono
parents:
diff changeset
255 if (ubsan_source_location_type)
kono
parents:
diff changeset
256 return ubsan_source_location_type;
kono
parents:
diff changeset
257
kono
parents:
diff changeset
258 tree const_char_type = build_qualified_type (char_type_node,
kono
parents:
diff changeset
259 TYPE_QUAL_CONST);
kono
parents:
diff changeset
260
kono
parents:
diff changeset
261 ret = make_node (RECORD_TYPE);
kono
parents:
diff changeset
262 for (int i = 0; i < 3; i++)
kono
parents:
diff changeset
263 {
kono
parents:
diff changeset
264 fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
kono
parents:
diff changeset
265 get_identifier (field_names[i]),
kono
parents:
diff changeset
266 (i == 0) ? build_pointer_type (const_char_type)
kono
parents:
diff changeset
267 : unsigned_type_node);
kono
parents:
diff changeset
268 DECL_CONTEXT (fields[i]) = ret;
kono
parents:
diff changeset
269 if (i)
kono
parents:
diff changeset
270 DECL_CHAIN (fields[i - 1]) = fields[i];
kono
parents:
diff changeset
271 }
kono
parents:
diff changeset
272 tree type_decl = build_decl (input_location, TYPE_DECL,
kono
parents:
diff changeset
273 get_identifier ("__ubsan_source_location"),
kono
parents:
diff changeset
274 ret);
kono
parents:
diff changeset
275 DECL_IGNORED_P (type_decl) = 1;
kono
parents:
diff changeset
276 DECL_ARTIFICIAL (type_decl) = 1;
kono
parents:
diff changeset
277 TYPE_FIELDS (ret) = fields[0];
kono
parents:
diff changeset
278 TYPE_NAME (ret) = type_decl;
kono
parents:
diff changeset
279 TYPE_STUB_DECL (ret) = type_decl;
kono
parents:
diff changeset
280 layout_type (ret);
kono
parents:
diff changeset
281 ubsan_source_location_type = ret;
kono
parents:
diff changeset
282 return ret;
kono
parents:
diff changeset
283 }
kono
parents:
diff changeset
284
kono
parents:
diff changeset
285 /* Helper routine that returns a CONSTRUCTOR of __ubsan_source_location
kono
parents:
diff changeset
286 type with its fields filled from a location_t LOC. */
kono
parents:
diff changeset
287
kono
parents:
diff changeset
288 static tree
kono
parents:
diff changeset
289 ubsan_source_location (location_t loc)
kono
parents:
diff changeset
290 {
kono
parents:
diff changeset
291 expanded_location xloc;
kono
parents:
diff changeset
292 tree type = ubsan_get_source_location_type ();
kono
parents:
diff changeset
293
kono
parents:
diff changeset
294 xloc = expand_location (loc);
kono
parents:
diff changeset
295 tree str;
kono
parents:
diff changeset
296 if (xloc.file == NULL)
kono
parents:
diff changeset
297 {
kono
parents:
diff changeset
298 str = build_int_cst (ptr_type_node, 0);
kono
parents:
diff changeset
299 xloc.line = 0;
kono
parents:
diff changeset
300 xloc.column = 0;
kono
parents:
diff changeset
301 }
kono
parents:
diff changeset
302 else
kono
parents:
diff changeset
303 {
kono
parents:
diff changeset
304 /* Fill in the values from LOC. */
kono
parents:
diff changeset
305 size_t len = strlen (xloc.file) + 1;
kono
parents:
diff changeset
306 str = build_string (len, xloc.file);
kono
parents:
diff changeset
307 TREE_TYPE (str) = build_array_type_nelts (char_type_node, len);
kono
parents:
diff changeset
308 TREE_READONLY (str) = 1;
kono
parents:
diff changeset
309 TREE_STATIC (str) = 1;
kono
parents:
diff changeset
310 str = build_fold_addr_expr (str);
kono
parents:
diff changeset
311 }
kono
parents:
diff changeset
312 tree ctor = build_constructor_va (type, 3, NULL_TREE, str, NULL_TREE,
kono
parents:
diff changeset
313 build_int_cst (unsigned_type_node,
kono
parents:
diff changeset
314 xloc.line), NULL_TREE,
kono
parents:
diff changeset
315 build_int_cst (unsigned_type_node,
kono
parents:
diff changeset
316 xloc.column));
kono
parents:
diff changeset
317 TREE_CONSTANT (ctor) = 1;
kono
parents:
diff changeset
318 TREE_STATIC (ctor) = 1;
kono
parents:
diff changeset
319
kono
parents:
diff changeset
320 return ctor;
kono
parents:
diff changeset
321 }
kono
parents:
diff changeset
322
kono
parents:
diff changeset
323 /* This routine returns a magic number for TYPE. */
kono
parents:
diff changeset
324
kono
parents:
diff changeset
325 static unsigned short
kono
parents:
diff changeset
326 get_ubsan_type_info_for_type (tree type)
kono
parents:
diff changeset
327 {
kono
parents:
diff changeset
328 if (TREE_CODE (type) == REAL_TYPE)
kono
parents:
diff changeset
329 return tree_to_uhwi (TYPE_SIZE (type));
kono
parents:
diff changeset
330 else if (INTEGRAL_TYPE_P (type))
kono
parents:
diff changeset
331 {
kono
parents:
diff changeset
332 int prec = exact_log2 (tree_to_uhwi (TYPE_SIZE (type)));
kono
parents:
diff changeset
333 gcc_assert (prec != -1);
kono
parents:
diff changeset
334 return (prec << 1) | !TYPE_UNSIGNED (type);
kono
parents:
diff changeset
335 }
kono
parents:
diff changeset
336 else
kono
parents:
diff changeset
337 return 0;
kono
parents:
diff changeset
338 }
kono
parents:
diff changeset
339
kono
parents:
diff changeset
340 /* Counters for internal labels. ubsan_ids[0] for Lubsan_type,
kono
parents:
diff changeset
341 ubsan_ids[1] for Lubsan_data labels. */
kono
parents:
diff changeset
342 static GTY(()) unsigned int ubsan_ids[2];
kono
parents:
diff changeset
343
kono
parents:
diff changeset
344 /* Helper routine that returns ADDR_EXPR of a VAR_DECL of a type
kono
parents:
diff changeset
345 descriptor. It first looks into the hash table; if not found,
kono
parents:
diff changeset
346 create the VAR_DECL, put it into the hash table and return the
kono
parents:
diff changeset
347 ADDR_EXPR of it. TYPE describes a particular type. PSTYLE is
kono
parents:
diff changeset
348 an enum controlling how we want to print the type. */
kono
parents:
diff changeset
349
kono
parents:
diff changeset
350 tree
kono
parents:
diff changeset
351 ubsan_type_descriptor (tree type, enum ubsan_print_style pstyle)
kono
parents:
diff changeset
352 {
kono
parents:
diff changeset
353 /* See through any typedefs. */
kono
parents:
diff changeset
354 type = TYPE_MAIN_VARIANT (type);
kono
parents:
diff changeset
355
kono
parents:
diff changeset
356 tree decl = decl_for_type_lookup (type);
kono
parents:
diff changeset
357 /* It is possible that some of the earlier created DECLs were found
kono
parents:
diff changeset
358 unused, in that case they weren't emitted and varpool_node::get
kono
parents:
diff changeset
359 returns NULL node on them. But now we really need them. Thus,
kono
parents:
diff changeset
360 renew them here. */
kono
parents:
diff changeset
361 if (decl != NULL_TREE && varpool_node::get (decl))
kono
parents:
diff changeset
362 return build_fold_addr_expr (decl);
kono
parents:
diff changeset
363
kono
parents:
diff changeset
364 tree dtype = ubsan_get_type_descriptor_type ();
kono
parents:
diff changeset
365 tree type2 = type;
kono
parents:
diff changeset
366 const char *tname = NULL;
kono
parents:
diff changeset
367 pretty_printer pretty_name;
kono
parents:
diff changeset
368 unsigned char deref_depth = 0;
kono
parents:
diff changeset
369 unsigned short tkind, tinfo;
kono
parents:
diff changeset
370
kono
parents:
diff changeset
371 /* Get the name of the type, or the name of the pointer type. */
kono
parents:
diff changeset
372 if (pstyle == UBSAN_PRINT_POINTER)
kono
parents:
diff changeset
373 {
kono
parents:
diff changeset
374 gcc_assert (POINTER_TYPE_P (type));
kono
parents:
diff changeset
375 type2 = TREE_TYPE (type);
kono
parents:
diff changeset
376
kono
parents:
diff changeset
377 /* Remove any '*' operators from TYPE. */
kono
parents:
diff changeset
378 while (POINTER_TYPE_P (type2))
kono
parents:
diff changeset
379 deref_depth++, type2 = TREE_TYPE (type2);
kono
parents:
diff changeset
380
kono
parents:
diff changeset
381 if (TREE_CODE (type2) == METHOD_TYPE)
kono
parents:
diff changeset
382 type2 = TYPE_METHOD_BASETYPE (type2);
kono
parents:
diff changeset
383 }
kono
parents:
diff changeset
384
kono
parents:
diff changeset
385 /* If an array, get its type. */
kono
parents:
diff changeset
386 type2 = strip_array_types (type2);
kono
parents:
diff changeset
387
kono
parents:
diff changeset
388 if (pstyle == UBSAN_PRINT_ARRAY)
kono
parents:
diff changeset
389 {
kono
parents:
diff changeset
390 while (POINTER_TYPE_P (type2))
kono
parents:
diff changeset
391 deref_depth++, type2 = TREE_TYPE (type2);
kono
parents:
diff changeset
392 }
kono
parents:
diff changeset
393
kono
parents:
diff changeset
394 if (TYPE_NAME (type2) != NULL)
kono
parents:
diff changeset
395 {
kono
parents:
diff changeset
396 if (TREE_CODE (TYPE_NAME (type2)) == IDENTIFIER_NODE)
kono
parents:
diff changeset
397 tname = IDENTIFIER_POINTER (TYPE_NAME (type2));
kono
parents:
diff changeset
398 else if (DECL_NAME (TYPE_NAME (type2)) != NULL)
kono
parents:
diff changeset
399 tname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type2)));
kono
parents:
diff changeset
400 }
kono
parents:
diff changeset
401
kono
parents:
diff changeset
402 if (tname == NULL)
kono
parents:
diff changeset
403 /* We weren't able to determine the type name. */
kono
parents:
diff changeset
404 tname = "<unknown>";
kono
parents:
diff changeset
405
kono
parents:
diff changeset
406 tree eltype = type;
kono
parents:
diff changeset
407 if (pstyle == UBSAN_PRINT_POINTER)
kono
parents:
diff changeset
408 {
kono
parents:
diff changeset
409 pp_printf (&pretty_name, "'%s%s%s%s%s%s%s",
kono
parents:
diff changeset
410 TYPE_VOLATILE (type2) ? "volatile " : "",
kono
parents:
diff changeset
411 TYPE_READONLY (type2) ? "const " : "",
kono
parents:
diff changeset
412 TYPE_RESTRICT (type2) ? "restrict " : "",
kono
parents:
diff changeset
413 TYPE_ATOMIC (type2) ? "_Atomic " : "",
kono
parents:
diff changeset
414 TREE_CODE (type2) == RECORD_TYPE
kono
parents:
diff changeset
415 ? "struct "
kono
parents:
diff changeset
416 : TREE_CODE (type2) == UNION_TYPE
kono
parents:
diff changeset
417 ? "union " : "", tname,
kono
parents:
diff changeset
418 deref_depth == 0 ? "" : " ");
kono
parents:
diff changeset
419 while (deref_depth-- > 0)
kono
parents:
diff changeset
420 pp_star (&pretty_name);
kono
parents:
diff changeset
421 pp_quote (&pretty_name);
kono
parents:
diff changeset
422 }
kono
parents:
diff changeset
423 else if (pstyle == UBSAN_PRINT_ARRAY)
kono
parents:
diff changeset
424 {
kono
parents:
diff changeset
425 /* Pretty print the array dimensions. */
kono
parents:
diff changeset
426 gcc_assert (TREE_CODE (type) == ARRAY_TYPE);
kono
parents:
diff changeset
427 tree t = type;
kono
parents:
diff changeset
428 pp_printf (&pretty_name, "'%s ", tname);
kono
parents:
diff changeset
429 while (deref_depth-- > 0)
kono
parents:
diff changeset
430 pp_star (&pretty_name);
kono
parents:
diff changeset
431 while (TREE_CODE (t) == ARRAY_TYPE)
kono
parents:
diff changeset
432 {
kono
parents:
diff changeset
433 pp_left_bracket (&pretty_name);
kono
parents:
diff changeset
434 tree dom = TYPE_DOMAIN (t);
kono
parents:
diff changeset
435 if (dom != NULL_TREE
kono
parents:
diff changeset
436 && TYPE_MAX_VALUE (dom) != NULL_TREE
kono
parents:
diff changeset
437 && TREE_CODE (TYPE_MAX_VALUE (dom)) == INTEGER_CST)
kono
parents:
diff changeset
438 {
kono
parents:
diff changeset
439 if (tree_fits_uhwi_p (TYPE_MAX_VALUE (dom))
kono
parents:
diff changeset
440 && tree_to_uhwi (TYPE_MAX_VALUE (dom)) + 1 != 0)
kono
parents:
diff changeset
441 pp_printf (&pretty_name, HOST_WIDE_INT_PRINT_DEC,
kono
parents:
diff changeset
442 tree_to_uhwi (TYPE_MAX_VALUE (dom)) + 1);
kono
parents:
diff changeset
443 else
kono
parents:
diff changeset
444 pp_wide_int (&pretty_name,
kono
parents:
diff changeset
445 wi::add (wi::to_widest (TYPE_MAX_VALUE (dom)), 1),
kono
parents:
diff changeset
446 TYPE_SIGN (TREE_TYPE (dom)));
kono
parents:
diff changeset
447 }
kono
parents:
diff changeset
448 else
kono
parents:
diff changeset
449 /* ??? We can't determine the variable name; print VLA unspec. */
kono
parents:
diff changeset
450 pp_star (&pretty_name);
kono
parents:
diff changeset
451 pp_right_bracket (&pretty_name);
kono
parents:
diff changeset
452 t = TREE_TYPE (t);
kono
parents:
diff changeset
453 }
kono
parents:
diff changeset
454 pp_quote (&pretty_name);
kono
parents:
diff changeset
455
kono
parents:
diff changeset
456 /* Save the tree with stripped types. */
kono
parents:
diff changeset
457 eltype = t;
kono
parents:
diff changeset
458 }
kono
parents:
diff changeset
459 else
kono
parents:
diff changeset
460 pp_printf (&pretty_name, "'%s'", tname);
kono
parents:
diff changeset
461
kono
parents:
diff changeset
462 switch (TREE_CODE (eltype))
kono
parents:
diff changeset
463 {
kono
parents:
diff changeset
464 case BOOLEAN_TYPE:
kono
parents:
diff changeset
465 case ENUMERAL_TYPE:
kono
parents:
diff changeset
466 case INTEGER_TYPE:
kono
parents:
diff changeset
467 tkind = 0x0000;
kono
parents:
diff changeset
468 break;
kono
parents:
diff changeset
469 case REAL_TYPE:
kono
parents:
diff changeset
470 /* FIXME: libubsan right now only supports float, double and
kono
parents:
diff changeset
471 long double type formats. */
kono
parents:
diff changeset
472 if (TYPE_MODE (eltype) == TYPE_MODE (float_type_node)
kono
parents:
diff changeset
473 || TYPE_MODE (eltype) == TYPE_MODE (double_type_node)
kono
parents:
diff changeset
474 || TYPE_MODE (eltype) == TYPE_MODE (long_double_type_node))
kono
parents:
diff changeset
475 tkind = 0x0001;
kono
parents:
diff changeset
476 else
kono
parents:
diff changeset
477 tkind = 0xffff;
kono
parents:
diff changeset
478 break;
kono
parents:
diff changeset
479 default:
kono
parents:
diff changeset
480 tkind = 0xffff;
kono
parents:
diff changeset
481 break;
kono
parents:
diff changeset
482 }
kono
parents:
diff changeset
483 tinfo = get_ubsan_type_info_for_type (eltype);
kono
parents:
diff changeset
484
kono
parents:
diff changeset
485 /* Create a new VAR_DECL of type descriptor. */
kono
parents:
diff changeset
486 const char *tmp = pp_formatted_text (&pretty_name);
kono
parents:
diff changeset
487 size_t len = strlen (tmp) + 1;
kono
parents:
diff changeset
488 tree str = build_string (len, tmp);
kono
parents:
diff changeset
489 TREE_TYPE (str) = build_array_type_nelts (char_type_node, len);
kono
parents:
diff changeset
490 TREE_READONLY (str) = 1;
kono
parents:
diff changeset
491 TREE_STATIC (str) = 1;
kono
parents:
diff changeset
492
kono
parents:
diff changeset
493 char tmp_name[32];
kono
parents:
diff changeset
494 ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lubsan_type", ubsan_ids[0]++);
kono
parents:
diff changeset
495 decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (tmp_name),
kono
parents:
diff changeset
496 dtype);
kono
parents:
diff changeset
497 TREE_STATIC (decl) = 1;
kono
parents:
diff changeset
498 TREE_PUBLIC (decl) = 0;
kono
parents:
diff changeset
499 DECL_ARTIFICIAL (decl) = 1;
kono
parents:
diff changeset
500 DECL_IGNORED_P (decl) = 1;
kono
parents:
diff changeset
501 DECL_EXTERNAL (decl) = 0;
kono
parents:
diff changeset
502 DECL_SIZE (decl)
kono
parents:
diff changeset
503 = size_binop (PLUS_EXPR, DECL_SIZE (decl), TYPE_SIZE (TREE_TYPE (str)));
kono
parents:
diff changeset
504 DECL_SIZE_UNIT (decl)
kono
parents:
diff changeset
505 = size_binop (PLUS_EXPR, DECL_SIZE_UNIT (decl),
kono
parents:
diff changeset
506 TYPE_SIZE_UNIT (TREE_TYPE (str)));
kono
parents:
diff changeset
507
kono
parents:
diff changeset
508 tree ctor = build_constructor_va (dtype, 3, NULL_TREE,
kono
parents:
diff changeset
509 build_int_cst (short_unsigned_type_node,
kono
parents:
diff changeset
510 tkind), NULL_TREE,
kono
parents:
diff changeset
511 build_int_cst (short_unsigned_type_node,
kono
parents:
diff changeset
512 tinfo), NULL_TREE, str);
kono
parents:
diff changeset
513 TREE_CONSTANT (ctor) = 1;
kono
parents:
diff changeset
514 TREE_STATIC (ctor) = 1;
kono
parents:
diff changeset
515 DECL_INITIAL (decl) = ctor;
kono
parents:
diff changeset
516 varpool_node::finalize_decl (decl);
kono
parents:
diff changeset
517
kono
parents:
diff changeset
518 /* Save the VAR_DECL into the hash table. */
kono
parents:
diff changeset
519 decl_for_type_insert (type, decl);
kono
parents:
diff changeset
520
kono
parents:
diff changeset
521 return build_fold_addr_expr (decl);
kono
parents:
diff changeset
522 }
kono
parents:
diff changeset
523
kono
parents:
diff changeset
524 /* Create a structure for the ubsan library. NAME is a name of the new
kono
parents:
diff changeset
525 structure. LOCCNT is number of locations, PLOC points to array of
kono
parents:
diff changeset
526 locations. The arguments in ... are of __ubsan_type_descriptor type
kono
parents:
diff changeset
527 and there are at most two of them, followed by NULL_TREE, followed
kono
parents:
diff changeset
528 by optional extra arguments and another NULL_TREE. */
kono
parents:
diff changeset
529
kono
parents:
diff changeset
530 tree
kono
parents:
diff changeset
531 ubsan_create_data (const char *name, int loccnt, const location_t *ploc, ...)
kono
parents:
diff changeset
532 {
kono
parents:
diff changeset
533 va_list args;
kono
parents:
diff changeset
534 tree ret, t;
kono
parents:
diff changeset
535 tree fields[6];
kono
parents:
diff changeset
536 vec<tree, va_gc> *saved_args = NULL;
kono
parents:
diff changeset
537 size_t i = 0;
kono
parents:
diff changeset
538 int j;
kono
parents:
diff changeset
539
kono
parents:
diff changeset
540 /* It is possible that PCH zapped table with definitions of sanitizer
kono
parents:
diff changeset
541 builtins. Reinitialize them if needed. */
kono
parents:
diff changeset
542 initialize_sanitizer_builtins ();
kono
parents:
diff changeset
543
kono
parents:
diff changeset
544 /* Firstly, create a pointer to type descriptor type. */
kono
parents:
diff changeset
545 tree td_type = ubsan_get_type_descriptor_type ();
kono
parents:
diff changeset
546 td_type = build_pointer_type (td_type);
kono
parents:
diff changeset
547
kono
parents:
diff changeset
548 /* Create the structure type. */
kono
parents:
diff changeset
549 ret = make_node (RECORD_TYPE);
kono
parents:
diff changeset
550 for (j = 0; j < loccnt; j++)
kono
parents:
diff changeset
551 {
kono
parents:
diff changeset
552 gcc_checking_assert (i < 2);
kono
parents:
diff changeset
553 fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
kono
parents:
diff changeset
554 ubsan_get_source_location_type ());
kono
parents:
diff changeset
555 DECL_CONTEXT (fields[i]) = ret;
kono
parents:
diff changeset
556 if (i)
kono
parents:
diff changeset
557 DECL_CHAIN (fields[i - 1]) = fields[i];
kono
parents:
diff changeset
558 i++;
kono
parents:
diff changeset
559 }
kono
parents:
diff changeset
560
kono
parents:
diff changeset
561 va_start (args, ploc);
kono
parents:
diff changeset
562 for (t = va_arg (args, tree); t != NULL_TREE;
kono
parents:
diff changeset
563 i++, t = va_arg (args, tree))
kono
parents:
diff changeset
564 {
kono
parents:
diff changeset
565 gcc_checking_assert (i < 4);
kono
parents:
diff changeset
566 /* Save the tree arguments for later use. */
kono
parents:
diff changeset
567 vec_safe_push (saved_args, t);
kono
parents:
diff changeset
568 fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
kono
parents:
diff changeset
569 td_type);
kono
parents:
diff changeset
570 DECL_CONTEXT (fields[i]) = ret;
kono
parents:
diff changeset
571 if (i)
kono
parents:
diff changeset
572 DECL_CHAIN (fields[i - 1]) = fields[i];
kono
parents:
diff changeset
573 }
kono
parents:
diff changeset
574
kono
parents:
diff changeset
575 for (t = va_arg (args, tree); t != NULL_TREE;
kono
parents:
diff changeset
576 i++, t = va_arg (args, tree))
kono
parents:
diff changeset
577 {
kono
parents:
diff changeset
578 gcc_checking_assert (i < 6);
kono
parents:
diff changeset
579 /* Save the tree arguments for later use. */
kono
parents:
diff changeset
580 vec_safe_push (saved_args, t);
kono
parents:
diff changeset
581 fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
kono
parents:
diff changeset
582 TREE_TYPE (t));
kono
parents:
diff changeset
583 DECL_CONTEXT (fields[i]) = ret;
kono
parents:
diff changeset
584 if (i)
kono
parents:
diff changeset
585 DECL_CHAIN (fields[i - 1]) = fields[i];
kono
parents:
diff changeset
586 }
kono
parents:
diff changeset
587 va_end (args);
kono
parents:
diff changeset
588
kono
parents:
diff changeset
589 tree type_decl = build_decl (input_location, TYPE_DECL,
kono
parents:
diff changeset
590 get_identifier (name), ret);
kono
parents:
diff changeset
591 DECL_IGNORED_P (type_decl) = 1;
kono
parents:
diff changeset
592 DECL_ARTIFICIAL (type_decl) = 1;
kono
parents:
diff changeset
593 TYPE_FIELDS (ret) = fields[0];
kono
parents:
diff changeset
594 TYPE_NAME (ret) = type_decl;
kono
parents:
diff changeset
595 TYPE_STUB_DECL (ret) = type_decl;
kono
parents:
diff changeset
596 layout_type (ret);
kono
parents:
diff changeset
597
kono
parents:
diff changeset
598 /* Now, fill in the type. */
kono
parents:
diff changeset
599 char tmp_name[32];
kono
parents:
diff changeset
600 ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lubsan_data", ubsan_ids[1]++);
kono
parents:
diff changeset
601 tree var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (tmp_name),
kono
parents:
diff changeset
602 ret);
kono
parents:
diff changeset
603 TREE_STATIC (var) = 1;
kono
parents:
diff changeset
604 TREE_PUBLIC (var) = 0;
kono
parents:
diff changeset
605 DECL_ARTIFICIAL (var) = 1;
kono
parents:
diff changeset
606 DECL_IGNORED_P (var) = 1;
kono
parents:
diff changeset
607 DECL_EXTERNAL (var) = 0;
kono
parents:
diff changeset
608
kono
parents:
diff changeset
609 vec<constructor_elt, va_gc> *v;
kono
parents:
diff changeset
610 vec_alloc (v, i);
kono
parents:
diff changeset
611 tree ctor = build_constructor (ret, v);
kono
parents:
diff changeset
612
kono
parents:
diff changeset
613 /* If desirable, set the __ubsan_source_location element. */
kono
parents:
diff changeset
614 for (j = 0; j < loccnt; j++)
kono
parents:
diff changeset
615 {
kono
parents:
diff changeset
616 location_t loc = LOCATION_LOCUS (ploc[j]);
kono
parents:
diff changeset
617 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, ubsan_source_location (loc));
kono
parents:
diff changeset
618 }
kono
parents:
diff changeset
619
kono
parents:
diff changeset
620 size_t nelts = vec_safe_length (saved_args);
kono
parents:
diff changeset
621 for (i = 0; i < nelts; i++)
kono
parents:
diff changeset
622 {
kono
parents:
diff changeset
623 t = (*saved_args)[i];
kono
parents:
diff changeset
624 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, t);
kono
parents:
diff changeset
625 }
kono
parents:
diff changeset
626
kono
parents:
diff changeset
627 TREE_CONSTANT (ctor) = 1;
kono
parents:
diff changeset
628 TREE_STATIC (ctor) = 1;
kono
parents:
diff changeset
629 DECL_INITIAL (var) = ctor;
kono
parents:
diff changeset
630 varpool_node::finalize_decl (var);
kono
parents:
diff changeset
631
kono
parents:
diff changeset
632 return var;
kono
parents:
diff changeset
633 }
kono
parents:
diff changeset
634
kono
parents:
diff changeset
635 /* Instrument the __builtin_unreachable call. We just call the libubsan
kono
parents:
diff changeset
636 routine instead. */
kono
parents:
diff changeset
637
kono
parents:
diff changeset
638 bool
kono
parents:
diff changeset
639 ubsan_instrument_unreachable (gimple_stmt_iterator *gsi)
kono
parents:
diff changeset
640 {
kono
parents:
diff changeset
641 gimple *g;
kono
parents:
diff changeset
642 location_t loc = gimple_location (gsi_stmt (*gsi));
kono
parents:
diff changeset
643
kono
parents:
diff changeset
644 if (flag_sanitize_undefined_trap_on_error)
kono
parents:
diff changeset
645 g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
kono
parents:
diff changeset
646 else
kono
parents:
diff changeset
647 {
kono
parents:
diff changeset
648 tree data = ubsan_create_data ("__ubsan_unreachable_data", 1, &loc,
kono
parents:
diff changeset
649 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
650 data = build_fold_addr_expr_loc (loc, data);
kono
parents:
diff changeset
651 tree fn
kono
parents:
diff changeset
652 = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_BUILTIN_UNREACHABLE);
kono
parents:
diff changeset
653 g = gimple_build_call (fn, 1, data);
kono
parents:
diff changeset
654 }
kono
parents:
diff changeset
655 gimple_set_location (g, loc);
kono
parents:
diff changeset
656 gsi_replace (gsi, g, false);
kono
parents:
diff changeset
657 return false;
kono
parents:
diff changeset
658 }
kono
parents:
diff changeset
659
kono
parents:
diff changeset
660 /* Return true if T is a call to a libubsan routine. */
kono
parents:
diff changeset
661
kono
parents:
diff changeset
662 bool
kono
parents:
diff changeset
663 is_ubsan_builtin_p (tree t)
kono
parents:
diff changeset
664 {
kono
parents:
diff changeset
665 return TREE_CODE (t) == FUNCTION_DECL
kono
parents:
diff changeset
666 && DECL_BUILT_IN_CLASS (t) == BUILT_IN_NORMAL
kono
parents:
diff changeset
667 && strncmp (IDENTIFIER_POINTER (DECL_NAME (t)),
kono
parents:
diff changeset
668 "__builtin___ubsan_", 18) == 0;
kono
parents:
diff changeset
669 }
kono
parents:
diff changeset
670
kono
parents:
diff changeset
671 /* Create a callgraph edge for statement STMT. */
kono
parents:
diff changeset
672
kono
parents:
diff changeset
673 static void
kono
parents:
diff changeset
674 ubsan_create_edge (gimple *stmt)
kono
parents:
diff changeset
675 {
kono
parents:
diff changeset
676 gcall *call_stmt = dyn_cast <gcall *> (stmt);
kono
parents:
diff changeset
677 basic_block bb = gimple_bb (stmt);
kono
parents:
diff changeset
678 int freq = compute_call_stmt_bb_frequency (current_function_decl, bb);
kono
parents:
diff changeset
679 cgraph_node *node = cgraph_node::get (current_function_decl);
kono
parents:
diff changeset
680 tree decl = gimple_call_fndecl (call_stmt);
kono
parents:
diff changeset
681 if (decl)
kono
parents:
diff changeset
682 node->create_edge (cgraph_node::get_create (decl), call_stmt, bb->count,
kono
parents:
diff changeset
683 freq);
kono
parents:
diff changeset
684 }
kono
parents:
diff changeset
685
kono
parents:
diff changeset
686 /* Expand the UBSAN_BOUNDS special builtin function. */
kono
parents:
diff changeset
687
kono
parents:
diff changeset
688 bool
kono
parents:
diff changeset
689 ubsan_expand_bounds_ifn (gimple_stmt_iterator *gsi)
kono
parents:
diff changeset
690 {
kono
parents:
diff changeset
691 gimple *stmt = gsi_stmt (*gsi);
kono
parents:
diff changeset
692 location_t loc = gimple_location (stmt);
kono
parents:
diff changeset
693 gcc_assert (gimple_call_num_args (stmt) == 3);
kono
parents:
diff changeset
694
kono
parents:
diff changeset
695 /* Pick up the arguments of the UBSAN_BOUNDS call. */
kono
parents:
diff changeset
696 tree type = TREE_TYPE (TREE_TYPE (gimple_call_arg (stmt, 0)));
kono
parents:
diff changeset
697 tree index = gimple_call_arg (stmt, 1);
kono
parents:
diff changeset
698 tree orig_index = index;
kono
parents:
diff changeset
699 tree bound = gimple_call_arg (stmt, 2);
kono
parents:
diff changeset
700
kono
parents:
diff changeset
701 gimple_stmt_iterator gsi_orig = *gsi;
kono
parents:
diff changeset
702
kono
parents:
diff changeset
703 /* Create condition "if (index > bound)". */
kono
parents:
diff changeset
704 basic_block then_bb, fallthru_bb;
kono
parents:
diff changeset
705 gimple_stmt_iterator cond_insert_point
kono
parents:
diff changeset
706 = create_cond_insert_point (gsi, false, false, true,
kono
parents:
diff changeset
707 &then_bb, &fallthru_bb);
kono
parents:
diff changeset
708 index = fold_convert (TREE_TYPE (bound), index);
kono
parents:
diff changeset
709 index = force_gimple_operand_gsi (&cond_insert_point, index,
kono
parents:
diff changeset
710 true, NULL_TREE,
kono
parents:
diff changeset
711 false, GSI_NEW_STMT);
kono
parents:
diff changeset
712 gimple *g = gimple_build_cond (GT_EXPR, index, bound, NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
713 gimple_set_location (g, loc);
kono
parents:
diff changeset
714 gsi_insert_after (&cond_insert_point, g, GSI_NEW_STMT);
kono
parents:
diff changeset
715
kono
parents:
diff changeset
716 /* Generate __ubsan_handle_out_of_bounds call. */
kono
parents:
diff changeset
717 *gsi = gsi_after_labels (then_bb);
kono
parents:
diff changeset
718 if (flag_sanitize_undefined_trap_on_error)
kono
parents:
diff changeset
719 g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
kono
parents:
diff changeset
720 else
kono
parents:
diff changeset
721 {
kono
parents:
diff changeset
722 tree data
kono
parents:
diff changeset
723 = ubsan_create_data ("__ubsan_out_of_bounds_data", 1, &loc,
kono
parents:
diff changeset
724 ubsan_type_descriptor (type, UBSAN_PRINT_ARRAY),
kono
parents:
diff changeset
725 ubsan_type_descriptor (TREE_TYPE (orig_index)),
kono
parents:
diff changeset
726 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
727 data = build_fold_addr_expr_loc (loc, data);
kono
parents:
diff changeset
728 enum built_in_function bcode
kono
parents:
diff changeset
729 = (flag_sanitize_recover & SANITIZE_BOUNDS)
kono
parents:
diff changeset
730 ? BUILT_IN_UBSAN_HANDLE_OUT_OF_BOUNDS
kono
parents:
diff changeset
731 : BUILT_IN_UBSAN_HANDLE_OUT_OF_BOUNDS_ABORT;
kono
parents:
diff changeset
732 tree fn = builtin_decl_explicit (bcode);
kono
parents:
diff changeset
733 tree val = ubsan_encode_value (orig_index, UBSAN_ENCODE_VALUE_GIMPLE);
kono
parents:
diff changeset
734 val = force_gimple_operand_gsi (gsi, val, true, NULL_TREE, true,
kono
parents:
diff changeset
735 GSI_SAME_STMT);
kono
parents:
diff changeset
736 g = gimple_build_call (fn, 2, data, val);
kono
parents:
diff changeset
737 }
kono
parents:
diff changeset
738 gimple_set_location (g, loc);
kono
parents:
diff changeset
739 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
740
kono
parents:
diff changeset
741 /* Get rid of the UBSAN_BOUNDS call from the IR. */
kono
parents:
diff changeset
742 unlink_stmt_vdef (stmt);
kono
parents:
diff changeset
743 gsi_remove (&gsi_orig, true);
kono
parents:
diff changeset
744
kono
parents:
diff changeset
745 /* Point GSI to next logical statement. */
kono
parents:
diff changeset
746 *gsi = gsi_start_bb (fallthru_bb);
kono
parents:
diff changeset
747 return true;
kono
parents:
diff changeset
748 }
kono
parents:
diff changeset
749
kono
parents:
diff changeset
750 /* Expand UBSAN_NULL internal call. The type is kept on the ckind
kono
parents:
diff changeset
751 argument which is a constant, because the middle-end treats pointer
kono
parents:
diff changeset
752 conversions as useless and therefore the type of the first argument
kono
parents:
diff changeset
753 could be changed to any other pointer type. */
kono
parents:
diff changeset
754
kono
parents:
diff changeset
755 bool
kono
parents:
diff changeset
756 ubsan_expand_null_ifn (gimple_stmt_iterator *gsip)
kono
parents:
diff changeset
757 {
kono
parents:
diff changeset
758 gimple_stmt_iterator gsi = *gsip;
kono
parents:
diff changeset
759 gimple *stmt = gsi_stmt (gsi);
kono
parents:
diff changeset
760 location_t loc = gimple_location (stmt);
kono
parents:
diff changeset
761 gcc_assert (gimple_call_num_args (stmt) == 3);
kono
parents:
diff changeset
762 tree ptr = gimple_call_arg (stmt, 0);
kono
parents:
diff changeset
763 tree ckind = gimple_call_arg (stmt, 1);
kono
parents:
diff changeset
764 tree align = gimple_call_arg (stmt, 2);
kono
parents:
diff changeset
765 tree check_align = NULL_TREE;
kono
parents:
diff changeset
766 bool check_null;
kono
parents:
diff changeset
767
kono
parents:
diff changeset
768 basic_block cur_bb = gsi_bb (gsi);
kono
parents:
diff changeset
769
kono
parents:
diff changeset
770 gimple *g;
kono
parents:
diff changeset
771 if (!integer_zerop (align))
kono
parents:
diff changeset
772 {
kono
parents:
diff changeset
773 unsigned int ptralign = get_pointer_alignment (ptr) / BITS_PER_UNIT;
kono
parents:
diff changeset
774 if (compare_tree_int (align, ptralign) == 1)
kono
parents:
diff changeset
775 {
kono
parents:
diff changeset
776 check_align = make_ssa_name (pointer_sized_int_node);
kono
parents:
diff changeset
777 g = gimple_build_assign (check_align, NOP_EXPR, ptr);
kono
parents:
diff changeset
778 gimple_set_location (g, loc);
kono
parents:
diff changeset
779 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
780 }
kono
parents:
diff changeset
781 }
kono
parents:
diff changeset
782 check_null = sanitize_flags_p (SANITIZE_NULL);
kono
parents:
diff changeset
783
kono
parents:
diff changeset
784 if (check_align == NULL_TREE && !check_null)
kono
parents:
diff changeset
785 {
kono
parents:
diff changeset
786 gsi_remove (gsip, true);
kono
parents:
diff changeset
787 /* Unlink the UBSAN_NULLs vops before replacing it. */
kono
parents:
diff changeset
788 unlink_stmt_vdef (stmt);
kono
parents:
diff changeset
789 return true;
kono
parents:
diff changeset
790 }
kono
parents:
diff changeset
791
kono
parents:
diff changeset
792 /* Split the original block holding the pointer dereference. */
kono
parents:
diff changeset
793 edge e = split_block (cur_bb, stmt);
kono
parents:
diff changeset
794
kono
parents:
diff changeset
795 /* Get a hold on the 'condition block', the 'then block' and the
kono
parents:
diff changeset
796 'else block'. */
kono
parents:
diff changeset
797 basic_block cond_bb = e->src;
kono
parents:
diff changeset
798 basic_block fallthru_bb = e->dest;
kono
parents:
diff changeset
799 basic_block then_bb = create_empty_bb (cond_bb);
kono
parents:
diff changeset
800 add_bb_to_loop (then_bb, cond_bb->loop_father);
kono
parents:
diff changeset
801 loops_state_set (LOOPS_NEED_FIXUP);
kono
parents:
diff changeset
802
kono
parents:
diff changeset
803 /* Make an edge coming from the 'cond block' into the 'then block';
kono
parents:
diff changeset
804 this edge is unlikely taken, so set up the probability accordingly. */
kono
parents:
diff changeset
805 e = make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
kono
parents:
diff changeset
806 e->probability = profile_probability::very_unlikely ();
kono
parents:
diff changeset
807
kono
parents:
diff changeset
808 /* Connect 'then block' with the 'else block'. This is needed
kono
parents:
diff changeset
809 as the ubsan routines we call in the 'then block' are not noreturn.
kono
parents:
diff changeset
810 The 'then block' only has one outcoming edge. */
kono
parents:
diff changeset
811 make_single_succ_edge (then_bb, fallthru_bb, EDGE_FALLTHRU);
kono
parents:
diff changeset
812
kono
parents:
diff changeset
813 /* Set up the fallthrough basic block. */
kono
parents:
diff changeset
814 e = find_edge (cond_bb, fallthru_bb);
kono
parents:
diff changeset
815 e->flags = EDGE_FALSE_VALUE;
kono
parents:
diff changeset
816 e->probability = profile_probability::very_likely ();
kono
parents:
diff changeset
817
kono
parents:
diff changeset
818 /* Update dominance info for the newly created then_bb; note that
kono
parents:
diff changeset
819 fallthru_bb's dominance info has already been updated by
kono
parents:
diff changeset
820 split_block. */
kono
parents:
diff changeset
821 if (dom_info_available_p (CDI_DOMINATORS))
kono
parents:
diff changeset
822 set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
kono
parents:
diff changeset
823
kono
parents:
diff changeset
824 /* Put the ubsan builtin call into the newly created BB. */
kono
parents:
diff changeset
825 if (flag_sanitize_undefined_trap_on_error)
kono
parents:
diff changeset
826 g = gimple_build_call (builtin_decl_implicit (BUILT_IN_TRAP), 0);
kono
parents:
diff changeset
827 else
kono
parents:
diff changeset
828 {
kono
parents:
diff changeset
829 enum built_in_function bcode
kono
parents:
diff changeset
830 = (flag_sanitize_recover & ((check_align ? SANITIZE_ALIGNMENT : 0)
kono
parents:
diff changeset
831 | (check_null ? SANITIZE_NULL : 0)))
kono
parents:
diff changeset
832 ? BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1
kono
parents:
diff changeset
833 : BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1_ABORT;
kono
parents:
diff changeset
834 tree fn = builtin_decl_implicit (bcode);
kono
parents:
diff changeset
835 int align_log = tree_log2 (align);
kono
parents:
diff changeset
836 tree data
kono
parents:
diff changeset
837 = ubsan_create_data ("__ubsan_null_data", 1, &loc,
kono
parents:
diff changeset
838 ubsan_type_descriptor (TREE_TYPE (ckind),
kono
parents:
diff changeset
839 UBSAN_PRINT_POINTER),
kono
parents:
diff changeset
840 NULL_TREE,
kono
parents:
diff changeset
841 build_int_cst (unsigned_char_type_node,
kono
parents:
diff changeset
842 MAX (align_log, 0)),
kono
parents:
diff changeset
843 fold_convert (unsigned_char_type_node, ckind),
kono
parents:
diff changeset
844 NULL_TREE);
kono
parents:
diff changeset
845 data = build_fold_addr_expr_loc (loc, data);
kono
parents:
diff changeset
846 g = gimple_build_call (fn, 2, data,
kono
parents:
diff changeset
847 check_align ? check_align
kono
parents:
diff changeset
848 : build_zero_cst (pointer_sized_int_node));
kono
parents:
diff changeset
849 }
kono
parents:
diff changeset
850 gimple_stmt_iterator gsi2 = gsi_start_bb (then_bb);
kono
parents:
diff changeset
851 gimple_set_location (g, loc);
kono
parents:
diff changeset
852 gsi_insert_after (&gsi2, g, GSI_NEW_STMT);
kono
parents:
diff changeset
853
kono
parents:
diff changeset
854 /* Unlink the UBSAN_NULLs vops before replacing it. */
kono
parents:
diff changeset
855 unlink_stmt_vdef (stmt);
kono
parents:
diff changeset
856
kono
parents:
diff changeset
857 if (check_null)
kono
parents:
diff changeset
858 {
kono
parents:
diff changeset
859 g = gimple_build_cond (EQ_EXPR, ptr, build_int_cst (TREE_TYPE (ptr), 0),
kono
parents:
diff changeset
860 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
861 gimple_set_location (g, loc);
kono
parents:
diff changeset
862
kono
parents:
diff changeset
863 /* Replace the UBSAN_NULL with a GIMPLE_COND stmt. */
kono
parents:
diff changeset
864 gsi_replace (&gsi, g, false);
kono
parents:
diff changeset
865 stmt = g;
kono
parents:
diff changeset
866 }
kono
parents:
diff changeset
867
kono
parents:
diff changeset
868 if (check_align)
kono
parents:
diff changeset
869 {
kono
parents:
diff changeset
870 if (check_null)
kono
parents:
diff changeset
871 {
kono
parents:
diff changeset
872 /* Split the block with the condition again. */
kono
parents:
diff changeset
873 e = split_block (cond_bb, stmt);
kono
parents:
diff changeset
874 basic_block cond1_bb = e->src;
kono
parents:
diff changeset
875 basic_block cond2_bb = e->dest;
kono
parents:
diff changeset
876
kono
parents:
diff changeset
877 /* Make an edge coming from the 'cond1 block' into the 'then block';
kono
parents:
diff changeset
878 this edge is unlikely taken, so set up the probability
kono
parents:
diff changeset
879 accordingly. */
kono
parents:
diff changeset
880 e = make_edge (cond1_bb, then_bb, EDGE_TRUE_VALUE);
kono
parents:
diff changeset
881 e->probability = profile_probability::very_unlikely ();
kono
parents:
diff changeset
882
kono
parents:
diff changeset
883 /* Set up the fallthrough basic block. */
kono
parents:
diff changeset
884 e = find_edge (cond1_bb, cond2_bb);
kono
parents:
diff changeset
885 e->flags = EDGE_FALSE_VALUE;
kono
parents:
diff changeset
886 e->probability = profile_probability::very_likely ();
kono
parents:
diff changeset
887
kono
parents:
diff changeset
888 /* Update dominance info. */
kono
parents:
diff changeset
889 if (dom_info_available_p (CDI_DOMINATORS))
kono
parents:
diff changeset
890 {
kono
parents:
diff changeset
891 set_immediate_dominator (CDI_DOMINATORS, fallthru_bb, cond1_bb);
kono
parents:
diff changeset
892 set_immediate_dominator (CDI_DOMINATORS, then_bb, cond1_bb);
kono
parents:
diff changeset
893 }
kono
parents:
diff changeset
894
kono
parents:
diff changeset
895 gsi2 = gsi_start_bb (cond2_bb);
kono
parents:
diff changeset
896 }
kono
parents:
diff changeset
897
kono
parents:
diff changeset
898 tree mask = build_int_cst (pointer_sized_int_node,
kono
parents:
diff changeset
899 tree_to_uhwi (align) - 1);
kono
parents:
diff changeset
900 g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
kono
parents:
diff changeset
901 BIT_AND_EXPR, check_align, mask);
kono
parents:
diff changeset
902 gimple_set_location (g, loc);
kono
parents:
diff changeset
903 if (check_null)
kono
parents:
diff changeset
904 gsi_insert_after (&gsi2, g, GSI_NEW_STMT);
kono
parents:
diff changeset
905 else
kono
parents:
diff changeset
906 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
907
kono
parents:
diff changeset
908 g = gimple_build_cond (NE_EXPR, gimple_assign_lhs (g),
kono
parents:
diff changeset
909 build_int_cst (pointer_sized_int_node, 0),
kono
parents:
diff changeset
910 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
911 gimple_set_location (g, loc);
kono
parents:
diff changeset
912 if (check_null)
kono
parents:
diff changeset
913 gsi_insert_after (&gsi2, g, GSI_NEW_STMT);
kono
parents:
diff changeset
914 else
kono
parents:
diff changeset
915 /* Replace the UBSAN_NULL with a GIMPLE_COND stmt. */
kono
parents:
diff changeset
916 gsi_replace (&gsi, g, false);
kono
parents:
diff changeset
917 }
kono
parents:
diff changeset
918 return false;
kono
parents:
diff changeset
919 }
kono
parents:
diff changeset
920
kono
parents:
diff changeset
921 #define OBJSZ_MAX_OFFSET (1024 * 16)
kono
parents:
diff changeset
922
kono
parents:
diff changeset
923 /* Expand UBSAN_OBJECT_SIZE internal call. */
kono
parents:
diff changeset
924
kono
parents:
diff changeset
925 bool
kono
parents:
diff changeset
926 ubsan_expand_objsize_ifn (gimple_stmt_iterator *gsi)
kono
parents:
diff changeset
927 {
kono
parents:
diff changeset
928 gimple *stmt = gsi_stmt (*gsi);
kono
parents:
diff changeset
929 location_t loc = gimple_location (stmt);
kono
parents:
diff changeset
930 gcc_assert (gimple_call_num_args (stmt) == 4);
kono
parents:
diff changeset
931
kono
parents:
diff changeset
932 tree ptr = gimple_call_arg (stmt, 0);
kono
parents:
diff changeset
933 tree offset = gimple_call_arg (stmt, 1);
kono
parents:
diff changeset
934 tree size = gimple_call_arg (stmt, 2);
kono
parents:
diff changeset
935 tree ckind = gimple_call_arg (stmt, 3);
kono
parents:
diff changeset
936 gimple_stmt_iterator gsi_orig = *gsi;
kono
parents:
diff changeset
937 gimple *g;
kono
parents:
diff changeset
938
kono
parents:
diff changeset
939 /* See if we can discard the check. */
kono
parents:
diff changeset
940 if (TREE_CODE (size) != INTEGER_CST
kono
parents:
diff changeset
941 || integer_all_onesp (size))
kono
parents:
diff changeset
942 /* Yes, __builtin_object_size couldn't determine the
kono
parents:
diff changeset
943 object size. */;
kono
parents:
diff changeset
944 else if (TREE_CODE (offset) == INTEGER_CST
kono
parents:
diff changeset
945 && wi::to_widest (offset) >= -OBJSZ_MAX_OFFSET
kono
parents:
diff changeset
946 && wi::to_widest (offset) <= -1)
kono
parents:
diff changeset
947 /* The offset is in range [-16K, -1]. */;
kono
parents:
diff changeset
948 else
kono
parents:
diff changeset
949 {
kono
parents:
diff changeset
950 /* if (offset > objsize) */
kono
parents:
diff changeset
951 basic_block then_bb, fallthru_bb;
kono
parents:
diff changeset
952 gimple_stmt_iterator cond_insert_point
kono
parents:
diff changeset
953 = create_cond_insert_point (gsi, false, false, true,
kono
parents:
diff changeset
954 &then_bb, &fallthru_bb);
kono
parents:
diff changeset
955 g = gimple_build_cond (GT_EXPR, offset, size, NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
956 gimple_set_location (g, loc);
kono
parents:
diff changeset
957 gsi_insert_after (&cond_insert_point, g, GSI_NEW_STMT);
kono
parents:
diff changeset
958
kono
parents:
diff changeset
959 /* If the offset is small enough, we don't need the second
kono
parents:
diff changeset
960 run-time check. */
kono
parents:
diff changeset
961 if (TREE_CODE (offset) == INTEGER_CST
kono
parents:
diff changeset
962 && wi::to_widest (offset) >= 0
kono
parents:
diff changeset
963 && wi::to_widest (offset) <= OBJSZ_MAX_OFFSET)
kono
parents:
diff changeset
964 *gsi = gsi_after_labels (then_bb);
kono
parents:
diff changeset
965 else
kono
parents:
diff changeset
966 {
kono
parents:
diff changeset
967 /* Don't issue run-time error if (ptr > ptr + offset). That
kono
parents:
diff changeset
968 may happen when computing a POINTER_PLUS_EXPR. */
kono
parents:
diff changeset
969 basic_block then2_bb, fallthru2_bb;
kono
parents:
diff changeset
970
kono
parents:
diff changeset
971 gimple_stmt_iterator gsi2 = gsi_after_labels (then_bb);
kono
parents:
diff changeset
972 cond_insert_point = create_cond_insert_point (&gsi2, false, false,
kono
parents:
diff changeset
973 true, &then2_bb,
kono
parents:
diff changeset
974 &fallthru2_bb);
kono
parents:
diff changeset
975 /* Convert the pointer to an integer type. */
kono
parents:
diff changeset
976 tree p = make_ssa_name (pointer_sized_int_node);
kono
parents:
diff changeset
977 g = gimple_build_assign (p, NOP_EXPR, ptr);
kono
parents:
diff changeset
978 gimple_set_location (g, loc);
kono
parents:
diff changeset
979 gsi_insert_before (&cond_insert_point, g, GSI_NEW_STMT);
kono
parents:
diff changeset
980 p = gimple_assign_lhs (g);
kono
parents:
diff changeset
981 /* Compute ptr + offset. */
kono
parents:
diff changeset
982 g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
kono
parents:
diff changeset
983 PLUS_EXPR, p, offset);
kono
parents:
diff changeset
984 gimple_set_location (g, loc);
kono
parents:
diff changeset
985 gsi_insert_after (&cond_insert_point, g, GSI_NEW_STMT);
kono
parents:
diff changeset
986 /* Now build the conditional and put it into the IR. */
kono
parents:
diff changeset
987 g = gimple_build_cond (LE_EXPR, p, gimple_assign_lhs (g),
kono
parents:
diff changeset
988 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
989 gimple_set_location (g, loc);
kono
parents:
diff changeset
990 gsi_insert_after (&cond_insert_point, g, GSI_NEW_STMT);
kono
parents:
diff changeset
991 *gsi = gsi_after_labels (then2_bb);
kono
parents:
diff changeset
992 }
kono
parents:
diff changeset
993
kono
parents:
diff changeset
994 /* Generate __ubsan_handle_type_mismatch call. */
kono
parents:
diff changeset
995 if (flag_sanitize_undefined_trap_on_error)
kono
parents:
diff changeset
996 g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
kono
parents:
diff changeset
997 else
kono
parents:
diff changeset
998 {
kono
parents:
diff changeset
999 tree data
kono
parents:
diff changeset
1000 = ubsan_create_data ("__ubsan_objsz_data", 1, &loc,
kono
parents:
diff changeset
1001 ubsan_type_descriptor (TREE_TYPE (ptr),
kono
parents:
diff changeset
1002 UBSAN_PRINT_POINTER),
kono
parents:
diff changeset
1003 NULL_TREE,
kono
parents:
diff changeset
1004 build_zero_cst (unsigned_char_type_node),
kono
parents:
diff changeset
1005 ckind,
kono
parents:
diff changeset
1006 NULL_TREE);
kono
parents:
diff changeset
1007 data = build_fold_addr_expr_loc (loc, data);
kono
parents:
diff changeset
1008 enum built_in_function bcode
kono
parents:
diff changeset
1009 = (flag_sanitize_recover & SANITIZE_OBJECT_SIZE)
kono
parents:
diff changeset
1010 ? BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1
kono
parents:
diff changeset
1011 : BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1_ABORT;
kono
parents:
diff changeset
1012 tree p = make_ssa_name (pointer_sized_int_node);
kono
parents:
diff changeset
1013 g = gimple_build_assign (p, NOP_EXPR, ptr);
kono
parents:
diff changeset
1014 gimple_set_location (g, loc);
kono
parents:
diff changeset
1015 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1016 g = gimple_build_call (builtin_decl_explicit (bcode), 2, data, p);
kono
parents:
diff changeset
1017 }
kono
parents:
diff changeset
1018 gimple_set_location (g, loc);
kono
parents:
diff changeset
1019 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1020
kono
parents:
diff changeset
1021 /* Point GSI to next logical statement. */
kono
parents:
diff changeset
1022 *gsi = gsi_start_bb (fallthru_bb);
kono
parents:
diff changeset
1023
kono
parents:
diff changeset
1024 /* Get rid of the UBSAN_OBJECT_SIZE call from the IR. */
kono
parents:
diff changeset
1025 unlink_stmt_vdef (stmt);
kono
parents:
diff changeset
1026 gsi_remove (&gsi_orig, true);
kono
parents:
diff changeset
1027 return true;
kono
parents:
diff changeset
1028 }
kono
parents:
diff changeset
1029
kono
parents:
diff changeset
1030 /* Get rid of the UBSAN_OBJECT_SIZE call from the IR. */
kono
parents:
diff changeset
1031 unlink_stmt_vdef (stmt);
kono
parents:
diff changeset
1032 gsi_remove (gsi, true);
kono
parents:
diff changeset
1033 return true;
kono
parents:
diff changeset
1034 }
kono
parents:
diff changeset
1035
kono
parents:
diff changeset
1036 /* Expand UBSAN_PTR internal call. */
kono
parents:
diff changeset
1037
kono
parents:
diff changeset
1038 bool
kono
parents:
diff changeset
1039 ubsan_expand_ptr_ifn (gimple_stmt_iterator *gsip)
kono
parents:
diff changeset
1040 {
kono
parents:
diff changeset
1041 gimple_stmt_iterator gsi = *gsip;
kono
parents:
diff changeset
1042 gimple *stmt = gsi_stmt (gsi);
kono
parents:
diff changeset
1043 location_t loc = gimple_location (stmt);
kono
parents:
diff changeset
1044 gcc_assert (gimple_call_num_args (stmt) == 2);
kono
parents:
diff changeset
1045 tree ptr = gimple_call_arg (stmt, 0);
kono
parents:
diff changeset
1046 tree off = gimple_call_arg (stmt, 1);
kono
parents:
diff changeset
1047
kono
parents:
diff changeset
1048 if (integer_zerop (off))
kono
parents:
diff changeset
1049 {
kono
parents:
diff changeset
1050 gsi_remove (gsip, true);
kono
parents:
diff changeset
1051 unlink_stmt_vdef (stmt);
kono
parents:
diff changeset
1052 return true;
kono
parents:
diff changeset
1053 }
kono
parents:
diff changeset
1054
kono
parents:
diff changeset
1055 basic_block cur_bb = gsi_bb (gsi);
kono
parents:
diff changeset
1056 tree ptrplusoff = make_ssa_name (pointer_sized_int_node);
kono
parents:
diff changeset
1057 tree ptri = make_ssa_name (pointer_sized_int_node);
kono
parents:
diff changeset
1058 int pos_neg = get_range_pos_neg (off);
kono
parents:
diff changeset
1059
kono
parents:
diff changeset
1060 /* Split the original block holding the pointer dereference. */
kono
parents:
diff changeset
1061 edge e = split_block (cur_bb, stmt);
kono
parents:
diff changeset
1062
kono
parents:
diff changeset
1063 /* Get a hold on the 'condition block', the 'then block' and the
kono
parents:
diff changeset
1064 'else block'. */
kono
parents:
diff changeset
1065 basic_block cond_bb = e->src;
kono
parents:
diff changeset
1066 basic_block fallthru_bb = e->dest;
kono
parents:
diff changeset
1067 basic_block then_bb = create_empty_bb (cond_bb);
kono
parents:
diff changeset
1068 basic_block cond_pos_bb = NULL, cond_neg_bb = NULL;
kono
parents:
diff changeset
1069 add_bb_to_loop (then_bb, cond_bb->loop_father);
kono
parents:
diff changeset
1070 loops_state_set (LOOPS_NEED_FIXUP);
kono
parents:
diff changeset
1071
kono
parents:
diff changeset
1072 /* Set up the fallthrough basic block. */
kono
parents:
diff changeset
1073 e->flags = EDGE_FALSE_VALUE;
kono
parents:
diff changeset
1074 if (pos_neg != 3)
kono
parents:
diff changeset
1075 {
kono
parents:
diff changeset
1076 e->probability = profile_probability::very_likely ();
kono
parents:
diff changeset
1077
kono
parents:
diff changeset
1078 /* Connect 'then block' with the 'else block'. This is needed
kono
parents:
diff changeset
1079 as the ubsan routines we call in the 'then block' are not noreturn.
kono
parents:
diff changeset
1080 The 'then block' only has one outcoming edge. */
kono
parents:
diff changeset
1081 make_single_succ_edge (then_bb, fallthru_bb, EDGE_FALLTHRU);
kono
parents:
diff changeset
1082
kono
parents:
diff changeset
1083 /* Make an edge coming from the 'cond block' into the 'then block';
kono
parents:
diff changeset
1084 this edge is unlikely taken, so set up the probability
kono
parents:
diff changeset
1085 accordingly. */
kono
parents:
diff changeset
1086 e = make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
kono
parents:
diff changeset
1087 e->probability = profile_probability::very_unlikely ();
kono
parents:
diff changeset
1088 }
kono
parents:
diff changeset
1089 else
kono
parents:
diff changeset
1090 {
kono
parents:
diff changeset
1091 e->probability = profile_probability::even ();
kono
parents:
diff changeset
1092
kono
parents:
diff changeset
1093 e = split_block (fallthru_bb, (gimple *) NULL);
kono
parents:
diff changeset
1094 cond_neg_bb = e->src;
kono
parents:
diff changeset
1095 fallthru_bb = e->dest;
kono
parents:
diff changeset
1096 e->probability = profile_probability::very_likely ();
kono
parents:
diff changeset
1097 e->flags = EDGE_FALSE_VALUE;
kono
parents:
diff changeset
1098
kono
parents:
diff changeset
1099 e = make_edge (cond_neg_bb, then_bb, EDGE_TRUE_VALUE);
kono
parents:
diff changeset
1100 e->probability = profile_probability::very_unlikely ();
kono
parents:
diff changeset
1101
kono
parents:
diff changeset
1102 cond_pos_bb = create_empty_bb (cond_bb);
kono
parents:
diff changeset
1103 add_bb_to_loop (cond_pos_bb, cond_bb->loop_father);
kono
parents:
diff changeset
1104
kono
parents:
diff changeset
1105 e = make_edge (cond_bb, cond_pos_bb, EDGE_TRUE_VALUE);
kono
parents:
diff changeset
1106 e->probability = profile_probability::even ();
kono
parents:
diff changeset
1107
kono
parents:
diff changeset
1108 e = make_edge (cond_pos_bb, then_bb, EDGE_TRUE_VALUE);
kono
parents:
diff changeset
1109 e->probability = profile_probability::very_unlikely ();
kono
parents:
diff changeset
1110
kono
parents:
diff changeset
1111 e = make_edge (cond_pos_bb, fallthru_bb, EDGE_FALSE_VALUE);
kono
parents:
diff changeset
1112 e->probability = profile_probability::very_likely ();
kono
parents:
diff changeset
1113
kono
parents:
diff changeset
1114 make_single_succ_edge (then_bb, fallthru_bb, EDGE_FALLTHRU);
kono
parents:
diff changeset
1115 }
kono
parents:
diff changeset
1116
kono
parents:
diff changeset
1117 gimple *g = gimple_build_assign (ptri, NOP_EXPR, ptr);
kono
parents:
diff changeset
1118 gimple_set_location (g, loc);
kono
parents:
diff changeset
1119 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1120 g = gimple_build_assign (ptrplusoff, PLUS_EXPR, ptri, off);
kono
parents:
diff changeset
1121 gimple_set_location (g, loc);
kono
parents:
diff changeset
1122 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1123
kono
parents:
diff changeset
1124 /* Update dominance info for the newly created then_bb; note that
kono
parents:
diff changeset
1125 fallthru_bb's dominance info has already been updated by
kono
parents:
diff changeset
1126 split_block. */
kono
parents:
diff changeset
1127 if (dom_info_available_p (CDI_DOMINATORS))
kono
parents:
diff changeset
1128 {
kono
parents:
diff changeset
1129 set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
kono
parents:
diff changeset
1130 if (pos_neg == 3)
kono
parents:
diff changeset
1131 {
kono
parents:
diff changeset
1132 set_immediate_dominator (CDI_DOMINATORS, cond_pos_bb, cond_bb);
kono
parents:
diff changeset
1133 set_immediate_dominator (CDI_DOMINATORS, fallthru_bb, cond_bb);
kono
parents:
diff changeset
1134 }
kono
parents:
diff changeset
1135 }
kono
parents:
diff changeset
1136
kono
parents:
diff changeset
1137 /* Put the ubsan builtin call into the newly created BB. */
kono
parents:
diff changeset
1138 if (flag_sanitize_undefined_trap_on_error)
kono
parents:
diff changeset
1139 g = gimple_build_call (builtin_decl_implicit (BUILT_IN_TRAP), 0);
kono
parents:
diff changeset
1140 else
kono
parents:
diff changeset
1141 {
kono
parents:
diff changeset
1142 enum built_in_function bcode
kono
parents:
diff changeset
1143 = (flag_sanitize_recover & SANITIZE_POINTER_OVERFLOW)
kono
parents:
diff changeset
1144 ? BUILT_IN_UBSAN_HANDLE_POINTER_OVERFLOW
kono
parents:
diff changeset
1145 : BUILT_IN_UBSAN_HANDLE_POINTER_OVERFLOW_ABORT;
kono
parents:
diff changeset
1146 tree fn = builtin_decl_implicit (bcode);
kono
parents:
diff changeset
1147 tree data
kono
parents:
diff changeset
1148 = ubsan_create_data ("__ubsan_ptrovf_data", 1, &loc,
kono
parents:
diff changeset
1149 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
1150 data = build_fold_addr_expr_loc (loc, data);
kono
parents:
diff changeset
1151 g = gimple_build_call (fn, 3, data, ptr, ptrplusoff);
kono
parents:
diff changeset
1152 }
kono
parents:
diff changeset
1153 gimple_stmt_iterator gsi2 = gsi_start_bb (then_bb);
kono
parents:
diff changeset
1154 gimple_set_location (g, loc);
kono
parents:
diff changeset
1155 gsi_insert_after (&gsi2, g, GSI_NEW_STMT);
kono
parents:
diff changeset
1156
kono
parents:
diff changeset
1157 /* Unlink the UBSAN_PTRs vops before replacing it. */
kono
parents:
diff changeset
1158 unlink_stmt_vdef (stmt);
kono
parents:
diff changeset
1159
kono
parents:
diff changeset
1160 if (TREE_CODE (off) == INTEGER_CST)
kono
parents:
diff changeset
1161 g = gimple_build_cond (wi::neg_p (wi::to_wide (off)) ? LT_EXPR : GE_EXPR,
kono
parents:
diff changeset
1162 ptri, fold_build1 (NEGATE_EXPR, sizetype, off),
kono
parents:
diff changeset
1163 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
1164 else if (pos_neg != 3)
kono
parents:
diff changeset
1165 g = gimple_build_cond (pos_neg == 1 ? LT_EXPR : GT_EXPR,
kono
parents:
diff changeset
1166 ptrplusoff, ptri, NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
1167 else
kono
parents:
diff changeset
1168 {
kono
parents:
diff changeset
1169 gsi2 = gsi_start_bb (cond_pos_bb);
kono
parents:
diff changeset
1170 g = gimple_build_cond (LT_EXPR, ptrplusoff, ptri, NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
1171 gimple_set_location (g, loc);
kono
parents:
diff changeset
1172 gsi_insert_after (&gsi2, g, GSI_NEW_STMT);
kono
parents:
diff changeset
1173
kono
parents:
diff changeset
1174 gsi2 = gsi_start_bb (cond_neg_bb);
kono
parents:
diff changeset
1175 g = gimple_build_cond (GT_EXPR, ptrplusoff, ptri, NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
1176 gimple_set_location (g, loc);
kono
parents:
diff changeset
1177 gsi_insert_after (&gsi2, g, GSI_NEW_STMT);
kono
parents:
diff changeset
1178
kono
parents:
diff changeset
1179 gimple_seq seq = NULL;
kono
parents:
diff changeset
1180 tree t = gimple_build (&seq, loc, NOP_EXPR, ssizetype, off);
kono
parents:
diff changeset
1181 t = gimple_build (&seq, loc, GE_EXPR, boolean_type_node,
kono
parents:
diff changeset
1182 t, ssize_int (0));
kono
parents:
diff changeset
1183 gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT);
kono
parents:
diff changeset
1184 g = gimple_build_cond (NE_EXPR, t, boolean_false_node,
kono
parents:
diff changeset
1185 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
1186 }
kono
parents:
diff changeset
1187 gimple_set_location (g, loc);
kono
parents:
diff changeset
1188 /* Replace the UBSAN_PTR with a GIMPLE_COND stmt. */
kono
parents:
diff changeset
1189 gsi_replace (&gsi, g, false);
kono
parents:
diff changeset
1190 return false;
kono
parents:
diff changeset
1191 }
kono
parents:
diff changeset
1192
kono
parents:
diff changeset
1193
kono
parents:
diff changeset
1194 /* Cached __ubsan_vptr_type_cache decl. */
kono
parents:
diff changeset
1195 static GTY(()) tree ubsan_vptr_type_cache_decl;
kono
parents:
diff changeset
1196
kono
parents:
diff changeset
1197 /* Expand UBSAN_VPTR internal call. The type is kept on the ckind
kono
parents:
diff changeset
1198 argument which is a constant, because the middle-end treats pointer
kono
parents:
diff changeset
1199 conversions as useless and therefore the type of the first argument
kono
parents:
diff changeset
1200 could be changed to any other pointer type. */
kono
parents:
diff changeset
1201
kono
parents:
diff changeset
1202 bool
kono
parents:
diff changeset
1203 ubsan_expand_vptr_ifn (gimple_stmt_iterator *gsip)
kono
parents:
diff changeset
1204 {
kono
parents:
diff changeset
1205 gimple_stmt_iterator gsi = *gsip;
kono
parents:
diff changeset
1206 gimple *stmt = gsi_stmt (gsi);
kono
parents:
diff changeset
1207 location_t loc = gimple_location (stmt);
kono
parents:
diff changeset
1208 gcc_assert (gimple_call_num_args (stmt) == 5);
kono
parents:
diff changeset
1209 tree op = gimple_call_arg (stmt, 0);
kono
parents:
diff changeset
1210 tree vptr = gimple_call_arg (stmt, 1);
kono
parents:
diff changeset
1211 tree str_hash = gimple_call_arg (stmt, 2);
kono
parents:
diff changeset
1212 tree ti_decl_addr = gimple_call_arg (stmt, 3);
kono
parents:
diff changeset
1213 tree ckind_tree = gimple_call_arg (stmt, 4);
kono
parents:
diff changeset
1214 ubsan_null_ckind ckind = (ubsan_null_ckind) tree_to_uhwi (ckind_tree);
kono
parents:
diff changeset
1215 tree type = TREE_TYPE (TREE_TYPE (ckind_tree));
kono
parents:
diff changeset
1216 gimple *g;
kono
parents:
diff changeset
1217 basic_block fallthru_bb = NULL;
kono
parents:
diff changeset
1218
kono
parents:
diff changeset
1219 if (ckind == UBSAN_DOWNCAST_POINTER)
kono
parents:
diff changeset
1220 {
kono
parents:
diff changeset
1221 /* Guard everything with if (op != NULL) { ... }. */
kono
parents:
diff changeset
1222 basic_block then_bb;
kono
parents:
diff changeset
1223 gimple_stmt_iterator cond_insert_point
kono
parents:
diff changeset
1224 = create_cond_insert_point (gsip, false, false, true,
kono
parents:
diff changeset
1225 &then_bb, &fallthru_bb);
kono
parents:
diff changeset
1226 g = gimple_build_cond (NE_EXPR, op, build_zero_cst (TREE_TYPE (op)),
kono
parents:
diff changeset
1227 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
1228 gimple_set_location (g, loc);
kono
parents:
diff changeset
1229 gsi_insert_after (&cond_insert_point, g, GSI_NEW_STMT);
kono
parents:
diff changeset
1230 *gsip = gsi_after_labels (then_bb);
kono
parents:
diff changeset
1231 gsi_remove (&gsi, false);
kono
parents:
diff changeset
1232 gsi_insert_before (gsip, stmt, GSI_NEW_STMT);
kono
parents:
diff changeset
1233 gsi = *gsip;
kono
parents:
diff changeset
1234 }
kono
parents:
diff changeset
1235
kono
parents:
diff changeset
1236 tree htype = TREE_TYPE (str_hash);
kono
parents:
diff changeset
1237 tree cst = wide_int_to_tree (htype,
kono
parents:
diff changeset
1238 wi::uhwi (((uint64_t) 0x9ddfea08 << 32)
kono
parents:
diff changeset
1239 | 0xeb382d69, 64));
kono
parents:
diff changeset
1240 g = gimple_build_assign (make_ssa_name (htype), BIT_XOR_EXPR,
kono
parents:
diff changeset
1241 vptr, str_hash);
kono
parents:
diff changeset
1242 gimple_set_location (g, loc);
kono
parents:
diff changeset
1243 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1244 g = gimple_build_assign (make_ssa_name (htype), MULT_EXPR,
kono
parents:
diff changeset
1245 gimple_assign_lhs (g), cst);
kono
parents:
diff changeset
1246 gimple_set_location (g, loc);
kono
parents:
diff changeset
1247 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1248 tree t1 = gimple_assign_lhs (g);
kono
parents:
diff changeset
1249 g = gimple_build_assign (make_ssa_name (htype), LSHIFT_EXPR,
kono
parents:
diff changeset
1250 t1, build_int_cst (integer_type_node, 47));
kono
parents:
diff changeset
1251 gimple_set_location (g, loc);
kono
parents:
diff changeset
1252 tree t2 = gimple_assign_lhs (g);
kono
parents:
diff changeset
1253 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1254 g = gimple_build_assign (make_ssa_name (htype), BIT_XOR_EXPR,
kono
parents:
diff changeset
1255 vptr, t1);
kono
parents:
diff changeset
1256 gimple_set_location (g, loc);
kono
parents:
diff changeset
1257 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1258 g = gimple_build_assign (make_ssa_name (htype), BIT_XOR_EXPR,
kono
parents:
diff changeset
1259 t2, gimple_assign_lhs (g));
kono
parents:
diff changeset
1260 gimple_set_location (g, loc);
kono
parents:
diff changeset
1261 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1262 g = gimple_build_assign (make_ssa_name (htype), MULT_EXPR,
kono
parents:
diff changeset
1263 gimple_assign_lhs (g), cst);
kono
parents:
diff changeset
1264 gimple_set_location (g, loc);
kono
parents:
diff changeset
1265 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1266 tree t3 = gimple_assign_lhs (g);
kono
parents:
diff changeset
1267 g = gimple_build_assign (make_ssa_name (htype), LSHIFT_EXPR,
kono
parents:
diff changeset
1268 t3, build_int_cst (integer_type_node, 47));
kono
parents:
diff changeset
1269 gimple_set_location (g, loc);
kono
parents:
diff changeset
1270 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1271 g = gimple_build_assign (make_ssa_name (htype), BIT_XOR_EXPR,
kono
parents:
diff changeset
1272 t3, gimple_assign_lhs (g));
kono
parents:
diff changeset
1273 gimple_set_location (g, loc);
kono
parents:
diff changeset
1274 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1275 g = gimple_build_assign (make_ssa_name (htype), MULT_EXPR,
kono
parents:
diff changeset
1276 gimple_assign_lhs (g), cst);
kono
parents:
diff changeset
1277 gimple_set_location (g, loc);
kono
parents:
diff changeset
1278 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1279 if (!useless_type_conversion_p (pointer_sized_int_node, htype))
kono
parents:
diff changeset
1280 {
kono
parents:
diff changeset
1281 g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
kono
parents:
diff changeset
1282 NOP_EXPR, gimple_assign_lhs (g));
kono
parents:
diff changeset
1283 gimple_set_location (g, loc);
kono
parents:
diff changeset
1284 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1285 }
kono
parents:
diff changeset
1286 tree hash = gimple_assign_lhs (g);
kono
parents:
diff changeset
1287
kono
parents:
diff changeset
1288 if (ubsan_vptr_type_cache_decl == NULL_TREE)
kono
parents:
diff changeset
1289 {
kono
parents:
diff changeset
1290 tree atype = build_array_type_nelts (pointer_sized_int_node, 128);
kono
parents:
diff changeset
1291 tree array = build_decl (UNKNOWN_LOCATION, VAR_DECL,
kono
parents:
diff changeset
1292 get_identifier ("__ubsan_vptr_type_cache"),
kono
parents:
diff changeset
1293 atype);
kono
parents:
diff changeset
1294 DECL_ARTIFICIAL (array) = 1;
kono
parents:
diff changeset
1295 DECL_IGNORED_P (array) = 1;
kono
parents:
diff changeset
1296 TREE_PUBLIC (array) = 1;
kono
parents:
diff changeset
1297 TREE_STATIC (array) = 1;
kono
parents:
diff changeset
1298 DECL_EXTERNAL (array) = 1;
kono
parents:
diff changeset
1299 DECL_VISIBILITY (array) = VISIBILITY_DEFAULT;
kono
parents:
diff changeset
1300 DECL_VISIBILITY_SPECIFIED (array) = 1;
kono
parents:
diff changeset
1301 varpool_node::finalize_decl (array);
kono
parents:
diff changeset
1302 ubsan_vptr_type_cache_decl = array;
kono
parents:
diff changeset
1303 }
kono
parents:
diff changeset
1304
kono
parents:
diff changeset
1305 g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
kono
parents:
diff changeset
1306 BIT_AND_EXPR, hash,
kono
parents:
diff changeset
1307 build_int_cst (pointer_sized_int_node, 127));
kono
parents:
diff changeset
1308 gimple_set_location (g, loc);
kono
parents:
diff changeset
1309 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1310
kono
parents:
diff changeset
1311 tree c = build4_loc (loc, ARRAY_REF, pointer_sized_int_node,
kono
parents:
diff changeset
1312 ubsan_vptr_type_cache_decl, gimple_assign_lhs (g),
kono
parents:
diff changeset
1313 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
1314 g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
kono
parents:
diff changeset
1315 ARRAY_REF, c);
kono
parents:
diff changeset
1316 gimple_set_location (g, loc);
kono
parents:
diff changeset
1317 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1318
kono
parents:
diff changeset
1319 basic_block then_bb, fallthru2_bb;
kono
parents:
diff changeset
1320 gimple_stmt_iterator cond_insert_point
kono
parents:
diff changeset
1321 = create_cond_insert_point (gsip, false, false, true,
kono
parents:
diff changeset
1322 &then_bb, &fallthru2_bb);
kono
parents:
diff changeset
1323 g = gimple_build_cond (NE_EXPR, gimple_assign_lhs (g), hash,
kono
parents:
diff changeset
1324 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
1325 gimple_set_location (g, loc);
kono
parents:
diff changeset
1326 gsi_insert_after (&cond_insert_point, g, GSI_NEW_STMT);
kono
parents:
diff changeset
1327 *gsip = gsi_after_labels (then_bb);
kono
parents:
diff changeset
1328 if (fallthru_bb == NULL)
kono
parents:
diff changeset
1329 fallthru_bb = fallthru2_bb;
kono
parents:
diff changeset
1330
kono
parents:
diff changeset
1331 tree data
kono
parents:
diff changeset
1332 = ubsan_create_data ("__ubsan_vptr_data", 1, &loc,
kono
parents:
diff changeset
1333 ubsan_type_descriptor (type), NULL_TREE, ti_decl_addr,
kono
parents:
diff changeset
1334 build_int_cst (unsigned_char_type_node, ckind),
kono
parents:
diff changeset
1335 NULL_TREE);
kono
parents:
diff changeset
1336 data = build_fold_addr_expr_loc (loc, data);
kono
parents:
diff changeset
1337 enum built_in_function bcode
kono
parents:
diff changeset
1338 = (flag_sanitize_recover & SANITIZE_VPTR)
kono
parents:
diff changeset
1339 ? BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS
kono
parents:
diff changeset
1340 : BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS_ABORT;
kono
parents:
diff changeset
1341
kono
parents:
diff changeset
1342 g = gimple_build_call (builtin_decl_explicit (bcode), 3, data, op, hash);
kono
parents:
diff changeset
1343 gimple_set_location (g, loc);
kono
parents:
diff changeset
1344 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1345
kono
parents:
diff changeset
1346 /* Point GSI to next logical statement. */
kono
parents:
diff changeset
1347 *gsip = gsi_start_bb (fallthru_bb);
kono
parents:
diff changeset
1348
kono
parents:
diff changeset
1349 /* Get rid of the UBSAN_VPTR call from the IR. */
kono
parents:
diff changeset
1350 unlink_stmt_vdef (stmt);
kono
parents:
diff changeset
1351 gsi_remove (&gsi, true);
kono
parents:
diff changeset
1352 return true;
kono
parents:
diff changeset
1353 }
kono
parents:
diff changeset
1354
kono
parents:
diff changeset
1355 /* Instrument a memory reference. BASE is the base of MEM, IS_LHS says
kono
parents:
diff changeset
1356 whether the pointer is on the left hand side of the assignment. */
kono
parents:
diff changeset
1357
kono
parents:
diff changeset
1358 static void
kono
parents:
diff changeset
1359 instrument_mem_ref (tree mem, tree base, gimple_stmt_iterator *iter,
kono
parents:
diff changeset
1360 bool is_lhs)
kono
parents:
diff changeset
1361 {
kono
parents:
diff changeset
1362 enum ubsan_null_ckind ikind = is_lhs ? UBSAN_STORE_OF : UBSAN_LOAD_OF;
kono
parents:
diff changeset
1363 unsigned int align = 0;
kono
parents:
diff changeset
1364 if (sanitize_flags_p (SANITIZE_ALIGNMENT))
kono
parents:
diff changeset
1365 {
kono
parents:
diff changeset
1366 align = min_align_of_type (TREE_TYPE (base));
kono
parents:
diff changeset
1367 if (align <= 1)
kono
parents:
diff changeset
1368 align = 0;
kono
parents:
diff changeset
1369 }
kono
parents:
diff changeset
1370 if (align == 0 && !sanitize_flags_p (SANITIZE_NULL))
kono
parents:
diff changeset
1371 return;
kono
parents:
diff changeset
1372 tree t = TREE_OPERAND (base, 0);
kono
parents:
diff changeset
1373 if (!POINTER_TYPE_P (TREE_TYPE (t)))
kono
parents:
diff changeset
1374 return;
kono
parents:
diff changeset
1375 if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (base)) && mem != base)
kono
parents:
diff changeset
1376 ikind = UBSAN_MEMBER_ACCESS;
kono
parents:
diff changeset
1377 tree kind = build_int_cst (build_pointer_type (TREE_TYPE (base)), ikind);
kono
parents:
diff changeset
1378 tree alignt = build_int_cst (pointer_sized_int_node, align);
kono
parents:
diff changeset
1379 gcall *g = gimple_build_call_internal (IFN_UBSAN_NULL, 3, t, kind, alignt);
kono
parents:
diff changeset
1380 gimple_set_location (g, gimple_location (gsi_stmt (*iter)));
kono
parents:
diff changeset
1381 gsi_insert_before (iter, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1382 }
kono
parents:
diff changeset
1383
kono
parents:
diff changeset
1384 /* Perform the pointer instrumentation. */
kono
parents:
diff changeset
1385
kono
parents:
diff changeset
1386 static void
kono
parents:
diff changeset
1387 instrument_null (gimple_stmt_iterator gsi, tree t, bool is_lhs)
kono
parents:
diff changeset
1388 {
kono
parents:
diff changeset
1389 /* Handle also e.g. &s->i. */
kono
parents:
diff changeset
1390 if (TREE_CODE (t) == ADDR_EXPR)
kono
parents:
diff changeset
1391 t = TREE_OPERAND (t, 0);
kono
parents:
diff changeset
1392 tree base = get_base_address (t);
kono
parents:
diff changeset
1393 if (base != NULL_TREE
kono
parents:
diff changeset
1394 && TREE_CODE (base) == MEM_REF
kono
parents:
diff changeset
1395 && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
kono
parents:
diff changeset
1396 instrument_mem_ref (t, base, &gsi, is_lhs);
kono
parents:
diff changeset
1397 }
kono
parents:
diff changeset
1398
kono
parents:
diff changeset
1399 /* Instrument pointer arithmetics PTR p+ OFF. */
kono
parents:
diff changeset
1400
kono
parents:
diff changeset
1401 static void
kono
parents:
diff changeset
1402 instrument_pointer_overflow (gimple_stmt_iterator *gsi, tree ptr, tree off)
kono
parents:
diff changeset
1403 {
kono
parents:
diff changeset
1404 if (TYPE_PRECISION (sizetype) != POINTER_SIZE)
kono
parents:
diff changeset
1405 return;
kono
parents:
diff changeset
1406 gcall *g = gimple_build_call_internal (IFN_UBSAN_PTR, 2, ptr, off);
kono
parents:
diff changeset
1407 gimple_set_location (g, gimple_location (gsi_stmt (*gsi)));
kono
parents:
diff changeset
1408 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1409 }
kono
parents:
diff changeset
1410
kono
parents:
diff changeset
1411 /* Instrument pointer arithmetics if any. */
kono
parents:
diff changeset
1412
kono
parents:
diff changeset
1413 static void
kono
parents:
diff changeset
1414 maybe_instrument_pointer_overflow (gimple_stmt_iterator *gsi, tree t)
kono
parents:
diff changeset
1415 {
kono
parents:
diff changeset
1416 if (TYPE_PRECISION (sizetype) != POINTER_SIZE)
kono
parents:
diff changeset
1417 return;
kono
parents:
diff changeset
1418
kono
parents:
diff changeset
1419 /* Handle also e.g. &s->i. */
kono
parents:
diff changeset
1420 if (TREE_CODE (t) == ADDR_EXPR)
kono
parents:
diff changeset
1421 t = TREE_OPERAND (t, 0);
kono
parents:
diff changeset
1422
kono
parents:
diff changeset
1423 if (!handled_component_p (t) && TREE_CODE (t) != MEM_REF)
kono
parents:
diff changeset
1424 return;
kono
parents:
diff changeset
1425
kono
parents:
diff changeset
1426 HOST_WIDE_INT bitsize, bitpos, bytepos;
kono
parents:
diff changeset
1427 tree offset;
kono
parents:
diff changeset
1428 machine_mode mode;
kono
parents:
diff changeset
1429 int volatilep = 0, reversep, unsignedp = 0;
kono
parents:
diff changeset
1430 tree inner = get_inner_reference (t, &bitsize, &bitpos, &offset, &mode,
kono
parents:
diff changeset
1431 &unsignedp, &reversep, &volatilep);
kono
parents:
diff changeset
1432 tree moff = NULL_TREE;
kono
parents:
diff changeset
1433
kono
parents:
diff changeset
1434 bool decl_p = DECL_P (inner);
kono
parents:
diff changeset
1435 tree base;
kono
parents:
diff changeset
1436 if (decl_p)
kono
parents:
diff changeset
1437 {
kono
parents:
diff changeset
1438 if (DECL_REGISTER (inner))
kono
parents:
diff changeset
1439 return;
kono
parents:
diff changeset
1440 base = inner;
kono
parents:
diff changeset
1441 /* If BASE is a fixed size automatic variable or
kono
parents:
diff changeset
1442 global variable defined in the current TU and bitpos
kono
parents:
diff changeset
1443 fits, don't instrument anything. */
kono
parents:
diff changeset
1444 if (offset == NULL_TREE
kono
parents:
diff changeset
1445 && bitpos > 0
kono
parents:
diff changeset
1446 && (VAR_P (base)
kono
parents:
diff changeset
1447 || TREE_CODE (base) == PARM_DECL
kono
parents:
diff changeset
1448 || TREE_CODE (base) == RESULT_DECL)
kono
parents:
diff changeset
1449 && DECL_SIZE (base)
kono
parents:
diff changeset
1450 && TREE_CODE (DECL_SIZE (base)) == INTEGER_CST
kono
parents:
diff changeset
1451 && compare_tree_int (DECL_SIZE (base), bitpos) >= 0
kono
parents:
diff changeset
1452 && (!is_global_var (base) || decl_binds_to_current_def_p (base)))
kono
parents:
diff changeset
1453 return;
kono
parents:
diff changeset
1454 }
kono
parents:
diff changeset
1455 else if (TREE_CODE (inner) == MEM_REF)
kono
parents:
diff changeset
1456 {
kono
parents:
diff changeset
1457 base = TREE_OPERAND (inner, 0);
kono
parents:
diff changeset
1458 if (TREE_CODE (base) == ADDR_EXPR
kono
parents:
diff changeset
1459 && DECL_P (TREE_OPERAND (base, 0))
kono
parents:
diff changeset
1460 && !TREE_ADDRESSABLE (TREE_OPERAND (base, 0))
kono
parents:
diff changeset
1461 && !is_global_var (TREE_OPERAND (base, 0)))
kono
parents:
diff changeset
1462 return;
kono
parents:
diff changeset
1463 moff = TREE_OPERAND (inner, 1);
kono
parents:
diff changeset
1464 if (integer_zerop (moff))
kono
parents:
diff changeset
1465 moff = NULL_TREE;
kono
parents:
diff changeset
1466 }
kono
parents:
diff changeset
1467 else
kono
parents:
diff changeset
1468 return;
kono
parents:
diff changeset
1469
kono
parents:
diff changeset
1470 if (!POINTER_TYPE_P (TREE_TYPE (base)) && !DECL_P (base))
kono
parents:
diff changeset
1471 return;
kono
parents:
diff changeset
1472 bytepos = bitpos / BITS_PER_UNIT;
kono
parents:
diff changeset
1473 if (offset == NULL_TREE && bytepos == 0 && moff == NULL_TREE)
kono
parents:
diff changeset
1474 return;
kono
parents:
diff changeset
1475
kono
parents:
diff changeset
1476 tree base_addr = base;
kono
parents:
diff changeset
1477 if (decl_p)
kono
parents:
diff changeset
1478 base_addr = build1 (ADDR_EXPR,
kono
parents:
diff changeset
1479 build_pointer_type (TREE_TYPE (base)), base);
kono
parents:
diff changeset
1480 t = offset;
kono
parents:
diff changeset
1481 if (bytepos)
kono
parents:
diff changeset
1482 {
kono
parents:
diff changeset
1483 if (t)
kono
parents:
diff changeset
1484 t = fold_build2 (PLUS_EXPR, TREE_TYPE (t), t,
kono
parents:
diff changeset
1485 build_int_cst (TREE_TYPE (t), bytepos));
kono
parents:
diff changeset
1486 else
kono
parents:
diff changeset
1487 t = size_int (bytepos);
kono
parents:
diff changeset
1488 }
kono
parents:
diff changeset
1489 if (moff)
kono
parents:
diff changeset
1490 {
kono
parents:
diff changeset
1491 if (t)
kono
parents:
diff changeset
1492 t = fold_build2 (PLUS_EXPR, TREE_TYPE (t), t,
kono
parents:
diff changeset
1493 fold_convert (TREE_TYPE (t), moff));
kono
parents:
diff changeset
1494 else
kono
parents:
diff changeset
1495 t = fold_convert (sizetype, moff);
kono
parents:
diff changeset
1496 }
kono
parents:
diff changeset
1497 t = force_gimple_operand_gsi (gsi, t, true, NULL_TREE, true,
kono
parents:
diff changeset
1498 GSI_SAME_STMT);
kono
parents:
diff changeset
1499 base_addr = force_gimple_operand_gsi (gsi, base_addr, true, NULL_TREE, true,
kono
parents:
diff changeset
1500 GSI_SAME_STMT);
kono
parents:
diff changeset
1501 instrument_pointer_overflow (gsi, base_addr, t);
kono
parents:
diff changeset
1502 }
kono
parents:
diff changeset
1503
kono
parents:
diff changeset
1504 /* Build an ubsan builtin call for the signed-integer-overflow
kono
parents:
diff changeset
1505 sanitization. CODE says what kind of builtin are we building,
kono
parents:
diff changeset
1506 LOC is a location, LHSTYPE is the type of LHS, OP0 and OP1
kono
parents:
diff changeset
1507 are operands of the binary operation. */
kono
parents:
diff changeset
1508
kono
parents:
diff changeset
1509 tree
kono
parents:
diff changeset
1510 ubsan_build_overflow_builtin (tree_code code, location_t loc, tree lhstype,
kono
parents:
diff changeset
1511 tree op0, tree op1, tree *datap)
kono
parents:
diff changeset
1512 {
kono
parents:
diff changeset
1513 if (flag_sanitize_undefined_trap_on_error)
kono
parents:
diff changeset
1514 return build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
kono
parents:
diff changeset
1515
kono
parents:
diff changeset
1516 tree data;
kono
parents:
diff changeset
1517 if (datap && *datap)
kono
parents:
diff changeset
1518 data = *datap;
kono
parents:
diff changeset
1519 else
kono
parents:
diff changeset
1520 data = ubsan_create_data ("__ubsan_overflow_data", 1, &loc,
kono
parents:
diff changeset
1521 ubsan_type_descriptor (lhstype), NULL_TREE,
kono
parents:
diff changeset
1522 NULL_TREE);
kono
parents:
diff changeset
1523 if (datap)
kono
parents:
diff changeset
1524 *datap = data;
kono
parents:
diff changeset
1525 enum built_in_function fn_code;
kono
parents:
diff changeset
1526
kono
parents:
diff changeset
1527 switch (code)
kono
parents:
diff changeset
1528 {
kono
parents:
diff changeset
1529 case PLUS_EXPR:
kono
parents:
diff changeset
1530 fn_code = (flag_sanitize_recover & SANITIZE_SI_OVERFLOW)
kono
parents:
diff changeset
1531 ? BUILT_IN_UBSAN_HANDLE_ADD_OVERFLOW
kono
parents:
diff changeset
1532 : BUILT_IN_UBSAN_HANDLE_ADD_OVERFLOW_ABORT;
kono
parents:
diff changeset
1533 break;
kono
parents:
diff changeset
1534 case MINUS_EXPR:
kono
parents:
diff changeset
1535 fn_code = (flag_sanitize_recover & SANITIZE_SI_OVERFLOW)
kono
parents:
diff changeset
1536 ? BUILT_IN_UBSAN_HANDLE_SUB_OVERFLOW
kono
parents:
diff changeset
1537 : BUILT_IN_UBSAN_HANDLE_SUB_OVERFLOW_ABORT;
kono
parents:
diff changeset
1538 break;
kono
parents:
diff changeset
1539 case MULT_EXPR:
kono
parents:
diff changeset
1540 fn_code = (flag_sanitize_recover & SANITIZE_SI_OVERFLOW)
kono
parents:
diff changeset
1541 ? BUILT_IN_UBSAN_HANDLE_MUL_OVERFLOW
kono
parents:
diff changeset
1542 : BUILT_IN_UBSAN_HANDLE_MUL_OVERFLOW_ABORT;
kono
parents:
diff changeset
1543 break;
kono
parents:
diff changeset
1544 case NEGATE_EXPR:
kono
parents:
diff changeset
1545 fn_code = (flag_sanitize_recover & SANITIZE_SI_OVERFLOW)
kono
parents:
diff changeset
1546 ? BUILT_IN_UBSAN_HANDLE_NEGATE_OVERFLOW
kono
parents:
diff changeset
1547 : BUILT_IN_UBSAN_HANDLE_NEGATE_OVERFLOW_ABORT;
kono
parents:
diff changeset
1548 break;
kono
parents:
diff changeset
1549 default:
kono
parents:
diff changeset
1550 gcc_unreachable ();
kono
parents:
diff changeset
1551 }
kono
parents:
diff changeset
1552 tree fn = builtin_decl_explicit (fn_code);
kono
parents:
diff changeset
1553 return build_call_expr_loc (loc, fn, 2 + (code != NEGATE_EXPR),
kono
parents:
diff changeset
1554 build_fold_addr_expr_loc (loc, data),
kono
parents:
diff changeset
1555 ubsan_encode_value (op0, UBSAN_ENCODE_VALUE_RTL),
kono
parents:
diff changeset
1556 op1
kono
parents:
diff changeset
1557 ? ubsan_encode_value (op1,
kono
parents:
diff changeset
1558 UBSAN_ENCODE_VALUE_RTL)
kono
parents:
diff changeset
1559 : NULL_TREE);
kono
parents:
diff changeset
1560 }
kono
parents:
diff changeset
1561
kono
parents:
diff changeset
1562 /* Perform the signed integer instrumentation. GSI is the iterator
kono
parents:
diff changeset
1563 pointing at statement we are trying to instrument. */
kono
parents:
diff changeset
1564
kono
parents:
diff changeset
1565 static void
kono
parents:
diff changeset
1566 instrument_si_overflow (gimple_stmt_iterator gsi)
kono
parents:
diff changeset
1567 {
kono
parents:
diff changeset
1568 gimple *stmt = gsi_stmt (gsi);
kono
parents:
diff changeset
1569 tree_code code = gimple_assign_rhs_code (stmt);
kono
parents:
diff changeset
1570 tree lhs = gimple_assign_lhs (stmt);
kono
parents:
diff changeset
1571 tree lhstype = TREE_TYPE (lhs);
kono
parents:
diff changeset
1572 tree lhsinner = VECTOR_TYPE_P (lhstype) ? TREE_TYPE (lhstype) : lhstype;
kono
parents:
diff changeset
1573 tree a, b;
kono
parents:
diff changeset
1574 gimple *g;
kono
parents:
diff changeset
1575
kono
parents:
diff changeset
1576 /* If this is not a signed operation, don't instrument anything here.
kono
parents:
diff changeset
1577 Also punt on bit-fields. */
kono
parents:
diff changeset
1578 if (!INTEGRAL_TYPE_P (lhsinner)
kono
parents:
diff changeset
1579 || TYPE_OVERFLOW_WRAPS (lhsinner)
kono
parents:
diff changeset
1580 || GET_MODE_BITSIZE (TYPE_MODE (lhsinner)) != TYPE_PRECISION (lhsinner))
kono
parents:
diff changeset
1581 return;
kono
parents:
diff changeset
1582
kono
parents:
diff changeset
1583 switch (code)
kono
parents:
diff changeset
1584 {
kono
parents:
diff changeset
1585 case MINUS_EXPR:
kono
parents:
diff changeset
1586 case PLUS_EXPR:
kono
parents:
diff changeset
1587 case MULT_EXPR:
kono
parents:
diff changeset
1588 /* Transform
kono
parents:
diff changeset
1589 i = u {+,-,*} 5;
kono
parents:
diff changeset
1590 into
kono
parents:
diff changeset
1591 i = UBSAN_CHECK_{ADD,SUB,MUL} (u, 5); */
kono
parents:
diff changeset
1592 a = gimple_assign_rhs1 (stmt);
kono
parents:
diff changeset
1593 b = gimple_assign_rhs2 (stmt);
kono
parents:
diff changeset
1594 g = gimple_build_call_internal (code == PLUS_EXPR
kono
parents:
diff changeset
1595 ? IFN_UBSAN_CHECK_ADD
kono
parents:
diff changeset
1596 : code == MINUS_EXPR
kono
parents:
diff changeset
1597 ? IFN_UBSAN_CHECK_SUB
kono
parents:
diff changeset
1598 : IFN_UBSAN_CHECK_MUL, 2, a, b);
kono
parents:
diff changeset
1599 gimple_call_set_lhs (g, lhs);
kono
parents:
diff changeset
1600 gsi_replace (&gsi, g, true);
kono
parents:
diff changeset
1601 break;
kono
parents:
diff changeset
1602 case NEGATE_EXPR:
kono
parents:
diff changeset
1603 /* Represent i = -u;
kono
parents:
diff changeset
1604 as
kono
parents:
diff changeset
1605 i = UBSAN_CHECK_SUB (0, u); */
kono
parents:
diff changeset
1606 a = build_zero_cst (lhstype);
kono
parents:
diff changeset
1607 b = gimple_assign_rhs1 (stmt);
kono
parents:
diff changeset
1608 g = gimple_build_call_internal (IFN_UBSAN_CHECK_SUB, 2, a, b);
kono
parents:
diff changeset
1609 gimple_call_set_lhs (g, lhs);
kono
parents:
diff changeset
1610 gsi_replace (&gsi, g, true);
kono
parents:
diff changeset
1611 break;
kono
parents:
diff changeset
1612 case ABS_EXPR:
kono
parents:
diff changeset
1613 /* Transform i = ABS_EXPR<u>;
kono
parents:
diff changeset
1614 into
kono
parents:
diff changeset
1615 _N = UBSAN_CHECK_SUB (0, u);
kono
parents:
diff changeset
1616 i = ABS_EXPR<_N>; */
kono
parents:
diff changeset
1617 a = build_zero_cst (lhstype);
kono
parents:
diff changeset
1618 b = gimple_assign_rhs1 (stmt);
kono
parents:
diff changeset
1619 g = gimple_build_call_internal (IFN_UBSAN_CHECK_SUB, 2, a, b);
kono
parents:
diff changeset
1620 a = make_ssa_name (lhstype);
kono
parents:
diff changeset
1621 gimple_call_set_lhs (g, a);
kono
parents:
diff changeset
1622 gimple_set_location (g, gimple_location (stmt));
kono
parents:
diff changeset
1623 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1624 gimple_assign_set_rhs1 (stmt, a);
kono
parents:
diff changeset
1625 update_stmt (stmt);
kono
parents:
diff changeset
1626 break;
kono
parents:
diff changeset
1627 default:
kono
parents:
diff changeset
1628 break;
kono
parents:
diff changeset
1629 }
kono
parents:
diff changeset
1630 }
kono
parents:
diff changeset
1631
kono
parents:
diff changeset
1632 /* Instrument loads from (non-bitfield) bool and C++ enum values
kono
parents:
diff changeset
1633 to check if the memory value is outside of the range of the valid
kono
parents:
diff changeset
1634 type values. */
kono
parents:
diff changeset
1635
kono
parents:
diff changeset
1636 static void
kono
parents:
diff changeset
1637 instrument_bool_enum_load (gimple_stmt_iterator *gsi)
kono
parents:
diff changeset
1638 {
kono
parents:
diff changeset
1639 gimple *stmt = gsi_stmt (*gsi);
kono
parents:
diff changeset
1640 tree rhs = gimple_assign_rhs1 (stmt);
kono
parents:
diff changeset
1641 tree type = TREE_TYPE (rhs);
kono
parents:
diff changeset
1642 tree minv = NULL_TREE, maxv = NULL_TREE;
kono
parents:
diff changeset
1643
kono
parents:
diff changeset
1644 if (TREE_CODE (type) == BOOLEAN_TYPE
kono
parents:
diff changeset
1645 && sanitize_flags_p (SANITIZE_BOOL))
kono
parents:
diff changeset
1646 {
kono
parents:
diff changeset
1647 minv = boolean_false_node;
kono
parents:
diff changeset
1648 maxv = boolean_true_node;
kono
parents:
diff changeset
1649 }
kono
parents:
diff changeset
1650 else if (TREE_CODE (type) == ENUMERAL_TYPE
kono
parents:
diff changeset
1651 && sanitize_flags_p (SANITIZE_ENUM)
kono
parents:
diff changeset
1652 && TREE_TYPE (type) != NULL_TREE
kono
parents:
diff changeset
1653 && TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE
kono
parents:
diff changeset
1654 && (TYPE_PRECISION (TREE_TYPE (type))
kono
parents:
diff changeset
1655 < GET_MODE_PRECISION (SCALAR_INT_TYPE_MODE (type))))
kono
parents:
diff changeset
1656 {
kono
parents:
diff changeset
1657 minv = TYPE_MIN_VALUE (TREE_TYPE (type));
kono
parents:
diff changeset
1658 maxv = TYPE_MAX_VALUE (TREE_TYPE (type));
kono
parents:
diff changeset
1659 }
kono
parents:
diff changeset
1660 else
kono
parents:
diff changeset
1661 return;
kono
parents:
diff changeset
1662
kono
parents:
diff changeset
1663 int modebitsize = GET_MODE_BITSIZE (SCALAR_INT_TYPE_MODE (type));
kono
parents:
diff changeset
1664 HOST_WIDE_INT bitsize, bitpos;
kono
parents:
diff changeset
1665 tree offset;
kono
parents:
diff changeset
1666 machine_mode mode;
kono
parents:
diff changeset
1667 int volatilep = 0, reversep, unsignedp = 0;
kono
parents:
diff changeset
1668 tree base = get_inner_reference (rhs, &bitsize, &bitpos, &offset, &mode,
kono
parents:
diff changeset
1669 &unsignedp, &reversep, &volatilep);
kono
parents:
diff changeset
1670 tree utype = build_nonstandard_integer_type (modebitsize, 1);
kono
parents:
diff changeset
1671
kono
parents:
diff changeset
1672 if ((VAR_P (base) && DECL_HARD_REGISTER (base))
kono
parents:
diff changeset
1673 || (bitpos % modebitsize) != 0
kono
parents:
diff changeset
1674 || bitsize != modebitsize
kono
parents:
diff changeset
1675 || GET_MODE_BITSIZE (SCALAR_INT_TYPE_MODE (utype)) != modebitsize
kono
parents:
diff changeset
1676 || TREE_CODE (gimple_assign_lhs (stmt)) != SSA_NAME)
kono
parents:
diff changeset
1677 return;
kono
parents:
diff changeset
1678
kono
parents:
diff changeset
1679 bool ends_bb = stmt_ends_bb_p (stmt);
kono
parents:
diff changeset
1680 location_t loc = gimple_location (stmt);
kono
parents:
diff changeset
1681 tree lhs = gimple_assign_lhs (stmt);
kono
parents:
diff changeset
1682 tree ptype = build_pointer_type (TREE_TYPE (rhs));
kono
parents:
diff changeset
1683 tree atype = reference_alias_ptr_type (rhs);
kono
parents:
diff changeset
1684 gimple *g = gimple_build_assign (make_ssa_name (ptype),
kono
parents:
diff changeset
1685 build_fold_addr_expr (rhs));
kono
parents:
diff changeset
1686 gimple_set_location (g, loc);
kono
parents:
diff changeset
1687 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1688 tree mem = build2 (MEM_REF, utype, gimple_assign_lhs (g),
kono
parents:
diff changeset
1689 build_int_cst (atype, 0));
kono
parents:
diff changeset
1690 tree urhs = make_ssa_name (utype);
kono
parents:
diff changeset
1691 if (ends_bb)
kono
parents:
diff changeset
1692 {
kono
parents:
diff changeset
1693 gimple_assign_set_lhs (stmt, urhs);
kono
parents:
diff changeset
1694 g = gimple_build_assign (lhs, NOP_EXPR, urhs);
kono
parents:
diff changeset
1695 gimple_set_location (g, loc);
kono
parents:
diff changeset
1696 edge e = find_fallthru_edge (gimple_bb (stmt)->succs);
kono
parents:
diff changeset
1697 gsi_insert_on_edge_immediate (e, g);
kono
parents:
diff changeset
1698 gimple_assign_set_rhs_from_tree (gsi, mem);
kono
parents:
diff changeset
1699 update_stmt (stmt);
kono
parents:
diff changeset
1700 *gsi = gsi_for_stmt (g);
kono
parents:
diff changeset
1701 g = stmt;
kono
parents:
diff changeset
1702 }
kono
parents:
diff changeset
1703 else
kono
parents:
diff changeset
1704 {
kono
parents:
diff changeset
1705 g = gimple_build_assign (urhs, mem);
kono
parents:
diff changeset
1706 gimple_set_location (g, loc);
kono
parents:
diff changeset
1707 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1708 }
kono
parents:
diff changeset
1709 minv = fold_convert (utype, minv);
kono
parents:
diff changeset
1710 maxv = fold_convert (utype, maxv);
kono
parents:
diff changeset
1711 if (!integer_zerop (minv))
kono
parents:
diff changeset
1712 {
kono
parents:
diff changeset
1713 g = gimple_build_assign (make_ssa_name (utype), MINUS_EXPR, urhs, minv);
kono
parents:
diff changeset
1714 gimple_set_location (g, loc);
kono
parents:
diff changeset
1715 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1716 }
kono
parents:
diff changeset
1717
kono
parents:
diff changeset
1718 gimple_stmt_iterator gsi2 = *gsi;
kono
parents:
diff changeset
1719 basic_block then_bb, fallthru_bb;
kono
parents:
diff changeset
1720 *gsi = create_cond_insert_point (gsi, true, false, true,
kono
parents:
diff changeset
1721 &then_bb, &fallthru_bb);
kono
parents:
diff changeset
1722 g = gimple_build_cond (GT_EXPR, gimple_assign_lhs (g),
kono
parents:
diff changeset
1723 int_const_binop (MINUS_EXPR, maxv, minv),
kono
parents:
diff changeset
1724 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
1725 gimple_set_location (g, loc);
kono
parents:
diff changeset
1726 gsi_insert_after (gsi, g, GSI_NEW_STMT);
kono
parents:
diff changeset
1727
kono
parents:
diff changeset
1728 if (!ends_bb)
kono
parents:
diff changeset
1729 {
kono
parents:
diff changeset
1730 gimple_assign_set_rhs_with_ops (&gsi2, NOP_EXPR, urhs);
kono
parents:
diff changeset
1731 update_stmt (stmt);
kono
parents:
diff changeset
1732 }
kono
parents:
diff changeset
1733
kono
parents:
diff changeset
1734 gsi2 = gsi_after_labels (then_bb);
kono
parents:
diff changeset
1735 if (flag_sanitize_undefined_trap_on_error)
kono
parents:
diff changeset
1736 g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
kono
parents:
diff changeset
1737 else
kono
parents:
diff changeset
1738 {
kono
parents:
diff changeset
1739 tree data = ubsan_create_data ("__ubsan_invalid_value_data", 1, &loc,
kono
parents:
diff changeset
1740 ubsan_type_descriptor (type), NULL_TREE,
kono
parents:
diff changeset
1741 NULL_TREE);
kono
parents:
diff changeset
1742 data = build_fold_addr_expr_loc (loc, data);
kono
parents:
diff changeset
1743 enum built_in_function bcode
kono
parents:
diff changeset
1744 = (flag_sanitize_recover & (TREE_CODE (type) == BOOLEAN_TYPE
kono
parents:
diff changeset
1745 ? SANITIZE_BOOL : SANITIZE_ENUM))
kono
parents:
diff changeset
1746 ? BUILT_IN_UBSAN_HANDLE_LOAD_INVALID_VALUE
kono
parents:
diff changeset
1747 : BUILT_IN_UBSAN_HANDLE_LOAD_INVALID_VALUE_ABORT;
kono
parents:
diff changeset
1748 tree fn = builtin_decl_explicit (bcode);
kono
parents:
diff changeset
1749
kono
parents:
diff changeset
1750 tree val = ubsan_encode_value (urhs, UBSAN_ENCODE_VALUE_GIMPLE);
kono
parents:
diff changeset
1751 val = force_gimple_operand_gsi (&gsi2, val, true, NULL_TREE, true,
kono
parents:
diff changeset
1752 GSI_SAME_STMT);
kono
parents:
diff changeset
1753 g = gimple_build_call (fn, 2, data, val);
kono
parents:
diff changeset
1754 }
kono
parents:
diff changeset
1755 gimple_set_location (g, loc);
kono
parents:
diff changeset
1756 gsi_insert_before (&gsi2, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1757 ubsan_create_edge (g);
kono
parents:
diff changeset
1758 *gsi = gsi_for_stmt (stmt);
kono
parents:
diff changeset
1759 }
kono
parents:
diff changeset
1760
kono
parents:
diff changeset
1761 /* Determine if we can propagate given LOCATION to ubsan_data descriptor to use
kono
parents:
diff changeset
1762 new style handlers. Libubsan uses heuristics to destinguish between old and
kono
parents:
diff changeset
1763 new styles and relies on these properties for filename:
kono
parents:
diff changeset
1764
kono
parents:
diff changeset
1765 a) Location's filename must not be NULL.
kono
parents:
diff changeset
1766 b) Location's filename must not be equal to "".
kono
parents:
diff changeset
1767 c) Location's filename must not be equal to "\1".
kono
parents:
diff changeset
1768 d) First two bytes of filename must not contain '\xff' symbol. */
kono
parents:
diff changeset
1769
kono
parents:
diff changeset
1770 static bool
kono
parents:
diff changeset
1771 ubsan_use_new_style_p (location_t loc)
kono
parents:
diff changeset
1772 {
kono
parents:
diff changeset
1773 if (loc == UNKNOWN_LOCATION)
kono
parents:
diff changeset
1774 return false;
kono
parents:
diff changeset
1775
kono
parents:
diff changeset
1776 expanded_location xloc = expand_location (loc);
kono
parents:
diff changeset
1777 if (xloc.file == NULL || strncmp (xloc.file, "\1", 2) == 0
kono
parents:
diff changeset
1778 || xloc.file[0] == '\0' || xloc.file[0] == '\xff'
kono
parents:
diff changeset
1779 || xloc.file[1] == '\xff')
kono
parents:
diff changeset
1780 return false;
kono
parents:
diff changeset
1781
kono
parents:
diff changeset
1782 return true;
kono
parents:
diff changeset
1783 }
kono
parents:
diff changeset
1784
kono
parents:
diff changeset
1785 /* Instrument float point-to-integer conversion. TYPE is an integer type of
kono
parents:
diff changeset
1786 destination, EXPR is floating-point expression. */
kono
parents:
diff changeset
1787
kono
parents:
diff changeset
1788 tree
kono
parents:
diff changeset
1789 ubsan_instrument_float_cast (location_t loc, tree type, tree expr)
kono
parents:
diff changeset
1790 {
kono
parents:
diff changeset
1791 tree expr_type = TREE_TYPE (expr);
kono
parents:
diff changeset
1792 tree t, tt, fn, min, max;
kono
parents:
diff changeset
1793 machine_mode mode = TYPE_MODE (expr_type);
kono
parents:
diff changeset
1794 int prec = TYPE_PRECISION (type);
kono
parents:
diff changeset
1795 bool uns_p = TYPE_UNSIGNED (type);
kono
parents:
diff changeset
1796 if (loc == UNKNOWN_LOCATION)
kono
parents:
diff changeset
1797 loc = input_location;
kono
parents:
diff changeset
1798
kono
parents:
diff changeset
1799 /* Float to integer conversion first truncates toward zero, so
kono
parents:
diff changeset
1800 even signed char c = 127.875f; is not problematic.
kono
parents:
diff changeset
1801 Therefore, we should complain only if EXPR is unordered or smaller
kono
parents:
diff changeset
1802 or equal than TYPE_MIN_VALUE - 1.0 or greater or equal than
kono
parents:
diff changeset
1803 TYPE_MAX_VALUE + 1.0. */
kono
parents:
diff changeset
1804 if (REAL_MODE_FORMAT (mode)->b == 2)
kono
parents:
diff changeset
1805 {
kono
parents:
diff changeset
1806 /* For maximum, TYPE_MAX_VALUE might not be representable
kono
parents:
diff changeset
1807 in EXPR_TYPE, e.g. if TYPE is 64-bit long long and
kono
parents:
diff changeset
1808 EXPR_TYPE is IEEE single float, but TYPE_MAX_VALUE + 1.0 is
kono
parents:
diff changeset
1809 either representable or infinity. */
kono
parents:
diff changeset
1810 REAL_VALUE_TYPE maxval = dconst1;
kono
parents:
diff changeset
1811 SET_REAL_EXP (&maxval, REAL_EXP (&maxval) + prec - !uns_p);
kono
parents:
diff changeset
1812 real_convert (&maxval, mode, &maxval);
kono
parents:
diff changeset
1813 max = build_real (expr_type, maxval);
kono
parents:
diff changeset
1814
kono
parents:
diff changeset
1815 /* For unsigned, assume -1.0 is always representable. */
kono
parents:
diff changeset
1816 if (uns_p)
kono
parents:
diff changeset
1817 min = build_minus_one_cst (expr_type);
kono
parents:
diff changeset
1818 else
kono
parents:
diff changeset
1819 {
kono
parents:
diff changeset
1820 /* TYPE_MIN_VALUE is generally representable (or -inf),
kono
parents:
diff changeset
1821 but TYPE_MIN_VALUE - 1.0 might not be. */
kono
parents:
diff changeset
1822 REAL_VALUE_TYPE minval = dconstm1, minval2;
kono
parents:
diff changeset
1823 SET_REAL_EXP (&minval, REAL_EXP (&minval) + prec - 1);
kono
parents:
diff changeset
1824 real_convert (&minval, mode, &minval);
kono
parents:
diff changeset
1825 real_arithmetic (&minval2, MINUS_EXPR, &minval, &dconst1);
kono
parents:
diff changeset
1826 real_convert (&minval2, mode, &minval2);
kono
parents:
diff changeset
1827 if (real_compare (EQ_EXPR, &minval, &minval2)
kono
parents:
diff changeset
1828 && !real_isinf (&minval))
kono
parents:
diff changeset
1829 {
kono
parents:
diff changeset
1830 /* If TYPE_MIN_VALUE - 1.0 is not representable and
kono
parents:
diff changeset
1831 rounds to TYPE_MIN_VALUE, we need to subtract
kono
parents:
diff changeset
1832 more. As REAL_MODE_FORMAT (mode)->p is the number
kono
parents:
diff changeset
1833 of base digits, we want to subtract a number that
kono
parents:
diff changeset
1834 will be 1 << (REAL_MODE_FORMAT (mode)->p - 1)
kono
parents:
diff changeset
1835 times smaller than minval. */
kono
parents:
diff changeset
1836 minval2 = dconst1;
kono
parents:
diff changeset
1837 gcc_assert (prec > REAL_MODE_FORMAT (mode)->p);
kono
parents:
diff changeset
1838 SET_REAL_EXP (&minval2,
kono
parents:
diff changeset
1839 REAL_EXP (&minval2) + prec - 1
kono
parents:
diff changeset
1840 - REAL_MODE_FORMAT (mode)->p + 1);
kono
parents:
diff changeset
1841 real_arithmetic (&minval2, MINUS_EXPR, &minval, &minval2);
kono
parents:
diff changeset
1842 real_convert (&minval2, mode, &minval2);
kono
parents:
diff changeset
1843 }
kono
parents:
diff changeset
1844 min = build_real (expr_type, minval2);
kono
parents:
diff changeset
1845 }
kono
parents:
diff changeset
1846 }
kono
parents:
diff changeset
1847 else if (REAL_MODE_FORMAT (mode)->b == 10)
kono
parents:
diff changeset
1848 {
kono
parents:
diff changeset
1849 /* For _Decimal128 up to 34 decimal digits, - sign,
kono
parents:
diff changeset
1850 dot, e, exponent. */
kono
parents:
diff changeset
1851 char buf[64];
kono
parents:
diff changeset
1852 mpfr_t m;
kono
parents:
diff changeset
1853 int p = REAL_MODE_FORMAT (mode)->p;
kono
parents:
diff changeset
1854 REAL_VALUE_TYPE maxval, minval;
kono
parents:
diff changeset
1855
kono
parents:
diff changeset
1856 /* Use mpfr_snprintf rounding to compute the smallest
kono
parents:
diff changeset
1857 representable decimal number greater or equal than
kono
parents:
diff changeset
1858 1 << (prec - !uns_p). */
kono
parents:
diff changeset
1859 mpfr_init2 (m, prec + 2);
kono
parents:
diff changeset
1860 mpfr_set_ui_2exp (m, 1, prec - !uns_p, GMP_RNDN);
kono
parents:
diff changeset
1861 mpfr_snprintf (buf, sizeof buf, "%.*RUe", p - 1, m);
kono
parents:
diff changeset
1862 decimal_real_from_string (&maxval, buf);
kono
parents:
diff changeset
1863 max = build_real (expr_type, maxval);
kono
parents:
diff changeset
1864
kono
parents:
diff changeset
1865 /* For unsigned, assume -1.0 is always representable. */
kono
parents:
diff changeset
1866 if (uns_p)
kono
parents:
diff changeset
1867 min = build_minus_one_cst (expr_type);
kono
parents:
diff changeset
1868 else
kono
parents:
diff changeset
1869 {
kono
parents:
diff changeset
1870 /* Use mpfr_snprintf rounding to compute the largest
kono
parents:
diff changeset
1871 representable decimal number less or equal than
kono
parents:
diff changeset
1872 (-1 << (prec - 1)) - 1. */
kono
parents:
diff changeset
1873 mpfr_set_si_2exp (m, -1, prec - 1, GMP_RNDN);
kono
parents:
diff changeset
1874 mpfr_sub_ui (m, m, 1, GMP_RNDN);
kono
parents:
diff changeset
1875 mpfr_snprintf (buf, sizeof buf, "%.*RDe", p - 1, m);
kono
parents:
diff changeset
1876 decimal_real_from_string (&minval, buf);
kono
parents:
diff changeset
1877 min = build_real (expr_type, minval);
kono
parents:
diff changeset
1878 }
kono
parents:
diff changeset
1879 mpfr_clear (m);
kono
parents:
diff changeset
1880 }
kono
parents:
diff changeset
1881 else
kono
parents:
diff changeset
1882 return NULL_TREE;
kono
parents:
diff changeset
1883
kono
parents:
diff changeset
1884 t = fold_build2 (UNLE_EXPR, boolean_type_node, expr, min);
kono
parents:
diff changeset
1885 tt = fold_build2 (UNGE_EXPR, boolean_type_node, expr, max);
kono
parents:
diff changeset
1886 t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, tt);
kono
parents:
diff changeset
1887 if (integer_zerop (t))
kono
parents:
diff changeset
1888 return NULL_TREE;
kono
parents:
diff changeset
1889
kono
parents:
diff changeset
1890 if (flag_sanitize_undefined_trap_on_error)
kono
parents:
diff changeset
1891 fn = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
kono
parents:
diff changeset
1892 else
kono
parents:
diff changeset
1893 {
kono
parents:
diff changeset
1894 location_t *loc_ptr = NULL;
kono
parents:
diff changeset
1895 unsigned num_locations = 0;
kono
parents:
diff changeset
1896 /* Figure out if we can propagate location to ubsan_data and use new
kono
parents:
diff changeset
1897 style handlers in libubsan. */
kono
parents:
diff changeset
1898 if (ubsan_use_new_style_p (loc))
kono
parents:
diff changeset
1899 {
kono
parents:
diff changeset
1900 loc_ptr = &loc;
kono
parents:
diff changeset
1901 num_locations = 1;
kono
parents:
diff changeset
1902 }
kono
parents:
diff changeset
1903 /* Create the __ubsan_handle_float_cast_overflow fn call. */
kono
parents:
diff changeset
1904 tree data = ubsan_create_data ("__ubsan_float_cast_overflow_data",
kono
parents:
diff changeset
1905 num_locations, loc_ptr,
kono
parents:
diff changeset
1906 ubsan_type_descriptor (expr_type),
kono
parents:
diff changeset
1907 ubsan_type_descriptor (type), NULL_TREE,
kono
parents:
diff changeset
1908 NULL_TREE);
kono
parents:
diff changeset
1909 enum built_in_function bcode
kono
parents:
diff changeset
1910 = (flag_sanitize_recover & SANITIZE_FLOAT_CAST)
kono
parents:
diff changeset
1911 ? BUILT_IN_UBSAN_HANDLE_FLOAT_CAST_OVERFLOW
kono
parents:
diff changeset
1912 : BUILT_IN_UBSAN_HANDLE_FLOAT_CAST_OVERFLOW_ABORT;
kono
parents:
diff changeset
1913 fn = builtin_decl_explicit (bcode);
kono
parents:
diff changeset
1914 fn = build_call_expr_loc (loc, fn, 2,
kono
parents:
diff changeset
1915 build_fold_addr_expr_loc (loc, data),
kono
parents:
diff changeset
1916 ubsan_encode_value (expr));
kono
parents:
diff changeset
1917 }
kono
parents:
diff changeset
1918
kono
parents:
diff changeset
1919 return fold_build3 (COND_EXPR, void_type_node, t, fn, integer_zero_node);
kono
parents:
diff changeset
1920 }
kono
parents:
diff changeset
1921
kono
parents:
diff changeset
1922 /* Instrument values passed to function arguments with nonnull attribute. */
kono
parents:
diff changeset
1923
kono
parents:
diff changeset
1924 static void
kono
parents:
diff changeset
1925 instrument_nonnull_arg (gimple_stmt_iterator *gsi)
kono
parents:
diff changeset
1926 {
kono
parents:
diff changeset
1927 gimple *stmt = gsi_stmt (*gsi);
kono
parents:
diff changeset
1928 location_t loc[2];
kono
parents:
diff changeset
1929 /* infer_nonnull_range needs flag_delete_null_pointer_checks set,
kono
parents:
diff changeset
1930 while for nonnull sanitization it is clear. */
kono
parents:
diff changeset
1931 int save_flag_delete_null_pointer_checks = flag_delete_null_pointer_checks;
kono
parents:
diff changeset
1932 flag_delete_null_pointer_checks = 1;
kono
parents:
diff changeset
1933 loc[0] = gimple_location (stmt);
kono
parents:
diff changeset
1934 loc[1] = UNKNOWN_LOCATION;
kono
parents:
diff changeset
1935 for (unsigned int i = 0; i < gimple_call_num_args (stmt); i++)
kono
parents:
diff changeset
1936 {
kono
parents:
diff changeset
1937 tree arg = gimple_call_arg (stmt, i);
kono
parents:
diff changeset
1938 if (POINTER_TYPE_P (TREE_TYPE (arg))
kono
parents:
diff changeset
1939 && infer_nonnull_range_by_attribute (stmt, arg))
kono
parents:
diff changeset
1940 {
kono
parents:
diff changeset
1941 gimple *g;
kono
parents:
diff changeset
1942 if (!is_gimple_val (arg))
kono
parents:
diff changeset
1943 {
kono
parents:
diff changeset
1944 g = gimple_build_assign (make_ssa_name (TREE_TYPE (arg)), arg);
kono
parents:
diff changeset
1945 gimple_set_location (g, loc[0]);
kono
parents:
diff changeset
1946 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1947 arg = gimple_assign_lhs (g);
kono
parents:
diff changeset
1948 }
kono
parents:
diff changeset
1949
kono
parents:
diff changeset
1950 basic_block then_bb, fallthru_bb;
kono
parents:
diff changeset
1951 *gsi = create_cond_insert_point (gsi, true, false, true,
kono
parents:
diff changeset
1952 &then_bb, &fallthru_bb);
kono
parents:
diff changeset
1953 g = gimple_build_cond (EQ_EXPR, arg,
kono
parents:
diff changeset
1954 build_zero_cst (TREE_TYPE (arg)),
kono
parents:
diff changeset
1955 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
1956 gimple_set_location (g, loc[0]);
kono
parents:
diff changeset
1957 gsi_insert_after (gsi, g, GSI_NEW_STMT);
kono
parents:
diff changeset
1958
kono
parents:
diff changeset
1959 *gsi = gsi_after_labels (then_bb);
kono
parents:
diff changeset
1960 if (flag_sanitize_undefined_trap_on_error)
kono
parents:
diff changeset
1961 g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
kono
parents:
diff changeset
1962 else
kono
parents:
diff changeset
1963 {
kono
parents:
diff changeset
1964 tree data = ubsan_create_data ("__ubsan_nonnull_arg_data",
kono
parents:
diff changeset
1965 2, loc, NULL_TREE,
kono
parents:
diff changeset
1966 build_int_cst (integer_type_node,
kono
parents:
diff changeset
1967 i + 1),
kono
parents:
diff changeset
1968 NULL_TREE);
kono
parents:
diff changeset
1969 data = build_fold_addr_expr_loc (loc[0], data);
kono
parents:
diff changeset
1970 enum built_in_function bcode
kono
parents:
diff changeset
1971 = (flag_sanitize_recover & SANITIZE_NONNULL_ATTRIBUTE)
kono
parents:
diff changeset
1972 ? BUILT_IN_UBSAN_HANDLE_NONNULL_ARG
kono
parents:
diff changeset
1973 : BUILT_IN_UBSAN_HANDLE_NONNULL_ARG_ABORT;
kono
parents:
diff changeset
1974 tree fn = builtin_decl_explicit (bcode);
kono
parents:
diff changeset
1975
kono
parents:
diff changeset
1976 g = gimple_build_call (fn, 1, data);
kono
parents:
diff changeset
1977 }
kono
parents:
diff changeset
1978 gimple_set_location (g, loc[0]);
kono
parents:
diff changeset
1979 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1980 ubsan_create_edge (g);
kono
parents:
diff changeset
1981 }
kono
parents:
diff changeset
1982 *gsi = gsi_for_stmt (stmt);
kono
parents:
diff changeset
1983 }
kono
parents:
diff changeset
1984 flag_delete_null_pointer_checks = save_flag_delete_null_pointer_checks;
kono
parents:
diff changeset
1985 }
kono
parents:
diff changeset
1986
kono
parents:
diff changeset
1987 /* Instrument returns in functions with returns_nonnull attribute. */
kono
parents:
diff changeset
1988
kono
parents:
diff changeset
1989 static void
kono
parents:
diff changeset
1990 instrument_nonnull_return (gimple_stmt_iterator *gsi)
kono
parents:
diff changeset
1991 {
kono
parents:
diff changeset
1992 greturn *stmt = as_a <greturn *> (gsi_stmt (*gsi));
kono
parents:
diff changeset
1993 location_t loc[2];
kono
parents:
diff changeset
1994 tree arg = gimple_return_retval (stmt);
kono
parents:
diff changeset
1995 /* infer_nonnull_range needs flag_delete_null_pointer_checks set,
kono
parents:
diff changeset
1996 while for nonnull return sanitization it is clear. */
kono
parents:
diff changeset
1997 int save_flag_delete_null_pointer_checks = flag_delete_null_pointer_checks;
kono
parents:
diff changeset
1998 flag_delete_null_pointer_checks = 1;
kono
parents:
diff changeset
1999 loc[0] = gimple_location (stmt);
kono
parents:
diff changeset
2000 loc[1] = UNKNOWN_LOCATION;
kono
parents:
diff changeset
2001 if (arg
kono
parents:
diff changeset
2002 && POINTER_TYPE_P (TREE_TYPE (arg))
kono
parents:
diff changeset
2003 && is_gimple_val (arg)
kono
parents:
diff changeset
2004 && infer_nonnull_range_by_attribute (stmt, arg))
kono
parents:
diff changeset
2005 {
kono
parents:
diff changeset
2006 basic_block then_bb, fallthru_bb;
kono
parents:
diff changeset
2007 *gsi = create_cond_insert_point (gsi, true, false, true,
kono
parents:
diff changeset
2008 &then_bb, &fallthru_bb);
kono
parents:
diff changeset
2009 gimple *g = gimple_build_cond (EQ_EXPR, arg,
kono
parents:
diff changeset
2010 build_zero_cst (TREE_TYPE (arg)),
kono
parents:
diff changeset
2011 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
2012 gimple_set_location (g, loc[0]);
kono
parents:
diff changeset
2013 gsi_insert_after (gsi, g, GSI_NEW_STMT);
kono
parents:
diff changeset
2014
kono
parents:
diff changeset
2015 *gsi = gsi_after_labels (then_bb);
kono
parents:
diff changeset
2016 if (flag_sanitize_undefined_trap_on_error)
kono
parents:
diff changeset
2017 g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
kono
parents:
diff changeset
2018 else
kono
parents:
diff changeset
2019 {
kono
parents:
diff changeset
2020 tree data = ubsan_create_data ("__ubsan_nonnull_return_data",
kono
parents:
diff changeset
2021 1, &loc[1], NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
2022 data = build_fold_addr_expr_loc (loc[0], data);
kono
parents:
diff changeset
2023 tree data2 = ubsan_create_data ("__ubsan_nonnull_return_data",
kono
parents:
diff changeset
2024 1, &loc[0], NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
2025 data2 = build_fold_addr_expr_loc (loc[0], data2);
kono
parents:
diff changeset
2026 enum built_in_function bcode
kono
parents:
diff changeset
2027 = (flag_sanitize_recover & SANITIZE_RETURNS_NONNULL_ATTRIBUTE)
kono
parents:
diff changeset
2028 ? BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_V1
kono
parents:
diff changeset
2029 : BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_V1_ABORT;
kono
parents:
diff changeset
2030 tree fn = builtin_decl_explicit (bcode);
kono
parents:
diff changeset
2031
kono
parents:
diff changeset
2032 g = gimple_build_call (fn, 2, data, data2);
kono
parents:
diff changeset
2033 }
kono
parents:
diff changeset
2034 gimple_set_location (g, loc[0]);
kono
parents:
diff changeset
2035 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
2036 ubsan_create_edge (g);
kono
parents:
diff changeset
2037 *gsi = gsi_for_stmt (stmt);
kono
parents:
diff changeset
2038 }
kono
parents:
diff changeset
2039 flag_delete_null_pointer_checks = save_flag_delete_null_pointer_checks;
kono
parents:
diff changeset
2040 }
kono
parents:
diff changeset
2041
kono
parents:
diff changeset
2042 /* Instrument memory references. Here we check whether the pointer
kono
parents:
diff changeset
2043 points to an out-of-bounds location. */
kono
parents:
diff changeset
2044
kono
parents:
diff changeset
2045 static void
kono
parents:
diff changeset
2046 instrument_object_size (gimple_stmt_iterator *gsi, tree t, bool is_lhs)
kono
parents:
diff changeset
2047 {
kono
parents:
diff changeset
2048 gimple *stmt = gsi_stmt (*gsi);
kono
parents:
diff changeset
2049 location_t loc = gimple_location (stmt);
kono
parents:
diff changeset
2050 tree type;
kono
parents:
diff changeset
2051 tree index = NULL_TREE;
kono
parents:
diff changeset
2052 HOST_WIDE_INT size_in_bytes;
kono
parents:
diff changeset
2053
kono
parents:
diff changeset
2054 type = TREE_TYPE (t);
kono
parents:
diff changeset
2055 if (VOID_TYPE_P (type))
kono
parents:
diff changeset
2056 return;
kono
parents:
diff changeset
2057
kono
parents:
diff changeset
2058 switch (TREE_CODE (t))
kono
parents:
diff changeset
2059 {
kono
parents:
diff changeset
2060 case COMPONENT_REF:
kono
parents:
diff changeset
2061 if (TREE_CODE (t) == COMPONENT_REF
kono
parents:
diff changeset
2062 && DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1)) != NULL_TREE)
kono
parents:
diff changeset
2063 {
kono
parents:
diff changeset
2064 tree repr = DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1));
kono
parents:
diff changeset
2065 t = build3 (COMPONENT_REF, TREE_TYPE (repr), TREE_OPERAND (t, 0),
kono
parents:
diff changeset
2066 repr, TREE_OPERAND (t, 2));
kono
parents:
diff changeset
2067 }
kono
parents:
diff changeset
2068 break;
kono
parents:
diff changeset
2069 case ARRAY_REF:
kono
parents:
diff changeset
2070 index = TREE_OPERAND (t, 1);
kono
parents:
diff changeset
2071 break;
kono
parents:
diff changeset
2072 case INDIRECT_REF:
kono
parents:
diff changeset
2073 case MEM_REF:
kono
parents:
diff changeset
2074 case VAR_DECL:
kono
parents:
diff changeset
2075 case PARM_DECL:
kono
parents:
diff changeset
2076 case RESULT_DECL:
kono
parents:
diff changeset
2077 break;
kono
parents:
diff changeset
2078 default:
kono
parents:
diff changeset
2079 return;
kono
parents:
diff changeset
2080 }
kono
parents:
diff changeset
2081
kono
parents:
diff changeset
2082 size_in_bytes = int_size_in_bytes (type);
kono
parents:
diff changeset
2083 if (size_in_bytes <= 0)
kono
parents:
diff changeset
2084 return;
kono
parents:
diff changeset
2085
kono
parents:
diff changeset
2086 HOST_WIDE_INT bitsize, bitpos;
kono
parents:
diff changeset
2087 tree offset;
kono
parents:
diff changeset
2088 machine_mode mode;
kono
parents:
diff changeset
2089 int volatilep = 0, reversep, unsignedp = 0;
kono
parents:
diff changeset
2090 tree inner = get_inner_reference (t, &bitsize, &bitpos, &offset, &mode,
kono
parents:
diff changeset
2091 &unsignedp, &reversep, &volatilep);
kono
parents:
diff changeset
2092
kono
parents:
diff changeset
2093 if (bitpos % BITS_PER_UNIT != 0
kono
parents:
diff changeset
2094 || bitsize != size_in_bytes * BITS_PER_UNIT)
kono
parents:
diff changeset
2095 return;
kono
parents:
diff changeset
2096
kono
parents:
diff changeset
2097 bool decl_p = DECL_P (inner);
kono
parents:
diff changeset
2098 tree base;
kono
parents:
diff changeset
2099 if (decl_p)
kono
parents:
diff changeset
2100 {
kono
parents:
diff changeset
2101 if (DECL_REGISTER (inner))
kono
parents:
diff changeset
2102 return;
kono
parents:
diff changeset
2103 base = inner;
kono
parents:
diff changeset
2104 }
kono
parents:
diff changeset
2105 else if (TREE_CODE (inner) == MEM_REF)
kono
parents:
diff changeset
2106 base = TREE_OPERAND (inner, 0);
kono
parents:
diff changeset
2107 else
kono
parents:
diff changeset
2108 return;
kono
parents:
diff changeset
2109 tree ptr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (t)), t);
kono
parents:
diff changeset
2110
kono
parents:
diff changeset
2111 while (TREE_CODE (base) == SSA_NAME)
kono
parents:
diff changeset
2112 {
kono
parents:
diff changeset
2113 gimple *def_stmt = SSA_NAME_DEF_STMT (base);
kono
parents:
diff changeset
2114 if (gimple_assign_ssa_name_copy_p (def_stmt)
kono
parents:
diff changeset
2115 || (gimple_assign_cast_p (def_stmt)
kono
parents:
diff changeset
2116 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (def_stmt))))
kono
parents:
diff changeset
2117 || (is_gimple_assign (def_stmt)
kono
parents:
diff changeset
2118 && gimple_assign_rhs_code (def_stmt) == POINTER_PLUS_EXPR))
kono
parents:
diff changeset
2119 {
kono
parents:
diff changeset
2120 tree rhs1 = gimple_assign_rhs1 (def_stmt);
kono
parents:
diff changeset
2121 if (TREE_CODE (rhs1) == SSA_NAME
kono
parents:
diff changeset
2122 && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs1))
kono
parents:
diff changeset
2123 break;
kono
parents:
diff changeset
2124 else
kono
parents:
diff changeset
2125 base = rhs1;
kono
parents:
diff changeset
2126 }
kono
parents:
diff changeset
2127 else
kono
parents:
diff changeset
2128 break;
kono
parents:
diff changeset
2129 }
kono
parents:
diff changeset
2130
kono
parents:
diff changeset
2131 if (!POINTER_TYPE_P (TREE_TYPE (base)) && !DECL_P (base))
kono
parents:
diff changeset
2132 return;
kono
parents:
diff changeset
2133
kono
parents:
diff changeset
2134 tree sizet;
kono
parents:
diff changeset
2135 tree base_addr = base;
kono
parents:
diff changeset
2136 gimple *bos_stmt = NULL;
kono
parents:
diff changeset
2137 if (decl_p)
kono
parents:
diff changeset
2138 base_addr = build1 (ADDR_EXPR,
kono
parents:
diff changeset
2139 build_pointer_type (TREE_TYPE (base)), base);
kono
parents:
diff changeset
2140 unsigned HOST_WIDE_INT size;
kono
parents:
diff changeset
2141 if (compute_builtin_object_size (base_addr, 0, &size))
kono
parents:
diff changeset
2142 sizet = build_int_cst (sizetype, size);
kono
parents:
diff changeset
2143 else if (optimize)
kono
parents:
diff changeset
2144 {
kono
parents:
diff changeset
2145 if (LOCATION_LOCUS (loc) == UNKNOWN_LOCATION)
kono
parents:
diff changeset
2146 loc = input_location;
kono
parents:
diff changeset
2147 /* Generate __builtin_object_size call. */
kono
parents:
diff changeset
2148 sizet = builtin_decl_explicit (BUILT_IN_OBJECT_SIZE);
kono
parents:
diff changeset
2149 sizet = build_call_expr_loc (loc, sizet, 2, base_addr,
kono
parents:
diff changeset
2150 integer_zero_node);
kono
parents:
diff changeset
2151 sizet = force_gimple_operand_gsi (gsi, sizet, false, NULL_TREE, true,
kono
parents:
diff changeset
2152 GSI_SAME_STMT);
kono
parents:
diff changeset
2153 /* If the call above didn't end up being an integer constant, go one
kono
parents:
diff changeset
2154 statement back and get the __builtin_object_size stmt. Save it,
kono
parents:
diff changeset
2155 we might need it later. */
kono
parents:
diff changeset
2156 if (SSA_VAR_P (sizet))
kono
parents:
diff changeset
2157 {
kono
parents:
diff changeset
2158 gsi_prev (gsi);
kono
parents:
diff changeset
2159 bos_stmt = gsi_stmt (*gsi);
kono
parents:
diff changeset
2160
kono
parents:
diff changeset
2161 /* Move on to where we were. */
kono
parents:
diff changeset
2162 gsi_next (gsi);
kono
parents:
diff changeset
2163 }
kono
parents:
diff changeset
2164 }
kono
parents:
diff changeset
2165 else
kono
parents:
diff changeset
2166 return;
kono
parents:
diff changeset
2167
kono
parents:
diff changeset
2168 /* Generate UBSAN_OBJECT_SIZE (ptr, ptr+sizeof(*ptr)-base, objsize, ckind)
kono
parents:
diff changeset
2169 call. */
kono
parents:
diff changeset
2170 /* ptr + sizeof (*ptr) - base */
kono
parents:
diff changeset
2171 t = fold_build2 (MINUS_EXPR, sizetype,
kono
parents:
diff changeset
2172 fold_convert (pointer_sized_int_node, ptr),
kono
parents:
diff changeset
2173 fold_convert (pointer_sized_int_node, base_addr));
kono
parents:
diff changeset
2174 t = fold_build2 (PLUS_EXPR, sizetype, t, TYPE_SIZE_UNIT (type));
kono
parents:
diff changeset
2175
kono
parents:
diff changeset
2176 /* Perhaps we can omit the check. */
kono
parents:
diff changeset
2177 if (TREE_CODE (t) == INTEGER_CST
kono
parents:
diff changeset
2178 && TREE_CODE (sizet) == INTEGER_CST
kono
parents:
diff changeset
2179 && tree_int_cst_le (t, sizet))
kono
parents:
diff changeset
2180 return;
kono
parents:
diff changeset
2181
kono
parents:
diff changeset
2182 if (index != NULL_TREE
kono
parents:
diff changeset
2183 && TREE_CODE (index) == SSA_NAME
kono
parents:
diff changeset
2184 && TREE_CODE (sizet) == INTEGER_CST)
kono
parents:
diff changeset
2185 {
kono
parents:
diff changeset
2186 gimple *def = SSA_NAME_DEF_STMT (index);
kono
parents:
diff changeset
2187 if (is_gimple_assign (def)
kono
parents:
diff changeset
2188 && gimple_assign_rhs_code (def) == BIT_AND_EXPR
kono
parents:
diff changeset
2189 && TREE_CODE (gimple_assign_rhs2 (def)) == INTEGER_CST)
kono
parents:
diff changeset
2190 {
kono
parents:
diff changeset
2191 tree cst = gimple_assign_rhs2 (def);
kono
parents:
diff changeset
2192 tree sz = fold_build2 (EXACT_DIV_EXPR, sizetype, sizet,
kono
parents:
diff changeset
2193 TYPE_SIZE_UNIT (type));
kono
parents:
diff changeset
2194 if (tree_int_cst_sgn (cst) >= 0
kono
parents:
diff changeset
2195 && tree_int_cst_lt (cst, sz))
kono
parents:
diff changeset
2196 return;
kono
parents:
diff changeset
2197 }
kono
parents:
diff changeset
2198 }
kono
parents:
diff changeset
2199
kono
parents:
diff changeset
2200 if (bos_stmt && gimple_call_builtin_p (bos_stmt, BUILT_IN_OBJECT_SIZE))
kono
parents:
diff changeset
2201 ubsan_create_edge (bos_stmt);
kono
parents:
diff changeset
2202
kono
parents:
diff changeset
2203 /* We have to emit the check. */
kono
parents:
diff changeset
2204 t = force_gimple_operand_gsi (gsi, t, true, NULL_TREE, true,
kono
parents:
diff changeset
2205 GSI_SAME_STMT);
kono
parents:
diff changeset
2206 ptr = force_gimple_operand_gsi (gsi, ptr, true, NULL_TREE, true,
kono
parents:
diff changeset
2207 GSI_SAME_STMT);
kono
parents:
diff changeset
2208 tree ckind = build_int_cst (unsigned_char_type_node,
kono
parents:
diff changeset
2209 is_lhs ? UBSAN_STORE_OF : UBSAN_LOAD_OF);
kono
parents:
diff changeset
2210 gimple *g = gimple_build_call_internal (IFN_UBSAN_OBJECT_SIZE, 4,
kono
parents:
diff changeset
2211 ptr, t, sizet, ckind);
kono
parents:
diff changeset
2212 gimple_set_location (g, loc);
kono
parents:
diff changeset
2213 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
2214 }
kono
parents:
diff changeset
2215
kono
parents:
diff changeset
2216 /* Instrument values passed to builtin functions. */
kono
parents:
diff changeset
2217
kono
parents:
diff changeset
2218 static void
kono
parents:
diff changeset
2219 instrument_builtin (gimple_stmt_iterator *gsi)
kono
parents:
diff changeset
2220 {
kono
parents:
diff changeset
2221 gimple *stmt = gsi_stmt (*gsi);
kono
parents:
diff changeset
2222 location_t loc = gimple_location (stmt);
kono
parents:
diff changeset
2223 tree arg;
kono
parents:
diff changeset
2224 enum built_in_function fcode
kono
parents:
diff changeset
2225 = DECL_FUNCTION_CODE (gimple_call_fndecl (stmt));
kono
parents:
diff changeset
2226 int kind = 0;
kono
parents:
diff changeset
2227 switch (fcode)
kono
parents:
diff changeset
2228 {
kono
parents:
diff changeset
2229 CASE_INT_FN (BUILT_IN_CLZ):
kono
parents:
diff changeset
2230 kind = 1;
kono
parents:
diff changeset
2231 gcc_fallthrough ();
kono
parents:
diff changeset
2232 CASE_INT_FN (BUILT_IN_CTZ):
kono
parents:
diff changeset
2233 arg = gimple_call_arg (stmt, 0);
kono
parents:
diff changeset
2234 if (!integer_nonzerop (arg))
kono
parents:
diff changeset
2235 {
kono
parents:
diff changeset
2236 gimple *g;
kono
parents:
diff changeset
2237 if (!is_gimple_val (arg))
kono
parents:
diff changeset
2238 {
kono
parents:
diff changeset
2239 g = gimple_build_assign (make_ssa_name (TREE_TYPE (arg)), arg);
kono
parents:
diff changeset
2240 gimple_set_location (g, loc);
kono
parents:
diff changeset
2241 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
2242 arg = gimple_assign_lhs (g);
kono
parents:
diff changeset
2243 }
kono
parents:
diff changeset
2244
kono
parents:
diff changeset
2245 basic_block then_bb, fallthru_bb;
kono
parents:
diff changeset
2246 *gsi = create_cond_insert_point (gsi, true, false, true,
kono
parents:
diff changeset
2247 &then_bb, &fallthru_bb);
kono
parents:
diff changeset
2248 g = gimple_build_cond (EQ_EXPR, arg,
kono
parents:
diff changeset
2249 build_zero_cst (TREE_TYPE (arg)),
kono
parents:
diff changeset
2250 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
2251 gimple_set_location (g, loc);
kono
parents:
diff changeset
2252 gsi_insert_after (gsi, g, GSI_NEW_STMT);
kono
parents:
diff changeset
2253
kono
parents:
diff changeset
2254 *gsi = gsi_after_labels (then_bb);
kono
parents:
diff changeset
2255 if (flag_sanitize_undefined_trap_on_error)
kono
parents:
diff changeset
2256 g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
kono
parents:
diff changeset
2257 else
kono
parents:
diff changeset
2258 {
kono
parents:
diff changeset
2259 tree t = build_int_cst (unsigned_char_type_node, kind);
kono
parents:
diff changeset
2260 tree data = ubsan_create_data ("__ubsan_builtin_data",
kono
parents:
diff changeset
2261 1, &loc, NULL_TREE, t, NULL_TREE);
kono
parents:
diff changeset
2262 data = build_fold_addr_expr_loc (loc, data);
kono
parents:
diff changeset
2263 enum built_in_function bcode
kono
parents:
diff changeset
2264 = (flag_sanitize_recover & SANITIZE_BUILTIN)
kono
parents:
diff changeset
2265 ? BUILT_IN_UBSAN_HANDLE_INVALID_BUILTIN
kono
parents:
diff changeset
2266 : BUILT_IN_UBSAN_HANDLE_INVALID_BUILTIN_ABORT;
kono
parents:
diff changeset
2267 tree fn = builtin_decl_explicit (bcode);
kono
parents:
diff changeset
2268
kono
parents:
diff changeset
2269 g = gimple_build_call (fn, 1, data);
kono
parents:
diff changeset
2270 }
kono
parents:
diff changeset
2271 gimple_set_location (g, loc);
kono
parents:
diff changeset
2272 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
2273 ubsan_create_edge (g);
kono
parents:
diff changeset
2274 }
kono
parents:
diff changeset
2275 *gsi = gsi_for_stmt (stmt);
kono
parents:
diff changeset
2276 break;
kono
parents:
diff changeset
2277 default:
kono
parents:
diff changeset
2278 break;
kono
parents:
diff changeset
2279 }
kono
parents:
diff changeset
2280 }
kono
parents:
diff changeset
2281
kono
parents:
diff changeset
2282 namespace {
kono
parents:
diff changeset
2283
kono
parents:
diff changeset
2284 const pass_data pass_data_ubsan =
kono
parents:
diff changeset
2285 {
kono
parents:
diff changeset
2286 GIMPLE_PASS, /* type */
kono
parents:
diff changeset
2287 "ubsan", /* name */
kono
parents:
diff changeset
2288 OPTGROUP_NONE, /* optinfo_flags */
kono
parents:
diff changeset
2289 TV_TREE_UBSAN, /* tv_id */
kono
parents:
diff changeset
2290 ( PROP_cfg | PROP_ssa ), /* properties_required */
kono
parents:
diff changeset
2291 0, /* properties_provided */
kono
parents:
diff changeset
2292 0, /* properties_destroyed */
kono
parents:
diff changeset
2293 0, /* todo_flags_start */
kono
parents:
diff changeset
2294 TODO_update_ssa, /* todo_flags_finish */
kono
parents:
diff changeset
2295 };
kono
parents:
diff changeset
2296
kono
parents:
diff changeset
2297 class pass_ubsan : public gimple_opt_pass
kono
parents:
diff changeset
2298 {
kono
parents:
diff changeset
2299 public:
kono
parents:
diff changeset
2300 pass_ubsan (gcc::context *ctxt)
kono
parents:
diff changeset
2301 : gimple_opt_pass (pass_data_ubsan, ctxt)
kono
parents:
diff changeset
2302 {}
kono
parents:
diff changeset
2303
kono
parents:
diff changeset
2304 /* opt_pass methods: */
kono
parents:
diff changeset
2305 virtual bool gate (function *)
kono
parents:
diff changeset
2306 {
kono
parents:
diff changeset
2307 return sanitize_flags_p ((SANITIZE_NULL | SANITIZE_SI_OVERFLOW
kono
parents:
diff changeset
2308 | SANITIZE_BOOL | SANITIZE_ENUM
kono
parents:
diff changeset
2309 | SANITIZE_ALIGNMENT
kono
parents:
diff changeset
2310 | SANITIZE_NONNULL_ATTRIBUTE
kono
parents:
diff changeset
2311 | SANITIZE_RETURNS_NONNULL_ATTRIBUTE
kono
parents:
diff changeset
2312 | SANITIZE_OBJECT_SIZE
kono
parents:
diff changeset
2313 | SANITIZE_POINTER_OVERFLOW
kono
parents:
diff changeset
2314 | SANITIZE_BUILTIN));
kono
parents:
diff changeset
2315 }
kono
parents:
diff changeset
2316
kono
parents:
diff changeset
2317 virtual unsigned int execute (function *);
kono
parents:
diff changeset
2318
kono
parents:
diff changeset
2319 }; // class pass_ubsan
kono
parents:
diff changeset
2320
kono
parents:
diff changeset
2321 unsigned int
kono
parents:
diff changeset
2322 pass_ubsan::execute (function *fun)
kono
parents:
diff changeset
2323 {
kono
parents:
diff changeset
2324 basic_block bb;
kono
parents:
diff changeset
2325 gimple_stmt_iterator gsi;
kono
parents:
diff changeset
2326 unsigned int ret = 0;
kono
parents:
diff changeset
2327
kono
parents:
diff changeset
2328 initialize_sanitizer_builtins ();
kono
parents:
diff changeset
2329
kono
parents:
diff changeset
2330 FOR_EACH_BB_FN (bb, fun)
kono
parents:
diff changeset
2331 {
kono
parents:
diff changeset
2332 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
kono
parents:
diff changeset
2333 {
kono
parents:
diff changeset
2334 gimple *stmt = gsi_stmt (gsi);
kono
parents:
diff changeset
2335 if (is_gimple_debug (stmt) || gimple_clobber_p (stmt))
kono
parents:
diff changeset
2336 {
kono
parents:
diff changeset
2337 gsi_next (&gsi);
kono
parents:
diff changeset
2338 continue;
kono
parents:
diff changeset
2339 }
kono
parents:
diff changeset
2340
kono
parents:
diff changeset
2341 if ((sanitize_flags_p (SANITIZE_SI_OVERFLOW, fun->decl))
kono
parents:
diff changeset
2342 && is_gimple_assign (stmt))
kono
parents:
diff changeset
2343 instrument_si_overflow (gsi);
kono
parents:
diff changeset
2344
kono
parents:
diff changeset
2345 if (sanitize_flags_p (SANITIZE_NULL | SANITIZE_ALIGNMENT, fun->decl))
kono
parents:
diff changeset
2346 {
kono
parents:
diff changeset
2347 if (gimple_store_p (stmt))
kono
parents:
diff changeset
2348 instrument_null (gsi, gimple_get_lhs (stmt), true);
kono
parents:
diff changeset
2349 if (gimple_assign_single_p (stmt))
kono
parents:
diff changeset
2350 instrument_null (gsi, gimple_assign_rhs1 (stmt), false);
kono
parents:
diff changeset
2351 if (is_gimple_call (stmt))
kono
parents:
diff changeset
2352 {
kono
parents:
diff changeset
2353 unsigned args_num = gimple_call_num_args (stmt);
kono
parents:
diff changeset
2354 for (unsigned i = 0; i < args_num; ++i)
kono
parents:
diff changeset
2355 {
kono
parents:
diff changeset
2356 tree arg = gimple_call_arg (stmt, i);
kono
parents:
diff changeset
2357 if (is_gimple_reg (arg) || is_gimple_min_invariant (arg))
kono
parents:
diff changeset
2358 continue;
kono
parents:
diff changeset
2359 instrument_null (gsi, arg, false);
kono
parents:
diff changeset
2360 }
kono
parents:
diff changeset
2361 }
kono
parents:
diff changeset
2362 }
kono
parents:
diff changeset
2363
kono
parents:
diff changeset
2364 if (sanitize_flags_p (SANITIZE_BOOL | SANITIZE_ENUM, fun->decl)
kono
parents:
diff changeset
2365 && gimple_assign_load_p (stmt))
kono
parents:
diff changeset
2366 {
kono
parents:
diff changeset
2367 instrument_bool_enum_load (&gsi);
kono
parents:
diff changeset
2368 bb = gimple_bb (stmt);
kono
parents:
diff changeset
2369 }
kono
parents:
diff changeset
2370
kono
parents:
diff changeset
2371 if (sanitize_flags_p (SANITIZE_NONNULL_ATTRIBUTE, fun->decl)
kono
parents:
diff changeset
2372 && is_gimple_call (stmt)
kono
parents:
diff changeset
2373 && !gimple_call_internal_p (stmt))
kono
parents:
diff changeset
2374 {
kono
parents:
diff changeset
2375 instrument_nonnull_arg (&gsi);
kono
parents:
diff changeset
2376 bb = gimple_bb (stmt);
kono
parents:
diff changeset
2377 }
kono
parents:
diff changeset
2378
kono
parents:
diff changeset
2379 if (sanitize_flags_p (SANITIZE_BUILTIN, fun->decl)
kono
parents:
diff changeset
2380 && gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
kono
parents:
diff changeset
2381 {
kono
parents:
diff changeset
2382 instrument_builtin (&gsi);
kono
parents:
diff changeset
2383 bb = gimple_bb (stmt);
kono
parents:
diff changeset
2384 }
kono
parents:
diff changeset
2385
kono
parents:
diff changeset
2386 if (sanitize_flags_p (SANITIZE_RETURNS_NONNULL_ATTRIBUTE, fun->decl)
kono
parents:
diff changeset
2387 && gimple_code (stmt) == GIMPLE_RETURN)
kono
parents:
diff changeset
2388 {
kono
parents:
diff changeset
2389 instrument_nonnull_return (&gsi);
kono
parents:
diff changeset
2390 bb = gimple_bb (stmt);
kono
parents:
diff changeset
2391 }
kono
parents:
diff changeset
2392
kono
parents:
diff changeset
2393 if (sanitize_flags_p (SANITIZE_OBJECT_SIZE, fun->decl))
kono
parents:
diff changeset
2394 {
kono
parents:
diff changeset
2395 if (gimple_store_p (stmt))
kono
parents:
diff changeset
2396 instrument_object_size (&gsi, gimple_get_lhs (stmt), true);
kono
parents:
diff changeset
2397 if (gimple_assign_load_p (stmt))
kono
parents:
diff changeset
2398 instrument_object_size (&gsi, gimple_assign_rhs1 (stmt),
kono
parents:
diff changeset
2399 false);
kono
parents:
diff changeset
2400 if (is_gimple_call (stmt))
kono
parents:
diff changeset
2401 {
kono
parents:
diff changeset
2402 unsigned args_num = gimple_call_num_args (stmt);
kono
parents:
diff changeset
2403 for (unsigned i = 0; i < args_num; ++i)
kono
parents:
diff changeset
2404 {
kono
parents:
diff changeset
2405 tree arg = gimple_call_arg (stmt, i);
kono
parents:
diff changeset
2406 if (is_gimple_reg (arg) || is_gimple_min_invariant (arg))
kono
parents:
diff changeset
2407 continue;
kono
parents:
diff changeset
2408 instrument_object_size (&gsi, arg, false);
kono
parents:
diff changeset
2409 }
kono
parents:
diff changeset
2410 }
kono
parents:
diff changeset
2411 }
kono
parents:
diff changeset
2412
kono
parents:
diff changeset
2413 if (sanitize_flags_p (SANITIZE_POINTER_OVERFLOW, fun->decl))
kono
parents:
diff changeset
2414 {
kono
parents:
diff changeset
2415 if (is_gimple_assign (stmt)
kono
parents:
diff changeset
2416 && gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
kono
parents:
diff changeset
2417 instrument_pointer_overflow (&gsi,
kono
parents:
diff changeset
2418 gimple_assign_rhs1 (stmt),
kono
parents:
diff changeset
2419 gimple_assign_rhs2 (stmt));
kono
parents:
diff changeset
2420 if (gimple_store_p (stmt))
kono
parents:
diff changeset
2421 maybe_instrument_pointer_overflow (&gsi,
kono
parents:
diff changeset
2422 gimple_get_lhs (stmt));
kono
parents:
diff changeset
2423 if (gimple_assign_single_p (stmt))
kono
parents:
diff changeset
2424 maybe_instrument_pointer_overflow (&gsi,
kono
parents:
diff changeset
2425 gimple_assign_rhs1 (stmt));
kono
parents:
diff changeset
2426 if (is_gimple_call (stmt))
kono
parents:
diff changeset
2427 {
kono
parents:
diff changeset
2428 unsigned args_num = gimple_call_num_args (stmt);
kono
parents:
diff changeset
2429 for (unsigned i = 0; i < args_num; ++i)
kono
parents:
diff changeset
2430 {
kono
parents:
diff changeset
2431 tree arg = gimple_call_arg (stmt, i);
kono
parents:
diff changeset
2432 if (is_gimple_reg (arg))
kono
parents:
diff changeset
2433 continue;
kono
parents:
diff changeset
2434 maybe_instrument_pointer_overflow (&gsi, arg);
kono
parents:
diff changeset
2435 }
kono
parents:
diff changeset
2436 }
kono
parents:
diff changeset
2437 }
kono
parents:
diff changeset
2438
kono
parents:
diff changeset
2439 gsi_next (&gsi);
kono
parents:
diff changeset
2440 }
kono
parents:
diff changeset
2441 if (gimple_purge_dead_eh_edges (bb))
kono
parents:
diff changeset
2442 ret = TODO_cleanup_cfg;
kono
parents:
diff changeset
2443 }
kono
parents:
diff changeset
2444 return ret;
kono
parents:
diff changeset
2445 }
kono
parents:
diff changeset
2446
kono
parents:
diff changeset
2447 } // anon namespace
kono
parents:
diff changeset
2448
kono
parents:
diff changeset
2449 gimple_opt_pass *
kono
parents:
diff changeset
2450 make_pass_ubsan (gcc::context *ctxt)
kono
parents:
diff changeset
2451 {
kono
parents:
diff changeset
2452 return new pass_ubsan (ctxt);
kono
parents:
diff changeset
2453 }
kono
parents:
diff changeset
2454
kono
parents:
diff changeset
2455 #include "gt-ubsan.h"