annotate gcc/ubsan.c @ 158:494b0b89df80 default tip

...
author Shinji KONO <kono@ie.u-ryukyu.ac.jp>
date Mon, 25 May 2020 18:13:55 +0900
parents 1830386684a0
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
111
kono
parents:
diff changeset
1 /* UndefinedBehaviorSanitizer, undefined behavior detector.
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
2 Copyright (C) 2013-2020 Free Software Foundation, Inc.
111
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 {
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
439 unsigned HOST_WIDE_INT m;
111
kono
parents:
diff changeset
440 if (tree_fits_uhwi_p (TYPE_MAX_VALUE (dom))
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
441 && (m = tree_to_uhwi (TYPE_MAX_VALUE (dom))) + 1 != 0)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
442 pp_unsigned_wide_integer (&pretty_name, m + 1);
111
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
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
666 && fndecl_built_in_p (t, BUILT_IN_NORMAL)
111
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 cgraph_node *node = cgraph_node::get (current_function_decl);
kono
parents:
diff changeset
679 tree decl = gimple_call_fndecl (call_stmt);
kono
parents:
diff changeset
680 if (decl)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
681 node->create_edge (cgraph_node::get_create (decl), call_stmt, bb->count);
111
kono
parents:
diff changeset
682 }
kono
parents:
diff changeset
683
kono
parents:
diff changeset
684 /* Expand the UBSAN_BOUNDS special builtin function. */
kono
parents:
diff changeset
685
kono
parents:
diff changeset
686 bool
kono
parents:
diff changeset
687 ubsan_expand_bounds_ifn (gimple_stmt_iterator *gsi)
kono
parents:
diff changeset
688 {
kono
parents:
diff changeset
689 gimple *stmt = gsi_stmt (*gsi);
kono
parents:
diff changeset
690 location_t loc = gimple_location (stmt);
kono
parents:
diff changeset
691 gcc_assert (gimple_call_num_args (stmt) == 3);
kono
parents:
diff changeset
692
kono
parents:
diff changeset
693 /* Pick up the arguments of the UBSAN_BOUNDS call. */
kono
parents:
diff changeset
694 tree type = TREE_TYPE (TREE_TYPE (gimple_call_arg (stmt, 0)));
kono
parents:
diff changeset
695 tree index = gimple_call_arg (stmt, 1);
kono
parents:
diff changeset
696 tree orig_index = index;
kono
parents:
diff changeset
697 tree bound = gimple_call_arg (stmt, 2);
kono
parents:
diff changeset
698
kono
parents:
diff changeset
699 gimple_stmt_iterator gsi_orig = *gsi;
kono
parents:
diff changeset
700
kono
parents:
diff changeset
701 /* Create condition "if (index > bound)". */
kono
parents:
diff changeset
702 basic_block then_bb, fallthru_bb;
kono
parents:
diff changeset
703 gimple_stmt_iterator cond_insert_point
kono
parents:
diff changeset
704 = create_cond_insert_point (gsi, false, false, true,
kono
parents:
diff changeset
705 &then_bb, &fallthru_bb);
kono
parents:
diff changeset
706 index = fold_convert (TREE_TYPE (bound), index);
kono
parents:
diff changeset
707 index = force_gimple_operand_gsi (&cond_insert_point, index,
kono
parents:
diff changeset
708 true, NULL_TREE,
kono
parents:
diff changeset
709 false, GSI_NEW_STMT);
kono
parents:
diff changeset
710 gimple *g = gimple_build_cond (GT_EXPR, index, bound, NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
711 gimple_set_location (g, loc);
kono
parents:
diff changeset
712 gsi_insert_after (&cond_insert_point, g, GSI_NEW_STMT);
kono
parents:
diff changeset
713
kono
parents:
diff changeset
714 /* Generate __ubsan_handle_out_of_bounds call. */
kono
parents:
diff changeset
715 *gsi = gsi_after_labels (then_bb);
kono
parents:
diff changeset
716 if (flag_sanitize_undefined_trap_on_error)
kono
parents:
diff changeset
717 g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
kono
parents:
diff changeset
718 else
kono
parents:
diff changeset
719 {
kono
parents:
diff changeset
720 tree data
kono
parents:
diff changeset
721 = ubsan_create_data ("__ubsan_out_of_bounds_data", 1, &loc,
kono
parents:
diff changeset
722 ubsan_type_descriptor (type, UBSAN_PRINT_ARRAY),
kono
parents:
diff changeset
723 ubsan_type_descriptor (TREE_TYPE (orig_index)),
kono
parents:
diff changeset
724 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
725 data = build_fold_addr_expr_loc (loc, data);
kono
parents:
diff changeset
726 enum built_in_function bcode
kono
parents:
diff changeset
727 = (flag_sanitize_recover & SANITIZE_BOUNDS)
kono
parents:
diff changeset
728 ? BUILT_IN_UBSAN_HANDLE_OUT_OF_BOUNDS
kono
parents:
diff changeset
729 : BUILT_IN_UBSAN_HANDLE_OUT_OF_BOUNDS_ABORT;
kono
parents:
diff changeset
730 tree fn = builtin_decl_explicit (bcode);
kono
parents:
diff changeset
731 tree val = ubsan_encode_value (orig_index, UBSAN_ENCODE_VALUE_GIMPLE);
kono
parents:
diff changeset
732 val = force_gimple_operand_gsi (gsi, val, true, NULL_TREE, true,
kono
parents:
diff changeset
733 GSI_SAME_STMT);
kono
parents:
diff changeset
734 g = gimple_build_call (fn, 2, data, val);
kono
parents:
diff changeset
735 }
kono
parents:
diff changeset
736 gimple_set_location (g, loc);
kono
parents:
diff changeset
737 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
738
kono
parents:
diff changeset
739 /* Get rid of the UBSAN_BOUNDS call from the IR. */
kono
parents:
diff changeset
740 unlink_stmt_vdef (stmt);
kono
parents:
diff changeset
741 gsi_remove (&gsi_orig, true);
kono
parents:
diff changeset
742
kono
parents:
diff changeset
743 /* Point GSI to next logical statement. */
kono
parents:
diff changeset
744 *gsi = gsi_start_bb (fallthru_bb);
kono
parents:
diff changeset
745 return true;
kono
parents:
diff changeset
746 }
kono
parents:
diff changeset
747
kono
parents:
diff changeset
748 /* Expand UBSAN_NULL internal call. The type is kept on the ckind
kono
parents:
diff changeset
749 argument which is a constant, because the middle-end treats pointer
kono
parents:
diff changeset
750 conversions as useless and therefore the type of the first argument
kono
parents:
diff changeset
751 could be changed to any other pointer type. */
kono
parents:
diff changeset
752
kono
parents:
diff changeset
753 bool
kono
parents:
diff changeset
754 ubsan_expand_null_ifn (gimple_stmt_iterator *gsip)
kono
parents:
diff changeset
755 {
kono
parents:
diff changeset
756 gimple_stmt_iterator gsi = *gsip;
kono
parents:
diff changeset
757 gimple *stmt = gsi_stmt (gsi);
kono
parents:
diff changeset
758 location_t loc = gimple_location (stmt);
kono
parents:
diff changeset
759 gcc_assert (gimple_call_num_args (stmt) == 3);
kono
parents:
diff changeset
760 tree ptr = gimple_call_arg (stmt, 0);
kono
parents:
diff changeset
761 tree ckind = gimple_call_arg (stmt, 1);
kono
parents:
diff changeset
762 tree align = gimple_call_arg (stmt, 2);
kono
parents:
diff changeset
763 tree check_align = NULL_TREE;
kono
parents:
diff changeset
764 bool check_null;
kono
parents:
diff changeset
765
kono
parents:
diff changeset
766 basic_block cur_bb = gsi_bb (gsi);
kono
parents:
diff changeset
767
kono
parents:
diff changeset
768 gimple *g;
kono
parents:
diff changeset
769 if (!integer_zerop (align))
kono
parents:
diff changeset
770 {
kono
parents:
diff changeset
771 unsigned int ptralign = get_pointer_alignment (ptr) / BITS_PER_UNIT;
kono
parents:
diff changeset
772 if (compare_tree_int (align, ptralign) == 1)
kono
parents:
diff changeset
773 {
kono
parents:
diff changeset
774 check_align = make_ssa_name (pointer_sized_int_node);
kono
parents:
diff changeset
775 g = gimple_build_assign (check_align, NOP_EXPR, ptr);
kono
parents:
diff changeset
776 gimple_set_location (g, loc);
kono
parents:
diff changeset
777 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
778 }
kono
parents:
diff changeset
779 }
kono
parents:
diff changeset
780 check_null = sanitize_flags_p (SANITIZE_NULL);
kono
parents:
diff changeset
781
kono
parents:
diff changeset
782 if (check_align == NULL_TREE && !check_null)
kono
parents:
diff changeset
783 {
kono
parents:
diff changeset
784 gsi_remove (gsip, true);
kono
parents:
diff changeset
785 /* Unlink the UBSAN_NULLs vops before replacing it. */
kono
parents:
diff changeset
786 unlink_stmt_vdef (stmt);
kono
parents:
diff changeset
787 return true;
kono
parents:
diff changeset
788 }
kono
parents:
diff changeset
789
kono
parents:
diff changeset
790 /* Split the original block holding the pointer dereference. */
kono
parents:
diff changeset
791 edge e = split_block (cur_bb, stmt);
kono
parents:
diff changeset
792
kono
parents:
diff changeset
793 /* Get a hold on the 'condition block', the 'then block' and the
kono
parents:
diff changeset
794 'else block'. */
kono
parents:
diff changeset
795 basic_block cond_bb = e->src;
kono
parents:
diff changeset
796 basic_block fallthru_bb = e->dest;
kono
parents:
diff changeset
797 basic_block then_bb = create_empty_bb (cond_bb);
kono
parents:
diff changeset
798 add_bb_to_loop (then_bb, cond_bb->loop_father);
kono
parents:
diff changeset
799 loops_state_set (LOOPS_NEED_FIXUP);
kono
parents:
diff changeset
800
kono
parents:
diff changeset
801 /* Make an edge coming from the 'cond block' into the 'then block';
kono
parents:
diff changeset
802 this edge is unlikely taken, so set up the probability accordingly. */
kono
parents:
diff changeset
803 e = make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
kono
parents:
diff changeset
804 e->probability = profile_probability::very_unlikely ();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
805 then_bb->count = e->count ();
111
kono
parents:
diff changeset
806
kono
parents:
diff changeset
807 /* Connect 'then block' with the 'else block'. This is needed
kono
parents:
diff changeset
808 as the ubsan routines we call in the 'then block' are not noreturn.
kono
parents:
diff changeset
809 The 'then block' only has one outcoming edge. */
kono
parents:
diff changeset
810 make_single_succ_edge (then_bb, fallthru_bb, EDGE_FALLTHRU);
kono
parents:
diff changeset
811
kono
parents:
diff changeset
812 /* Set up the fallthrough basic block. */
kono
parents:
diff changeset
813 e = find_edge (cond_bb, fallthru_bb);
kono
parents:
diff changeset
814 e->flags = EDGE_FALSE_VALUE;
kono
parents:
diff changeset
815 e->probability = profile_probability::very_likely ();
kono
parents:
diff changeset
816
kono
parents:
diff changeset
817 /* Update dominance info for the newly created then_bb; note that
kono
parents:
diff changeset
818 fallthru_bb's dominance info has already been updated by
kono
parents:
diff changeset
819 split_block. */
kono
parents:
diff changeset
820 if (dom_info_available_p (CDI_DOMINATORS))
kono
parents:
diff changeset
821 set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
kono
parents:
diff changeset
822
kono
parents:
diff changeset
823 /* Put the ubsan builtin call into the newly created BB. */
kono
parents:
diff changeset
824 if (flag_sanitize_undefined_trap_on_error)
kono
parents:
diff changeset
825 g = gimple_build_call (builtin_decl_implicit (BUILT_IN_TRAP), 0);
kono
parents:
diff changeset
826 else
kono
parents:
diff changeset
827 {
kono
parents:
diff changeset
828 enum built_in_function bcode
kono
parents:
diff changeset
829 = (flag_sanitize_recover & ((check_align ? SANITIZE_ALIGNMENT : 0)
kono
parents:
diff changeset
830 | (check_null ? SANITIZE_NULL : 0)))
kono
parents:
diff changeset
831 ? BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1
kono
parents:
diff changeset
832 : BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1_ABORT;
kono
parents:
diff changeset
833 tree fn = builtin_decl_implicit (bcode);
kono
parents:
diff changeset
834 int align_log = tree_log2 (align);
kono
parents:
diff changeset
835 tree data
kono
parents:
diff changeset
836 = ubsan_create_data ("__ubsan_null_data", 1, &loc,
kono
parents:
diff changeset
837 ubsan_type_descriptor (TREE_TYPE (ckind),
kono
parents:
diff changeset
838 UBSAN_PRINT_POINTER),
kono
parents:
diff changeset
839 NULL_TREE,
kono
parents:
diff changeset
840 build_int_cst (unsigned_char_type_node,
kono
parents:
diff changeset
841 MAX (align_log, 0)),
kono
parents:
diff changeset
842 fold_convert (unsigned_char_type_node, ckind),
kono
parents:
diff changeset
843 NULL_TREE);
kono
parents:
diff changeset
844 data = build_fold_addr_expr_loc (loc, data);
kono
parents:
diff changeset
845 g = gimple_build_call (fn, 2, data,
kono
parents:
diff changeset
846 check_align ? check_align
kono
parents:
diff changeset
847 : build_zero_cst (pointer_sized_int_node));
kono
parents:
diff changeset
848 }
kono
parents:
diff changeset
849 gimple_stmt_iterator gsi2 = gsi_start_bb (then_bb);
kono
parents:
diff changeset
850 gimple_set_location (g, loc);
kono
parents:
diff changeset
851 gsi_insert_after (&gsi2, g, GSI_NEW_STMT);
kono
parents:
diff changeset
852
kono
parents:
diff changeset
853 /* Unlink the UBSAN_NULLs vops before replacing it. */
kono
parents:
diff changeset
854 unlink_stmt_vdef (stmt);
kono
parents:
diff changeset
855
kono
parents:
diff changeset
856 if (check_null)
kono
parents:
diff changeset
857 {
kono
parents:
diff changeset
858 g = gimple_build_cond (EQ_EXPR, ptr, build_int_cst (TREE_TYPE (ptr), 0),
kono
parents:
diff changeset
859 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
860 gimple_set_location (g, loc);
kono
parents:
diff changeset
861
kono
parents:
diff changeset
862 /* Replace the UBSAN_NULL with a GIMPLE_COND stmt. */
kono
parents:
diff changeset
863 gsi_replace (&gsi, g, false);
kono
parents:
diff changeset
864 stmt = g;
kono
parents:
diff changeset
865 }
kono
parents:
diff changeset
866
kono
parents:
diff changeset
867 if (check_align)
kono
parents:
diff changeset
868 {
kono
parents:
diff changeset
869 if (check_null)
kono
parents:
diff changeset
870 {
kono
parents:
diff changeset
871 /* Split the block with the condition again. */
kono
parents:
diff changeset
872 e = split_block (cond_bb, stmt);
kono
parents:
diff changeset
873 basic_block cond1_bb = e->src;
kono
parents:
diff changeset
874 basic_block cond2_bb = e->dest;
kono
parents:
diff changeset
875
kono
parents:
diff changeset
876 /* Make an edge coming from the 'cond1 block' into the 'then block';
kono
parents:
diff changeset
877 this edge is unlikely taken, so set up the probability
kono
parents:
diff changeset
878 accordingly. */
kono
parents:
diff changeset
879 e = make_edge (cond1_bb, then_bb, EDGE_TRUE_VALUE);
kono
parents:
diff changeset
880 e->probability = profile_probability::very_unlikely ();
kono
parents:
diff changeset
881
kono
parents:
diff changeset
882 /* Set up the fallthrough basic block. */
kono
parents:
diff changeset
883 e = find_edge (cond1_bb, cond2_bb);
kono
parents:
diff changeset
884 e->flags = EDGE_FALSE_VALUE;
kono
parents:
diff changeset
885 e->probability = profile_probability::very_likely ();
kono
parents:
diff changeset
886
kono
parents:
diff changeset
887 /* Update dominance info. */
kono
parents:
diff changeset
888 if (dom_info_available_p (CDI_DOMINATORS))
kono
parents:
diff changeset
889 {
kono
parents:
diff changeset
890 set_immediate_dominator (CDI_DOMINATORS, fallthru_bb, cond1_bb);
kono
parents:
diff changeset
891 set_immediate_dominator (CDI_DOMINATORS, then_bb, cond1_bb);
kono
parents:
diff changeset
892 }
kono
parents:
diff changeset
893
kono
parents:
diff changeset
894 gsi2 = gsi_start_bb (cond2_bb);
kono
parents:
diff changeset
895 }
kono
parents:
diff changeset
896
kono
parents:
diff changeset
897 tree mask = build_int_cst (pointer_sized_int_node,
kono
parents:
diff changeset
898 tree_to_uhwi (align) - 1);
kono
parents:
diff changeset
899 g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
kono
parents:
diff changeset
900 BIT_AND_EXPR, check_align, mask);
kono
parents:
diff changeset
901 gimple_set_location (g, loc);
kono
parents:
diff changeset
902 if (check_null)
kono
parents:
diff changeset
903 gsi_insert_after (&gsi2, g, GSI_NEW_STMT);
kono
parents:
diff changeset
904 else
kono
parents:
diff changeset
905 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
906
kono
parents:
diff changeset
907 g = gimple_build_cond (NE_EXPR, gimple_assign_lhs (g),
kono
parents:
diff changeset
908 build_int_cst (pointer_sized_int_node, 0),
kono
parents:
diff changeset
909 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
910 gimple_set_location (g, loc);
kono
parents:
diff changeset
911 if (check_null)
kono
parents:
diff changeset
912 gsi_insert_after (&gsi2, g, GSI_NEW_STMT);
kono
parents:
diff changeset
913 else
kono
parents:
diff changeset
914 /* Replace the UBSAN_NULL with a GIMPLE_COND stmt. */
kono
parents:
diff changeset
915 gsi_replace (&gsi, g, false);
kono
parents:
diff changeset
916 }
kono
parents:
diff changeset
917 return false;
kono
parents:
diff changeset
918 }
kono
parents:
diff changeset
919
kono
parents:
diff changeset
920 #define OBJSZ_MAX_OFFSET (1024 * 16)
kono
parents:
diff changeset
921
kono
parents:
diff changeset
922 /* Expand UBSAN_OBJECT_SIZE internal call. */
kono
parents:
diff changeset
923
kono
parents:
diff changeset
924 bool
kono
parents:
diff changeset
925 ubsan_expand_objsize_ifn (gimple_stmt_iterator *gsi)
kono
parents:
diff changeset
926 {
kono
parents:
diff changeset
927 gimple *stmt = gsi_stmt (*gsi);
kono
parents:
diff changeset
928 location_t loc = gimple_location (stmt);
kono
parents:
diff changeset
929 gcc_assert (gimple_call_num_args (stmt) == 4);
kono
parents:
diff changeset
930
kono
parents:
diff changeset
931 tree ptr = gimple_call_arg (stmt, 0);
kono
parents:
diff changeset
932 tree offset = gimple_call_arg (stmt, 1);
kono
parents:
diff changeset
933 tree size = gimple_call_arg (stmt, 2);
kono
parents:
diff changeset
934 tree ckind = gimple_call_arg (stmt, 3);
kono
parents:
diff changeset
935 gimple_stmt_iterator gsi_orig = *gsi;
kono
parents:
diff changeset
936 gimple *g;
kono
parents:
diff changeset
937
kono
parents:
diff changeset
938 /* See if we can discard the check. */
kono
parents:
diff changeset
939 if (TREE_CODE (size) != INTEGER_CST
kono
parents:
diff changeset
940 || integer_all_onesp (size))
kono
parents:
diff changeset
941 /* Yes, __builtin_object_size couldn't determine the
kono
parents:
diff changeset
942 object size. */;
kono
parents:
diff changeset
943 else if (TREE_CODE (offset) == INTEGER_CST
kono
parents:
diff changeset
944 && wi::to_widest (offset) >= -OBJSZ_MAX_OFFSET
kono
parents:
diff changeset
945 && wi::to_widest (offset) <= -1)
kono
parents:
diff changeset
946 /* The offset is in range [-16K, -1]. */;
kono
parents:
diff changeset
947 else
kono
parents:
diff changeset
948 {
kono
parents:
diff changeset
949 /* if (offset > objsize) */
kono
parents:
diff changeset
950 basic_block then_bb, fallthru_bb;
kono
parents:
diff changeset
951 gimple_stmt_iterator cond_insert_point
kono
parents:
diff changeset
952 = create_cond_insert_point (gsi, false, false, true,
kono
parents:
diff changeset
953 &then_bb, &fallthru_bb);
kono
parents:
diff changeset
954 g = gimple_build_cond (GT_EXPR, offset, size, NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
955 gimple_set_location (g, loc);
kono
parents:
diff changeset
956 gsi_insert_after (&cond_insert_point, g, GSI_NEW_STMT);
kono
parents:
diff changeset
957
kono
parents:
diff changeset
958 /* If the offset is small enough, we don't need the second
kono
parents:
diff changeset
959 run-time check. */
kono
parents:
diff changeset
960 if (TREE_CODE (offset) == INTEGER_CST
kono
parents:
diff changeset
961 && wi::to_widest (offset) >= 0
kono
parents:
diff changeset
962 && wi::to_widest (offset) <= OBJSZ_MAX_OFFSET)
kono
parents:
diff changeset
963 *gsi = gsi_after_labels (then_bb);
kono
parents:
diff changeset
964 else
kono
parents:
diff changeset
965 {
kono
parents:
diff changeset
966 /* Don't issue run-time error if (ptr > ptr + offset). That
kono
parents:
diff changeset
967 may happen when computing a POINTER_PLUS_EXPR. */
kono
parents:
diff changeset
968 basic_block then2_bb, fallthru2_bb;
kono
parents:
diff changeset
969
kono
parents:
diff changeset
970 gimple_stmt_iterator gsi2 = gsi_after_labels (then_bb);
kono
parents:
diff changeset
971 cond_insert_point = create_cond_insert_point (&gsi2, false, false,
kono
parents:
diff changeset
972 true, &then2_bb,
kono
parents:
diff changeset
973 &fallthru2_bb);
kono
parents:
diff changeset
974 /* Convert the pointer to an integer type. */
kono
parents:
diff changeset
975 tree p = make_ssa_name (pointer_sized_int_node);
kono
parents:
diff changeset
976 g = gimple_build_assign (p, NOP_EXPR, ptr);
kono
parents:
diff changeset
977 gimple_set_location (g, loc);
kono
parents:
diff changeset
978 gsi_insert_before (&cond_insert_point, g, GSI_NEW_STMT);
kono
parents:
diff changeset
979 p = gimple_assign_lhs (g);
kono
parents:
diff changeset
980 /* Compute ptr + offset. */
kono
parents:
diff changeset
981 g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
kono
parents:
diff changeset
982 PLUS_EXPR, p, offset);
kono
parents:
diff changeset
983 gimple_set_location (g, loc);
kono
parents:
diff changeset
984 gsi_insert_after (&cond_insert_point, g, GSI_NEW_STMT);
kono
parents:
diff changeset
985 /* Now build the conditional and put it into the IR. */
kono
parents:
diff changeset
986 g = gimple_build_cond (LE_EXPR, p, gimple_assign_lhs (g),
kono
parents:
diff changeset
987 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
988 gimple_set_location (g, loc);
kono
parents:
diff changeset
989 gsi_insert_after (&cond_insert_point, g, GSI_NEW_STMT);
kono
parents:
diff changeset
990 *gsi = gsi_after_labels (then2_bb);
kono
parents:
diff changeset
991 }
kono
parents:
diff changeset
992
kono
parents:
diff changeset
993 /* Generate __ubsan_handle_type_mismatch call. */
kono
parents:
diff changeset
994 if (flag_sanitize_undefined_trap_on_error)
kono
parents:
diff changeset
995 g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
kono
parents:
diff changeset
996 else
kono
parents:
diff changeset
997 {
kono
parents:
diff changeset
998 tree data
kono
parents:
diff changeset
999 = ubsan_create_data ("__ubsan_objsz_data", 1, &loc,
kono
parents:
diff changeset
1000 ubsan_type_descriptor (TREE_TYPE (ptr),
kono
parents:
diff changeset
1001 UBSAN_PRINT_POINTER),
kono
parents:
diff changeset
1002 NULL_TREE,
kono
parents:
diff changeset
1003 build_zero_cst (unsigned_char_type_node),
kono
parents:
diff changeset
1004 ckind,
kono
parents:
diff changeset
1005 NULL_TREE);
kono
parents:
diff changeset
1006 data = build_fold_addr_expr_loc (loc, data);
kono
parents:
diff changeset
1007 enum built_in_function bcode
kono
parents:
diff changeset
1008 = (flag_sanitize_recover & SANITIZE_OBJECT_SIZE)
kono
parents:
diff changeset
1009 ? BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1
kono
parents:
diff changeset
1010 : BUILT_IN_UBSAN_HANDLE_TYPE_MISMATCH_V1_ABORT;
kono
parents:
diff changeset
1011 tree p = make_ssa_name (pointer_sized_int_node);
kono
parents:
diff changeset
1012 g = gimple_build_assign (p, NOP_EXPR, ptr);
kono
parents:
diff changeset
1013 gimple_set_location (g, loc);
kono
parents:
diff changeset
1014 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1015 g = gimple_build_call (builtin_decl_explicit (bcode), 2, data, p);
kono
parents:
diff changeset
1016 }
kono
parents:
diff changeset
1017 gimple_set_location (g, loc);
kono
parents:
diff changeset
1018 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1019
kono
parents:
diff changeset
1020 /* Point GSI to next logical statement. */
kono
parents:
diff changeset
1021 *gsi = gsi_start_bb (fallthru_bb);
kono
parents:
diff changeset
1022
kono
parents:
diff changeset
1023 /* Get rid of the UBSAN_OBJECT_SIZE call from the IR. */
kono
parents:
diff changeset
1024 unlink_stmt_vdef (stmt);
kono
parents:
diff changeset
1025 gsi_remove (&gsi_orig, true);
kono
parents:
diff changeset
1026 return true;
kono
parents:
diff changeset
1027 }
kono
parents:
diff changeset
1028
kono
parents:
diff changeset
1029 /* Get rid of the UBSAN_OBJECT_SIZE call from the IR. */
kono
parents:
diff changeset
1030 unlink_stmt_vdef (stmt);
kono
parents:
diff changeset
1031 gsi_remove (gsi, true);
kono
parents:
diff changeset
1032 return true;
kono
parents:
diff changeset
1033 }
kono
parents:
diff changeset
1034
kono
parents:
diff changeset
1035 /* Expand UBSAN_PTR internal call. */
kono
parents:
diff changeset
1036
kono
parents:
diff changeset
1037 bool
kono
parents:
diff changeset
1038 ubsan_expand_ptr_ifn (gimple_stmt_iterator *gsip)
kono
parents:
diff changeset
1039 {
kono
parents:
diff changeset
1040 gimple_stmt_iterator gsi = *gsip;
kono
parents:
diff changeset
1041 gimple *stmt = gsi_stmt (gsi);
kono
parents:
diff changeset
1042 location_t loc = gimple_location (stmt);
kono
parents:
diff changeset
1043 gcc_assert (gimple_call_num_args (stmt) == 2);
kono
parents:
diff changeset
1044 tree ptr = gimple_call_arg (stmt, 0);
kono
parents:
diff changeset
1045 tree off = gimple_call_arg (stmt, 1);
kono
parents:
diff changeset
1046
kono
parents:
diff changeset
1047 if (integer_zerop (off))
kono
parents:
diff changeset
1048 {
kono
parents:
diff changeset
1049 gsi_remove (gsip, true);
kono
parents:
diff changeset
1050 unlink_stmt_vdef (stmt);
kono
parents:
diff changeset
1051 return true;
kono
parents:
diff changeset
1052 }
kono
parents:
diff changeset
1053
kono
parents:
diff changeset
1054 basic_block cur_bb = gsi_bb (gsi);
kono
parents:
diff changeset
1055 tree ptrplusoff = make_ssa_name (pointer_sized_int_node);
kono
parents:
diff changeset
1056 tree ptri = make_ssa_name (pointer_sized_int_node);
kono
parents:
diff changeset
1057 int pos_neg = get_range_pos_neg (off);
kono
parents:
diff changeset
1058
kono
parents:
diff changeset
1059 /* Split the original block holding the pointer dereference. */
kono
parents:
diff changeset
1060 edge e = split_block (cur_bb, stmt);
kono
parents:
diff changeset
1061
kono
parents:
diff changeset
1062 /* Get a hold on the 'condition block', the 'then block' and the
kono
parents:
diff changeset
1063 'else block'. */
kono
parents:
diff changeset
1064 basic_block cond_bb = e->src;
kono
parents:
diff changeset
1065 basic_block fallthru_bb = e->dest;
kono
parents:
diff changeset
1066 basic_block then_bb = create_empty_bb (cond_bb);
kono
parents:
diff changeset
1067 basic_block cond_pos_bb = NULL, cond_neg_bb = NULL;
kono
parents:
diff changeset
1068 add_bb_to_loop (then_bb, cond_bb->loop_father);
kono
parents:
diff changeset
1069 loops_state_set (LOOPS_NEED_FIXUP);
kono
parents:
diff changeset
1070
kono
parents:
diff changeset
1071 /* Set up the fallthrough basic block. */
kono
parents:
diff changeset
1072 e->flags = EDGE_FALSE_VALUE;
kono
parents:
diff changeset
1073 if (pos_neg != 3)
kono
parents:
diff changeset
1074 {
kono
parents:
diff changeset
1075 e->probability = profile_probability::very_likely ();
kono
parents:
diff changeset
1076
kono
parents:
diff changeset
1077 /* Connect 'then block' with the 'else block'. This is needed
kono
parents:
diff changeset
1078 as the ubsan routines we call in the 'then block' are not noreturn.
kono
parents:
diff changeset
1079 The 'then block' only has one outcoming edge. */
kono
parents:
diff changeset
1080 make_single_succ_edge (then_bb, fallthru_bb, EDGE_FALLTHRU);
kono
parents:
diff changeset
1081
kono
parents:
diff changeset
1082 /* Make an edge coming from the 'cond block' into the 'then block';
kono
parents:
diff changeset
1083 this edge is unlikely taken, so set up the probability
kono
parents:
diff changeset
1084 accordingly. */
kono
parents:
diff changeset
1085 e = make_edge (cond_bb, then_bb, EDGE_TRUE_VALUE);
kono
parents:
diff changeset
1086 e->probability = profile_probability::very_unlikely ();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1087 then_bb->count = e->count ();
111
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 ();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1101 then_bb->count = e->count ();
111
kono
parents:
diff changeset
1102
kono
parents:
diff changeset
1103 cond_pos_bb = create_empty_bb (cond_bb);
kono
parents:
diff changeset
1104 add_bb_to_loop (cond_pos_bb, cond_bb->loop_father);
kono
parents:
diff changeset
1105
kono
parents:
diff changeset
1106 e = make_edge (cond_bb, cond_pos_bb, EDGE_TRUE_VALUE);
kono
parents:
diff changeset
1107 e->probability = profile_probability::even ();
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1108 cond_pos_bb->count = e->count ();
111
kono
parents:
diff changeset
1109
kono
parents:
diff changeset
1110 e = make_edge (cond_pos_bb, then_bb, EDGE_TRUE_VALUE);
kono
parents:
diff changeset
1111 e->probability = profile_probability::very_unlikely ();
kono
parents:
diff changeset
1112
kono
parents:
diff changeset
1113 e = make_edge (cond_pos_bb, fallthru_bb, EDGE_FALSE_VALUE);
kono
parents:
diff changeset
1114 e->probability = profile_probability::very_likely ();
kono
parents:
diff changeset
1115
kono
parents:
diff changeset
1116 make_single_succ_edge (then_bb, fallthru_bb, EDGE_FALLTHRU);
kono
parents:
diff changeset
1117 }
kono
parents:
diff changeset
1118
kono
parents:
diff changeset
1119 gimple *g = gimple_build_assign (ptri, NOP_EXPR, ptr);
kono
parents:
diff changeset
1120 gimple_set_location (g, loc);
kono
parents:
diff changeset
1121 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1122 g = gimple_build_assign (ptrplusoff, PLUS_EXPR, ptri, off);
kono
parents:
diff changeset
1123 gimple_set_location (g, loc);
kono
parents:
diff changeset
1124 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1125
kono
parents:
diff changeset
1126 /* Update dominance info for the newly created then_bb; note that
kono
parents:
diff changeset
1127 fallthru_bb's dominance info has already been updated by
kono
parents:
diff changeset
1128 split_block. */
kono
parents:
diff changeset
1129 if (dom_info_available_p (CDI_DOMINATORS))
kono
parents:
diff changeset
1130 {
kono
parents:
diff changeset
1131 set_immediate_dominator (CDI_DOMINATORS, then_bb, cond_bb);
kono
parents:
diff changeset
1132 if (pos_neg == 3)
kono
parents:
diff changeset
1133 {
kono
parents:
diff changeset
1134 set_immediate_dominator (CDI_DOMINATORS, cond_pos_bb, cond_bb);
kono
parents:
diff changeset
1135 set_immediate_dominator (CDI_DOMINATORS, fallthru_bb, cond_bb);
kono
parents:
diff changeset
1136 }
kono
parents:
diff changeset
1137 }
kono
parents:
diff changeset
1138
kono
parents:
diff changeset
1139 /* Put the ubsan builtin call into the newly created BB. */
kono
parents:
diff changeset
1140 if (flag_sanitize_undefined_trap_on_error)
kono
parents:
diff changeset
1141 g = gimple_build_call (builtin_decl_implicit (BUILT_IN_TRAP), 0);
kono
parents:
diff changeset
1142 else
kono
parents:
diff changeset
1143 {
kono
parents:
diff changeset
1144 enum built_in_function bcode
kono
parents:
diff changeset
1145 = (flag_sanitize_recover & SANITIZE_POINTER_OVERFLOW)
kono
parents:
diff changeset
1146 ? BUILT_IN_UBSAN_HANDLE_POINTER_OVERFLOW
kono
parents:
diff changeset
1147 : BUILT_IN_UBSAN_HANDLE_POINTER_OVERFLOW_ABORT;
kono
parents:
diff changeset
1148 tree fn = builtin_decl_implicit (bcode);
kono
parents:
diff changeset
1149 tree data
kono
parents:
diff changeset
1150 = ubsan_create_data ("__ubsan_ptrovf_data", 1, &loc,
kono
parents:
diff changeset
1151 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
1152 data = build_fold_addr_expr_loc (loc, data);
kono
parents:
diff changeset
1153 g = gimple_build_call (fn, 3, data, ptr, ptrplusoff);
kono
parents:
diff changeset
1154 }
kono
parents:
diff changeset
1155 gimple_stmt_iterator gsi2 = gsi_start_bb (then_bb);
kono
parents:
diff changeset
1156 gimple_set_location (g, loc);
kono
parents:
diff changeset
1157 gsi_insert_after (&gsi2, g, GSI_NEW_STMT);
kono
parents:
diff changeset
1158
kono
parents:
diff changeset
1159 /* Unlink the UBSAN_PTRs vops before replacing it. */
kono
parents:
diff changeset
1160 unlink_stmt_vdef (stmt);
kono
parents:
diff changeset
1161
kono
parents:
diff changeset
1162 if (TREE_CODE (off) == INTEGER_CST)
kono
parents:
diff changeset
1163 g = gimple_build_cond (wi::neg_p (wi::to_wide (off)) ? LT_EXPR : GE_EXPR,
kono
parents:
diff changeset
1164 ptri, fold_build1 (NEGATE_EXPR, sizetype, off),
kono
parents:
diff changeset
1165 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
1166 else if (pos_neg != 3)
kono
parents:
diff changeset
1167 g = gimple_build_cond (pos_neg == 1 ? LT_EXPR : GT_EXPR,
kono
parents:
diff changeset
1168 ptrplusoff, ptri, NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
1169 else
kono
parents:
diff changeset
1170 {
kono
parents:
diff changeset
1171 gsi2 = gsi_start_bb (cond_pos_bb);
kono
parents:
diff changeset
1172 g = gimple_build_cond (LT_EXPR, ptrplusoff, ptri, NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
1173 gimple_set_location (g, loc);
kono
parents:
diff changeset
1174 gsi_insert_after (&gsi2, g, GSI_NEW_STMT);
kono
parents:
diff changeset
1175
kono
parents:
diff changeset
1176 gsi2 = gsi_start_bb (cond_neg_bb);
kono
parents:
diff changeset
1177 g = gimple_build_cond (GT_EXPR, ptrplusoff, ptri, NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
1178 gimple_set_location (g, loc);
kono
parents:
diff changeset
1179 gsi_insert_after (&gsi2, g, GSI_NEW_STMT);
kono
parents:
diff changeset
1180
kono
parents:
diff changeset
1181 gimple_seq seq = NULL;
kono
parents:
diff changeset
1182 tree t = gimple_build (&seq, loc, NOP_EXPR, ssizetype, off);
kono
parents:
diff changeset
1183 t = gimple_build (&seq, loc, GE_EXPR, boolean_type_node,
kono
parents:
diff changeset
1184 t, ssize_int (0));
kono
parents:
diff changeset
1185 gsi_insert_seq_before (&gsi, seq, GSI_SAME_STMT);
kono
parents:
diff changeset
1186 g = gimple_build_cond (NE_EXPR, t, boolean_false_node,
kono
parents:
diff changeset
1187 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
1188 }
kono
parents:
diff changeset
1189 gimple_set_location (g, loc);
kono
parents:
diff changeset
1190 /* Replace the UBSAN_PTR with a GIMPLE_COND stmt. */
kono
parents:
diff changeset
1191 gsi_replace (&gsi, g, false);
kono
parents:
diff changeset
1192 return false;
kono
parents:
diff changeset
1193 }
kono
parents:
diff changeset
1194
kono
parents:
diff changeset
1195
kono
parents:
diff changeset
1196 /* Cached __ubsan_vptr_type_cache decl. */
kono
parents:
diff changeset
1197 static GTY(()) tree ubsan_vptr_type_cache_decl;
kono
parents:
diff changeset
1198
kono
parents:
diff changeset
1199 /* Expand UBSAN_VPTR internal call. The type is kept on the ckind
kono
parents:
diff changeset
1200 argument which is a constant, because the middle-end treats pointer
kono
parents:
diff changeset
1201 conversions as useless and therefore the type of the first argument
kono
parents:
diff changeset
1202 could be changed to any other pointer type. */
kono
parents:
diff changeset
1203
kono
parents:
diff changeset
1204 bool
kono
parents:
diff changeset
1205 ubsan_expand_vptr_ifn (gimple_stmt_iterator *gsip)
kono
parents:
diff changeset
1206 {
kono
parents:
diff changeset
1207 gimple_stmt_iterator gsi = *gsip;
kono
parents:
diff changeset
1208 gimple *stmt = gsi_stmt (gsi);
kono
parents:
diff changeset
1209 location_t loc = gimple_location (stmt);
kono
parents:
diff changeset
1210 gcc_assert (gimple_call_num_args (stmt) == 5);
kono
parents:
diff changeset
1211 tree op = gimple_call_arg (stmt, 0);
kono
parents:
diff changeset
1212 tree vptr = gimple_call_arg (stmt, 1);
kono
parents:
diff changeset
1213 tree str_hash = gimple_call_arg (stmt, 2);
kono
parents:
diff changeset
1214 tree ti_decl_addr = gimple_call_arg (stmt, 3);
kono
parents:
diff changeset
1215 tree ckind_tree = gimple_call_arg (stmt, 4);
kono
parents:
diff changeset
1216 ubsan_null_ckind ckind = (ubsan_null_ckind) tree_to_uhwi (ckind_tree);
kono
parents:
diff changeset
1217 tree type = TREE_TYPE (TREE_TYPE (ckind_tree));
kono
parents:
diff changeset
1218 gimple *g;
kono
parents:
diff changeset
1219 basic_block fallthru_bb = NULL;
kono
parents:
diff changeset
1220
kono
parents:
diff changeset
1221 if (ckind == UBSAN_DOWNCAST_POINTER)
kono
parents:
diff changeset
1222 {
kono
parents:
diff changeset
1223 /* Guard everything with if (op != NULL) { ... }. */
kono
parents:
diff changeset
1224 basic_block then_bb;
kono
parents:
diff changeset
1225 gimple_stmt_iterator cond_insert_point
kono
parents:
diff changeset
1226 = create_cond_insert_point (gsip, false, false, true,
kono
parents:
diff changeset
1227 &then_bb, &fallthru_bb);
kono
parents:
diff changeset
1228 g = gimple_build_cond (NE_EXPR, op, build_zero_cst (TREE_TYPE (op)),
kono
parents:
diff changeset
1229 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
1230 gimple_set_location (g, loc);
kono
parents:
diff changeset
1231 gsi_insert_after (&cond_insert_point, g, GSI_NEW_STMT);
kono
parents:
diff changeset
1232 *gsip = gsi_after_labels (then_bb);
kono
parents:
diff changeset
1233 gsi_remove (&gsi, false);
kono
parents:
diff changeset
1234 gsi_insert_before (gsip, stmt, GSI_NEW_STMT);
kono
parents:
diff changeset
1235 gsi = *gsip;
kono
parents:
diff changeset
1236 }
kono
parents:
diff changeset
1237
kono
parents:
diff changeset
1238 tree htype = TREE_TYPE (str_hash);
kono
parents:
diff changeset
1239 tree cst = wide_int_to_tree (htype,
kono
parents:
diff changeset
1240 wi::uhwi (((uint64_t) 0x9ddfea08 << 32)
kono
parents:
diff changeset
1241 | 0xeb382d69, 64));
kono
parents:
diff changeset
1242 g = gimple_build_assign (make_ssa_name (htype), BIT_XOR_EXPR,
kono
parents:
diff changeset
1243 vptr, str_hash);
kono
parents:
diff changeset
1244 gimple_set_location (g, loc);
kono
parents:
diff changeset
1245 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1246 g = gimple_build_assign (make_ssa_name (htype), MULT_EXPR,
kono
parents:
diff changeset
1247 gimple_assign_lhs (g), cst);
kono
parents:
diff changeset
1248 gimple_set_location (g, loc);
kono
parents:
diff changeset
1249 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1250 tree t1 = gimple_assign_lhs (g);
kono
parents:
diff changeset
1251 g = gimple_build_assign (make_ssa_name (htype), LSHIFT_EXPR,
kono
parents:
diff changeset
1252 t1, build_int_cst (integer_type_node, 47));
kono
parents:
diff changeset
1253 gimple_set_location (g, loc);
kono
parents:
diff changeset
1254 tree t2 = gimple_assign_lhs (g);
kono
parents:
diff changeset
1255 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1256 g = gimple_build_assign (make_ssa_name (htype), BIT_XOR_EXPR,
kono
parents:
diff changeset
1257 vptr, t1);
kono
parents:
diff changeset
1258 gimple_set_location (g, loc);
kono
parents:
diff changeset
1259 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1260 g = gimple_build_assign (make_ssa_name (htype), BIT_XOR_EXPR,
kono
parents:
diff changeset
1261 t2, gimple_assign_lhs (g));
kono
parents:
diff changeset
1262 gimple_set_location (g, loc);
kono
parents:
diff changeset
1263 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1264 g = gimple_build_assign (make_ssa_name (htype), MULT_EXPR,
kono
parents:
diff changeset
1265 gimple_assign_lhs (g), cst);
kono
parents:
diff changeset
1266 gimple_set_location (g, loc);
kono
parents:
diff changeset
1267 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1268 tree t3 = gimple_assign_lhs (g);
kono
parents:
diff changeset
1269 g = gimple_build_assign (make_ssa_name (htype), LSHIFT_EXPR,
kono
parents:
diff changeset
1270 t3, build_int_cst (integer_type_node, 47));
kono
parents:
diff changeset
1271 gimple_set_location (g, loc);
kono
parents:
diff changeset
1272 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1273 g = gimple_build_assign (make_ssa_name (htype), BIT_XOR_EXPR,
kono
parents:
diff changeset
1274 t3, gimple_assign_lhs (g));
kono
parents:
diff changeset
1275 gimple_set_location (g, loc);
kono
parents:
diff changeset
1276 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1277 g = gimple_build_assign (make_ssa_name (htype), MULT_EXPR,
kono
parents:
diff changeset
1278 gimple_assign_lhs (g), cst);
kono
parents:
diff changeset
1279 gimple_set_location (g, loc);
kono
parents:
diff changeset
1280 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1281 if (!useless_type_conversion_p (pointer_sized_int_node, htype))
kono
parents:
diff changeset
1282 {
kono
parents:
diff changeset
1283 g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
kono
parents:
diff changeset
1284 NOP_EXPR, gimple_assign_lhs (g));
kono
parents:
diff changeset
1285 gimple_set_location (g, loc);
kono
parents:
diff changeset
1286 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1287 }
kono
parents:
diff changeset
1288 tree hash = gimple_assign_lhs (g);
kono
parents:
diff changeset
1289
kono
parents:
diff changeset
1290 if (ubsan_vptr_type_cache_decl == NULL_TREE)
kono
parents:
diff changeset
1291 {
kono
parents:
diff changeset
1292 tree atype = build_array_type_nelts (pointer_sized_int_node, 128);
kono
parents:
diff changeset
1293 tree array = build_decl (UNKNOWN_LOCATION, VAR_DECL,
kono
parents:
diff changeset
1294 get_identifier ("__ubsan_vptr_type_cache"),
kono
parents:
diff changeset
1295 atype);
kono
parents:
diff changeset
1296 DECL_ARTIFICIAL (array) = 1;
kono
parents:
diff changeset
1297 DECL_IGNORED_P (array) = 1;
kono
parents:
diff changeset
1298 TREE_PUBLIC (array) = 1;
kono
parents:
diff changeset
1299 TREE_STATIC (array) = 1;
kono
parents:
diff changeset
1300 DECL_EXTERNAL (array) = 1;
kono
parents:
diff changeset
1301 DECL_VISIBILITY (array) = VISIBILITY_DEFAULT;
kono
parents:
diff changeset
1302 DECL_VISIBILITY_SPECIFIED (array) = 1;
kono
parents:
diff changeset
1303 varpool_node::finalize_decl (array);
kono
parents:
diff changeset
1304 ubsan_vptr_type_cache_decl = array;
kono
parents:
diff changeset
1305 }
kono
parents:
diff changeset
1306
kono
parents:
diff changeset
1307 g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
kono
parents:
diff changeset
1308 BIT_AND_EXPR, hash,
kono
parents:
diff changeset
1309 build_int_cst (pointer_sized_int_node, 127));
kono
parents:
diff changeset
1310 gimple_set_location (g, loc);
kono
parents:
diff changeset
1311 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1312
kono
parents:
diff changeset
1313 tree c = build4_loc (loc, ARRAY_REF, pointer_sized_int_node,
kono
parents:
diff changeset
1314 ubsan_vptr_type_cache_decl, gimple_assign_lhs (g),
kono
parents:
diff changeset
1315 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
1316 g = gimple_build_assign (make_ssa_name (pointer_sized_int_node),
kono
parents:
diff changeset
1317 ARRAY_REF, c);
kono
parents:
diff changeset
1318 gimple_set_location (g, loc);
kono
parents:
diff changeset
1319 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1320
kono
parents:
diff changeset
1321 basic_block then_bb, fallthru2_bb;
kono
parents:
diff changeset
1322 gimple_stmt_iterator cond_insert_point
kono
parents:
diff changeset
1323 = create_cond_insert_point (gsip, false, false, true,
kono
parents:
diff changeset
1324 &then_bb, &fallthru2_bb);
kono
parents:
diff changeset
1325 g = gimple_build_cond (NE_EXPR, gimple_assign_lhs (g), hash,
kono
parents:
diff changeset
1326 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
1327 gimple_set_location (g, loc);
kono
parents:
diff changeset
1328 gsi_insert_after (&cond_insert_point, g, GSI_NEW_STMT);
kono
parents:
diff changeset
1329 *gsip = gsi_after_labels (then_bb);
kono
parents:
diff changeset
1330 if (fallthru_bb == NULL)
kono
parents:
diff changeset
1331 fallthru_bb = fallthru2_bb;
kono
parents:
diff changeset
1332
kono
parents:
diff changeset
1333 tree data
kono
parents:
diff changeset
1334 = ubsan_create_data ("__ubsan_vptr_data", 1, &loc,
kono
parents:
diff changeset
1335 ubsan_type_descriptor (type), NULL_TREE, ti_decl_addr,
kono
parents:
diff changeset
1336 build_int_cst (unsigned_char_type_node, ckind),
kono
parents:
diff changeset
1337 NULL_TREE);
kono
parents:
diff changeset
1338 data = build_fold_addr_expr_loc (loc, data);
kono
parents:
diff changeset
1339 enum built_in_function bcode
kono
parents:
diff changeset
1340 = (flag_sanitize_recover & SANITIZE_VPTR)
kono
parents:
diff changeset
1341 ? BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS
kono
parents:
diff changeset
1342 : BUILT_IN_UBSAN_HANDLE_DYNAMIC_TYPE_CACHE_MISS_ABORT;
kono
parents:
diff changeset
1343
kono
parents:
diff changeset
1344 g = gimple_build_call (builtin_decl_explicit (bcode), 3, data, op, hash);
kono
parents:
diff changeset
1345 gimple_set_location (g, loc);
kono
parents:
diff changeset
1346 gsi_insert_before (gsip, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1347
kono
parents:
diff changeset
1348 /* Point GSI to next logical statement. */
kono
parents:
diff changeset
1349 *gsip = gsi_start_bb (fallthru_bb);
kono
parents:
diff changeset
1350
kono
parents:
diff changeset
1351 /* Get rid of the UBSAN_VPTR call from the IR. */
kono
parents:
diff changeset
1352 unlink_stmt_vdef (stmt);
kono
parents:
diff changeset
1353 gsi_remove (&gsi, true);
kono
parents:
diff changeset
1354 return true;
kono
parents:
diff changeset
1355 }
kono
parents:
diff changeset
1356
kono
parents:
diff changeset
1357 /* Instrument a memory reference. BASE is the base of MEM, IS_LHS says
kono
parents:
diff changeset
1358 whether the pointer is on the left hand side of the assignment. */
kono
parents:
diff changeset
1359
kono
parents:
diff changeset
1360 static void
kono
parents:
diff changeset
1361 instrument_mem_ref (tree mem, tree base, gimple_stmt_iterator *iter,
kono
parents:
diff changeset
1362 bool is_lhs)
kono
parents:
diff changeset
1363 {
kono
parents:
diff changeset
1364 enum ubsan_null_ckind ikind = is_lhs ? UBSAN_STORE_OF : UBSAN_LOAD_OF;
kono
parents:
diff changeset
1365 unsigned int align = 0;
kono
parents:
diff changeset
1366 if (sanitize_flags_p (SANITIZE_ALIGNMENT))
kono
parents:
diff changeset
1367 {
kono
parents:
diff changeset
1368 align = min_align_of_type (TREE_TYPE (base));
kono
parents:
diff changeset
1369 if (align <= 1)
kono
parents:
diff changeset
1370 align = 0;
kono
parents:
diff changeset
1371 }
kono
parents:
diff changeset
1372 if (align == 0 && !sanitize_flags_p (SANITIZE_NULL))
kono
parents:
diff changeset
1373 return;
kono
parents:
diff changeset
1374 tree t = TREE_OPERAND (base, 0);
kono
parents:
diff changeset
1375 if (!POINTER_TYPE_P (TREE_TYPE (t)))
kono
parents:
diff changeset
1376 return;
kono
parents:
diff changeset
1377 if (RECORD_OR_UNION_TYPE_P (TREE_TYPE (base)) && mem != base)
kono
parents:
diff changeset
1378 ikind = UBSAN_MEMBER_ACCESS;
kono
parents:
diff changeset
1379 tree kind = build_int_cst (build_pointer_type (TREE_TYPE (base)), ikind);
kono
parents:
diff changeset
1380 tree alignt = build_int_cst (pointer_sized_int_node, align);
kono
parents:
diff changeset
1381 gcall *g = gimple_build_call_internal (IFN_UBSAN_NULL, 3, t, kind, alignt);
kono
parents:
diff changeset
1382 gimple_set_location (g, gimple_location (gsi_stmt (*iter)));
kono
parents:
diff changeset
1383 gsi_insert_before (iter, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1384 }
kono
parents:
diff changeset
1385
kono
parents:
diff changeset
1386 /* Perform the pointer instrumentation. */
kono
parents:
diff changeset
1387
kono
parents:
diff changeset
1388 static void
kono
parents:
diff changeset
1389 instrument_null (gimple_stmt_iterator gsi, tree t, bool is_lhs)
kono
parents:
diff changeset
1390 {
kono
parents:
diff changeset
1391 /* Handle also e.g. &s->i. */
kono
parents:
diff changeset
1392 if (TREE_CODE (t) == ADDR_EXPR)
kono
parents:
diff changeset
1393 t = TREE_OPERAND (t, 0);
kono
parents:
diff changeset
1394 tree base = get_base_address (t);
kono
parents:
diff changeset
1395 if (base != NULL_TREE
kono
parents:
diff changeset
1396 && TREE_CODE (base) == MEM_REF
kono
parents:
diff changeset
1397 && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
kono
parents:
diff changeset
1398 instrument_mem_ref (t, base, &gsi, is_lhs);
kono
parents:
diff changeset
1399 }
kono
parents:
diff changeset
1400
kono
parents:
diff changeset
1401 /* Instrument pointer arithmetics PTR p+ OFF. */
kono
parents:
diff changeset
1402
kono
parents:
diff changeset
1403 static void
kono
parents:
diff changeset
1404 instrument_pointer_overflow (gimple_stmt_iterator *gsi, tree ptr, tree off)
kono
parents:
diff changeset
1405 {
kono
parents:
diff changeset
1406 if (TYPE_PRECISION (sizetype) != POINTER_SIZE)
kono
parents:
diff changeset
1407 return;
kono
parents:
diff changeset
1408 gcall *g = gimple_build_call_internal (IFN_UBSAN_PTR, 2, ptr, off);
kono
parents:
diff changeset
1409 gimple_set_location (g, gimple_location (gsi_stmt (*gsi)));
kono
parents:
diff changeset
1410 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1411 }
kono
parents:
diff changeset
1412
kono
parents:
diff changeset
1413 /* Instrument pointer arithmetics if any. */
kono
parents:
diff changeset
1414
kono
parents:
diff changeset
1415 static void
kono
parents:
diff changeset
1416 maybe_instrument_pointer_overflow (gimple_stmt_iterator *gsi, tree t)
kono
parents:
diff changeset
1417 {
kono
parents:
diff changeset
1418 if (TYPE_PRECISION (sizetype) != POINTER_SIZE)
kono
parents:
diff changeset
1419 return;
kono
parents:
diff changeset
1420
kono
parents:
diff changeset
1421 /* Handle also e.g. &s->i. */
kono
parents:
diff changeset
1422 if (TREE_CODE (t) == ADDR_EXPR)
kono
parents:
diff changeset
1423 t = TREE_OPERAND (t, 0);
kono
parents:
diff changeset
1424
kono
parents:
diff changeset
1425 if (!handled_component_p (t) && TREE_CODE (t) != MEM_REF)
kono
parents:
diff changeset
1426 return;
kono
parents:
diff changeset
1427
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1428 poly_int64 bitsize, bitpos, bytepos;
111
kono
parents:
diff changeset
1429 tree offset;
kono
parents:
diff changeset
1430 machine_mode mode;
kono
parents:
diff changeset
1431 int volatilep = 0, reversep, unsignedp = 0;
kono
parents:
diff changeset
1432 tree inner = get_inner_reference (t, &bitsize, &bitpos, &offset, &mode,
kono
parents:
diff changeset
1433 &unsignedp, &reversep, &volatilep);
kono
parents:
diff changeset
1434 tree moff = NULL_TREE;
kono
parents:
diff changeset
1435
kono
parents:
diff changeset
1436 bool decl_p = DECL_P (inner);
kono
parents:
diff changeset
1437 tree base;
kono
parents:
diff changeset
1438 if (decl_p)
kono
parents:
diff changeset
1439 {
kono
parents:
diff changeset
1440 if (DECL_REGISTER (inner))
kono
parents:
diff changeset
1441 return;
kono
parents:
diff changeset
1442 base = inner;
kono
parents:
diff changeset
1443 /* If BASE is a fixed size automatic variable or
kono
parents:
diff changeset
1444 global variable defined in the current TU and bitpos
kono
parents:
diff changeset
1445 fits, don't instrument anything. */
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1446 poly_int64 base_size;
111
kono
parents:
diff changeset
1447 if (offset == NULL_TREE
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1448 && maybe_ne (bitpos, 0)
111
kono
parents:
diff changeset
1449 && (VAR_P (base)
kono
parents:
diff changeset
1450 || TREE_CODE (base) == PARM_DECL
kono
parents:
diff changeset
1451 || TREE_CODE (base) == RESULT_DECL)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1452 && poly_int_tree_p (DECL_SIZE (base), &base_size)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1453 && known_ge (base_size, bitpos)
111
kono
parents:
diff changeset
1454 && (!is_global_var (base) || decl_binds_to_current_def_p (base)))
kono
parents:
diff changeset
1455 return;
kono
parents:
diff changeset
1456 }
kono
parents:
diff changeset
1457 else if (TREE_CODE (inner) == MEM_REF)
kono
parents:
diff changeset
1458 {
kono
parents:
diff changeset
1459 base = TREE_OPERAND (inner, 0);
kono
parents:
diff changeset
1460 if (TREE_CODE (base) == ADDR_EXPR
kono
parents:
diff changeset
1461 && DECL_P (TREE_OPERAND (base, 0))
kono
parents:
diff changeset
1462 && !TREE_ADDRESSABLE (TREE_OPERAND (base, 0))
kono
parents:
diff changeset
1463 && !is_global_var (TREE_OPERAND (base, 0)))
kono
parents:
diff changeset
1464 return;
kono
parents:
diff changeset
1465 moff = TREE_OPERAND (inner, 1);
kono
parents:
diff changeset
1466 if (integer_zerop (moff))
kono
parents:
diff changeset
1467 moff = NULL_TREE;
kono
parents:
diff changeset
1468 }
kono
parents:
diff changeset
1469 else
kono
parents:
diff changeset
1470 return;
kono
parents:
diff changeset
1471
kono
parents:
diff changeset
1472 if (!POINTER_TYPE_P (TREE_TYPE (base)) && !DECL_P (base))
kono
parents:
diff changeset
1473 return;
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1474 bytepos = bits_to_bytes_round_down (bitpos);
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1475 if (offset == NULL_TREE && known_eq (bytepos, 0) && moff == NULL_TREE)
111
kono
parents:
diff changeset
1476 return;
kono
parents:
diff changeset
1477
kono
parents:
diff changeset
1478 tree base_addr = base;
kono
parents:
diff changeset
1479 if (decl_p)
kono
parents:
diff changeset
1480 base_addr = build1 (ADDR_EXPR,
kono
parents:
diff changeset
1481 build_pointer_type (TREE_TYPE (base)), base);
kono
parents:
diff changeset
1482 t = offset;
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1483 if (maybe_ne (bytepos, 0))
111
kono
parents:
diff changeset
1484 {
kono
parents:
diff changeset
1485 if (t)
kono
parents:
diff changeset
1486 t = fold_build2 (PLUS_EXPR, TREE_TYPE (t), t,
kono
parents:
diff changeset
1487 build_int_cst (TREE_TYPE (t), bytepos));
kono
parents:
diff changeset
1488 else
kono
parents:
diff changeset
1489 t = size_int (bytepos);
kono
parents:
diff changeset
1490 }
kono
parents:
diff changeset
1491 if (moff)
kono
parents:
diff changeset
1492 {
kono
parents:
diff changeset
1493 if (t)
kono
parents:
diff changeset
1494 t = fold_build2 (PLUS_EXPR, TREE_TYPE (t), t,
kono
parents:
diff changeset
1495 fold_convert (TREE_TYPE (t), moff));
kono
parents:
diff changeset
1496 else
kono
parents:
diff changeset
1497 t = fold_convert (sizetype, moff);
kono
parents:
diff changeset
1498 }
kono
parents:
diff changeset
1499 t = force_gimple_operand_gsi (gsi, t, true, NULL_TREE, true,
kono
parents:
diff changeset
1500 GSI_SAME_STMT);
kono
parents:
diff changeset
1501 base_addr = force_gimple_operand_gsi (gsi, base_addr, true, NULL_TREE, true,
kono
parents:
diff changeset
1502 GSI_SAME_STMT);
kono
parents:
diff changeset
1503 instrument_pointer_overflow (gsi, base_addr, t);
kono
parents:
diff changeset
1504 }
kono
parents:
diff changeset
1505
kono
parents:
diff changeset
1506 /* Build an ubsan builtin call for the signed-integer-overflow
kono
parents:
diff changeset
1507 sanitization. CODE says what kind of builtin are we building,
kono
parents:
diff changeset
1508 LOC is a location, LHSTYPE is the type of LHS, OP0 and OP1
kono
parents:
diff changeset
1509 are operands of the binary operation. */
kono
parents:
diff changeset
1510
kono
parents:
diff changeset
1511 tree
kono
parents:
diff changeset
1512 ubsan_build_overflow_builtin (tree_code code, location_t loc, tree lhstype,
kono
parents:
diff changeset
1513 tree op0, tree op1, tree *datap)
kono
parents:
diff changeset
1514 {
kono
parents:
diff changeset
1515 if (flag_sanitize_undefined_trap_on_error)
kono
parents:
diff changeset
1516 return build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
kono
parents:
diff changeset
1517
kono
parents:
diff changeset
1518 tree data;
kono
parents:
diff changeset
1519 if (datap && *datap)
kono
parents:
diff changeset
1520 data = *datap;
kono
parents:
diff changeset
1521 else
kono
parents:
diff changeset
1522 data = ubsan_create_data ("__ubsan_overflow_data", 1, &loc,
kono
parents:
diff changeset
1523 ubsan_type_descriptor (lhstype), NULL_TREE,
kono
parents:
diff changeset
1524 NULL_TREE);
kono
parents:
diff changeset
1525 if (datap)
kono
parents:
diff changeset
1526 *datap = data;
kono
parents:
diff changeset
1527 enum built_in_function fn_code;
kono
parents:
diff changeset
1528
kono
parents:
diff changeset
1529 switch (code)
kono
parents:
diff changeset
1530 {
kono
parents:
diff changeset
1531 case PLUS_EXPR:
kono
parents:
diff changeset
1532 fn_code = (flag_sanitize_recover & SANITIZE_SI_OVERFLOW)
kono
parents:
diff changeset
1533 ? BUILT_IN_UBSAN_HANDLE_ADD_OVERFLOW
kono
parents:
diff changeset
1534 : BUILT_IN_UBSAN_HANDLE_ADD_OVERFLOW_ABORT;
kono
parents:
diff changeset
1535 break;
kono
parents:
diff changeset
1536 case MINUS_EXPR:
kono
parents:
diff changeset
1537 fn_code = (flag_sanitize_recover & SANITIZE_SI_OVERFLOW)
kono
parents:
diff changeset
1538 ? BUILT_IN_UBSAN_HANDLE_SUB_OVERFLOW
kono
parents:
diff changeset
1539 : BUILT_IN_UBSAN_HANDLE_SUB_OVERFLOW_ABORT;
kono
parents:
diff changeset
1540 break;
kono
parents:
diff changeset
1541 case MULT_EXPR:
kono
parents:
diff changeset
1542 fn_code = (flag_sanitize_recover & SANITIZE_SI_OVERFLOW)
kono
parents:
diff changeset
1543 ? BUILT_IN_UBSAN_HANDLE_MUL_OVERFLOW
kono
parents:
diff changeset
1544 : BUILT_IN_UBSAN_HANDLE_MUL_OVERFLOW_ABORT;
kono
parents:
diff changeset
1545 break;
kono
parents:
diff changeset
1546 case NEGATE_EXPR:
kono
parents:
diff changeset
1547 fn_code = (flag_sanitize_recover & SANITIZE_SI_OVERFLOW)
kono
parents:
diff changeset
1548 ? BUILT_IN_UBSAN_HANDLE_NEGATE_OVERFLOW
kono
parents:
diff changeset
1549 : BUILT_IN_UBSAN_HANDLE_NEGATE_OVERFLOW_ABORT;
kono
parents:
diff changeset
1550 break;
kono
parents:
diff changeset
1551 default:
kono
parents:
diff changeset
1552 gcc_unreachable ();
kono
parents:
diff changeset
1553 }
kono
parents:
diff changeset
1554 tree fn = builtin_decl_explicit (fn_code);
kono
parents:
diff changeset
1555 return build_call_expr_loc (loc, fn, 2 + (code != NEGATE_EXPR),
kono
parents:
diff changeset
1556 build_fold_addr_expr_loc (loc, data),
kono
parents:
diff changeset
1557 ubsan_encode_value (op0, UBSAN_ENCODE_VALUE_RTL),
kono
parents:
diff changeset
1558 op1
kono
parents:
diff changeset
1559 ? ubsan_encode_value (op1,
kono
parents:
diff changeset
1560 UBSAN_ENCODE_VALUE_RTL)
kono
parents:
diff changeset
1561 : NULL_TREE);
kono
parents:
diff changeset
1562 }
kono
parents:
diff changeset
1563
kono
parents:
diff changeset
1564 /* Perform the signed integer instrumentation. GSI is the iterator
kono
parents:
diff changeset
1565 pointing at statement we are trying to instrument. */
kono
parents:
diff changeset
1566
kono
parents:
diff changeset
1567 static void
kono
parents:
diff changeset
1568 instrument_si_overflow (gimple_stmt_iterator gsi)
kono
parents:
diff changeset
1569 {
kono
parents:
diff changeset
1570 gimple *stmt = gsi_stmt (gsi);
kono
parents:
diff changeset
1571 tree_code code = gimple_assign_rhs_code (stmt);
kono
parents:
diff changeset
1572 tree lhs = gimple_assign_lhs (stmt);
kono
parents:
diff changeset
1573 tree lhstype = TREE_TYPE (lhs);
kono
parents:
diff changeset
1574 tree lhsinner = VECTOR_TYPE_P (lhstype) ? TREE_TYPE (lhstype) : lhstype;
kono
parents:
diff changeset
1575 tree a, b;
kono
parents:
diff changeset
1576 gimple *g;
kono
parents:
diff changeset
1577
kono
parents:
diff changeset
1578 /* If this is not a signed operation, don't instrument anything here.
kono
parents:
diff changeset
1579 Also punt on bit-fields. */
kono
parents:
diff changeset
1580 if (!INTEGRAL_TYPE_P (lhsinner)
kono
parents:
diff changeset
1581 || TYPE_OVERFLOW_WRAPS (lhsinner)
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1582 || maybe_ne (GET_MODE_BITSIZE (TYPE_MODE (lhsinner)),
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1583 TYPE_PRECISION (lhsinner)))
111
kono
parents:
diff changeset
1584 return;
kono
parents:
diff changeset
1585
kono
parents:
diff changeset
1586 switch (code)
kono
parents:
diff changeset
1587 {
kono
parents:
diff changeset
1588 case MINUS_EXPR:
kono
parents:
diff changeset
1589 case PLUS_EXPR:
kono
parents:
diff changeset
1590 case MULT_EXPR:
kono
parents:
diff changeset
1591 /* Transform
kono
parents:
diff changeset
1592 i = u {+,-,*} 5;
kono
parents:
diff changeset
1593 into
kono
parents:
diff changeset
1594 i = UBSAN_CHECK_{ADD,SUB,MUL} (u, 5); */
kono
parents:
diff changeset
1595 a = gimple_assign_rhs1 (stmt);
kono
parents:
diff changeset
1596 b = gimple_assign_rhs2 (stmt);
kono
parents:
diff changeset
1597 g = gimple_build_call_internal (code == PLUS_EXPR
kono
parents:
diff changeset
1598 ? IFN_UBSAN_CHECK_ADD
kono
parents:
diff changeset
1599 : code == MINUS_EXPR
kono
parents:
diff changeset
1600 ? IFN_UBSAN_CHECK_SUB
kono
parents:
diff changeset
1601 : IFN_UBSAN_CHECK_MUL, 2, a, b);
kono
parents:
diff changeset
1602 gimple_call_set_lhs (g, lhs);
kono
parents:
diff changeset
1603 gsi_replace (&gsi, g, true);
kono
parents:
diff changeset
1604 break;
kono
parents:
diff changeset
1605 case NEGATE_EXPR:
kono
parents:
diff changeset
1606 /* Represent i = -u;
kono
parents:
diff changeset
1607 as
kono
parents:
diff changeset
1608 i = UBSAN_CHECK_SUB (0, u); */
kono
parents:
diff changeset
1609 a = build_zero_cst (lhstype);
kono
parents:
diff changeset
1610 b = gimple_assign_rhs1 (stmt);
kono
parents:
diff changeset
1611 g = gimple_build_call_internal (IFN_UBSAN_CHECK_SUB, 2, a, b);
kono
parents:
diff changeset
1612 gimple_call_set_lhs (g, lhs);
kono
parents:
diff changeset
1613 gsi_replace (&gsi, g, true);
kono
parents:
diff changeset
1614 break;
kono
parents:
diff changeset
1615 case ABS_EXPR:
kono
parents:
diff changeset
1616 /* Transform i = ABS_EXPR<u>;
kono
parents:
diff changeset
1617 into
kono
parents:
diff changeset
1618 _N = UBSAN_CHECK_SUB (0, u);
kono
parents:
diff changeset
1619 i = ABS_EXPR<_N>; */
kono
parents:
diff changeset
1620 a = build_zero_cst (lhstype);
kono
parents:
diff changeset
1621 b = gimple_assign_rhs1 (stmt);
kono
parents:
diff changeset
1622 g = gimple_build_call_internal (IFN_UBSAN_CHECK_SUB, 2, a, b);
kono
parents:
diff changeset
1623 a = make_ssa_name (lhstype);
kono
parents:
diff changeset
1624 gimple_call_set_lhs (g, a);
kono
parents:
diff changeset
1625 gimple_set_location (g, gimple_location (stmt));
kono
parents:
diff changeset
1626 gsi_insert_before (&gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1627 gimple_assign_set_rhs1 (stmt, a);
kono
parents:
diff changeset
1628 update_stmt (stmt);
kono
parents:
diff changeset
1629 break;
kono
parents:
diff changeset
1630 default:
kono
parents:
diff changeset
1631 break;
kono
parents:
diff changeset
1632 }
kono
parents:
diff changeset
1633 }
kono
parents:
diff changeset
1634
kono
parents:
diff changeset
1635 /* Instrument loads from (non-bitfield) bool and C++ enum values
kono
parents:
diff changeset
1636 to check if the memory value is outside of the range of the valid
kono
parents:
diff changeset
1637 type values. */
kono
parents:
diff changeset
1638
kono
parents:
diff changeset
1639 static void
kono
parents:
diff changeset
1640 instrument_bool_enum_load (gimple_stmt_iterator *gsi)
kono
parents:
diff changeset
1641 {
kono
parents:
diff changeset
1642 gimple *stmt = gsi_stmt (*gsi);
kono
parents:
diff changeset
1643 tree rhs = gimple_assign_rhs1 (stmt);
kono
parents:
diff changeset
1644 tree type = TREE_TYPE (rhs);
kono
parents:
diff changeset
1645 tree minv = NULL_TREE, maxv = NULL_TREE;
kono
parents:
diff changeset
1646
kono
parents:
diff changeset
1647 if (TREE_CODE (type) == BOOLEAN_TYPE
kono
parents:
diff changeset
1648 && sanitize_flags_p (SANITIZE_BOOL))
kono
parents:
diff changeset
1649 {
kono
parents:
diff changeset
1650 minv = boolean_false_node;
kono
parents:
diff changeset
1651 maxv = boolean_true_node;
kono
parents:
diff changeset
1652 }
kono
parents:
diff changeset
1653 else if (TREE_CODE (type) == ENUMERAL_TYPE
kono
parents:
diff changeset
1654 && sanitize_flags_p (SANITIZE_ENUM)
kono
parents:
diff changeset
1655 && TREE_TYPE (type) != NULL_TREE
kono
parents:
diff changeset
1656 && TREE_CODE (TREE_TYPE (type)) == INTEGER_TYPE
kono
parents:
diff changeset
1657 && (TYPE_PRECISION (TREE_TYPE (type))
kono
parents:
diff changeset
1658 < GET_MODE_PRECISION (SCALAR_INT_TYPE_MODE (type))))
kono
parents:
diff changeset
1659 {
kono
parents:
diff changeset
1660 minv = TYPE_MIN_VALUE (TREE_TYPE (type));
kono
parents:
diff changeset
1661 maxv = TYPE_MAX_VALUE (TREE_TYPE (type));
kono
parents:
diff changeset
1662 }
kono
parents:
diff changeset
1663 else
kono
parents:
diff changeset
1664 return;
kono
parents:
diff changeset
1665
kono
parents:
diff changeset
1666 int modebitsize = GET_MODE_BITSIZE (SCALAR_INT_TYPE_MODE (type));
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1667 poly_int64 bitsize, bitpos;
111
kono
parents:
diff changeset
1668 tree offset;
kono
parents:
diff changeset
1669 machine_mode mode;
kono
parents:
diff changeset
1670 int volatilep = 0, reversep, unsignedp = 0;
kono
parents:
diff changeset
1671 tree base = get_inner_reference (rhs, &bitsize, &bitpos, &offset, &mode,
kono
parents:
diff changeset
1672 &unsignedp, &reversep, &volatilep);
kono
parents:
diff changeset
1673 tree utype = build_nonstandard_integer_type (modebitsize, 1);
kono
parents:
diff changeset
1674
kono
parents:
diff changeset
1675 if ((VAR_P (base) && DECL_HARD_REGISTER (base))
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1676 || !multiple_p (bitpos, modebitsize)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
1677 || maybe_ne (bitsize, modebitsize)
111
kono
parents:
diff changeset
1678 || GET_MODE_BITSIZE (SCALAR_INT_TYPE_MODE (utype)) != modebitsize
kono
parents:
diff changeset
1679 || TREE_CODE (gimple_assign_lhs (stmt)) != SSA_NAME)
kono
parents:
diff changeset
1680 return;
kono
parents:
diff changeset
1681
kono
parents:
diff changeset
1682 bool ends_bb = stmt_ends_bb_p (stmt);
kono
parents:
diff changeset
1683 location_t loc = gimple_location (stmt);
kono
parents:
diff changeset
1684 tree lhs = gimple_assign_lhs (stmt);
kono
parents:
diff changeset
1685 tree ptype = build_pointer_type (TREE_TYPE (rhs));
kono
parents:
diff changeset
1686 tree atype = reference_alias_ptr_type (rhs);
kono
parents:
diff changeset
1687 gimple *g = gimple_build_assign (make_ssa_name (ptype),
kono
parents:
diff changeset
1688 build_fold_addr_expr (rhs));
kono
parents:
diff changeset
1689 gimple_set_location (g, loc);
kono
parents:
diff changeset
1690 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1691 tree mem = build2 (MEM_REF, utype, gimple_assign_lhs (g),
kono
parents:
diff changeset
1692 build_int_cst (atype, 0));
kono
parents:
diff changeset
1693 tree urhs = make_ssa_name (utype);
kono
parents:
diff changeset
1694 if (ends_bb)
kono
parents:
diff changeset
1695 {
kono
parents:
diff changeset
1696 gimple_assign_set_lhs (stmt, urhs);
kono
parents:
diff changeset
1697 g = gimple_build_assign (lhs, NOP_EXPR, urhs);
kono
parents:
diff changeset
1698 gimple_set_location (g, loc);
kono
parents:
diff changeset
1699 edge e = find_fallthru_edge (gimple_bb (stmt)->succs);
kono
parents:
diff changeset
1700 gsi_insert_on_edge_immediate (e, g);
kono
parents:
diff changeset
1701 gimple_assign_set_rhs_from_tree (gsi, mem);
kono
parents:
diff changeset
1702 update_stmt (stmt);
kono
parents:
diff changeset
1703 *gsi = gsi_for_stmt (g);
kono
parents:
diff changeset
1704 g = stmt;
kono
parents:
diff changeset
1705 }
kono
parents:
diff changeset
1706 else
kono
parents:
diff changeset
1707 {
kono
parents:
diff changeset
1708 g = gimple_build_assign (urhs, mem);
kono
parents:
diff changeset
1709 gimple_set_location (g, loc);
kono
parents:
diff changeset
1710 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1711 }
kono
parents:
diff changeset
1712 minv = fold_convert (utype, minv);
kono
parents:
diff changeset
1713 maxv = fold_convert (utype, maxv);
kono
parents:
diff changeset
1714 if (!integer_zerop (minv))
kono
parents:
diff changeset
1715 {
kono
parents:
diff changeset
1716 g = gimple_build_assign (make_ssa_name (utype), MINUS_EXPR, urhs, minv);
kono
parents:
diff changeset
1717 gimple_set_location (g, loc);
kono
parents:
diff changeset
1718 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1719 }
kono
parents:
diff changeset
1720
kono
parents:
diff changeset
1721 gimple_stmt_iterator gsi2 = *gsi;
kono
parents:
diff changeset
1722 basic_block then_bb, fallthru_bb;
kono
parents:
diff changeset
1723 *gsi = create_cond_insert_point (gsi, true, false, true,
kono
parents:
diff changeset
1724 &then_bb, &fallthru_bb);
kono
parents:
diff changeset
1725 g = gimple_build_cond (GT_EXPR, gimple_assign_lhs (g),
kono
parents:
diff changeset
1726 int_const_binop (MINUS_EXPR, maxv, minv),
kono
parents:
diff changeset
1727 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
1728 gimple_set_location (g, loc);
kono
parents:
diff changeset
1729 gsi_insert_after (gsi, g, GSI_NEW_STMT);
kono
parents:
diff changeset
1730
kono
parents:
diff changeset
1731 if (!ends_bb)
kono
parents:
diff changeset
1732 {
kono
parents:
diff changeset
1733 gimple_assign_set_rhs_with_ops (&gsi2, NOP_EXPR, urhs);
kono
parents:
diff changeset
1734 update_stmt (stmt);
kono
parents:
diff changeset
1735 }
kono
parents:
diff changeset
1736
kono
parents:
diff changeset
1737 gsi2 = gsi_after_labels (then_bb);
kono
parents:
diff changeset
1738 if (flag_sanitize_undefined_trap_on_error)
kono
parents:
diff changeset
1739 g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
kono
parents:
diff changeset
1740 else
kono
parents:
diff changeset
1741 {
kono
parents:
diff changeset
1742 tree data = ubsan_create_data ("__ubsan_invalid_value_data", 1, &loc,
kono
parents:
diff changeset
1743 ubsan_type_descriptor (type), NULL_TREE,
kono
parents:
diff changeset
1744 NULL_TREE);
kono
parents:
diff changeset
1745 data = build_fold_addr_expr_loc (loc, data);
kono
parents:
diff changeset
1746 enum built_in_function bcode
kono
parents:
diff changeset
1747 = (flag_sanitize_recover & (TREE_CODE (type) == BOOLEAN_TYPE
kono
parents:
diff changeset
1748 ? SANITIZE_BOOL : SANITIZE_ENUM))
kono
parents:
diff changeset
1749 ? BUILT_IN_UBSAN_HANDLE_LOAD_INVALID_VALUE
kono
parents:
diff changeset
1750 : BUILT_IN_UBSAN_HANDLE_LOAD_INVALID_VALUE_ABORT;
kono
parents:
diff changeset
1751 tree fn = builtin_decl_explicit (bcode);
kono
parents:
diff changeset
1752
kono
parents:
diff changeset
1753 tree val = ubsan_encode_value (urhs, UBSAN_ENCODE_VALUE_GIMPLE);
kono
parents:
diff changeset
1754 val = force_gimple_operand_gsi (&gsi2, val, true, NULL_TREE, true,
kono
parents:
diff changeset
1755 GSI_SAME_STMT);
kono
parents:
diff changeset
1756 g = gimple_build_call (fn, 2, data, val);
kono
parents:
diff changeset
1757 }
kono
parents:
diff changeset
1758 gimple_set_location (g, loc);
kono
parents:
diff changeset
1759 gsi_insert_before (&gsi2, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1760 ubsan_create_edge (g);
kono
parents:
diff changeset
1761 *gsi = gsi_for_stmt (stmt);
kono
parents:
diff changeset
1762 }
kono
parents:
diff changeset
1763
kono
parents:
diff changeset
1764 /* Determine if we can propagate given LOCATION to ubsan_data descriptor to use
kono
parents:
diff changeset
1765 new style handlers. Libubsan uses heuristics to destinguish between old and
kono
parents:
diff changeset
1766 new styles and relies on these properties for filename:
kono
parents:
diff changeset
1767
kono
parents:
diff changeset
1768 a) Location's filename must not be NULL.
kono
parents:
diff changeset
1769 b) Location's filename must not be equal to "".
kono
parents:
diff changeset
1770 c) Location's filename must not be equal to "\1".
kono
parents:
diff changeset
1771 d) First two bytes of filename must not contain '\xff' symbol. */
kono
parents:
diff changeset
1772
kono
parents:
diff changeset
1773 static bool
kono
parents:
diff changeset
1774 ubsan_use_new_style_p (location_t loc)
kono
parents:
diff changeset
1775 {
kono
parents:
diff changeset
1776 if (loc == UNKNOWN_LOCATION)
kono
parents:
diff changeset
1777 return false;
kono
parents:
diff changeset
1778
kono
parents:
diff changeset
1779 expanded_location xloc = expand_location (loc);
kono
parents:
diff changeset
1780 if (xloc.file == NULL || strncmp (xloc.file, "\1", 2) == 0
kono
parents:
diff changeset
1781 || xloc.file[0] == '\0' || xloc.file[0] == '\xff'
kono
parents:
diff changeset
1782 || xloc.file[1] == '\xff')
kono
parents:
diff changeset
1783 return false;
kono
parents:
diff changeset
1784
kono
parents:
diff changeset
1785 return true;
kono
parents:
diff changeset
1786 }
kono
parents:
diff changeset
1787
kono
parents:
diff changeset
1788 /* Instrument float point-to-integer conversion. TYPE is an integer type of
kono
parents:
diff changeset
1789 destination, EXPR is floating-point expression. */
kono
parents:
diff changeset
1790
kono
parents:
diff changeset
1791 tree
kono
parents:
diff changeset
1792 ubsan_instrument_float_cast (location_t loc, tree type, tree expr)
kono
parents:
diff changeset
1793 {
kono
parents:
diff changeset
1794 tree expr_type = TREE_TYPE (expr);
kono
parents:
diff changeset
1795 tree t, tt, fn, min, max;
kono
parents:
diff changeset
1796 machine_mode mode = TYPE_MODE (expr_type);
kono
parents:
diff changeset
1797 int prec = TYPE_PRECISION (type);
kono
parents:
diff changeset
1798 bool uns_p = TYPE_UNSIGNED (type);
kono
parents:
diff changeset
1799 if (loc == UNKNOWN_LOCATION)
kono
parents:
diff changeset
1800 loc = input_location;
kono
parents:
diff changeset
1801
kono
parents:
diff changeset
1802 /* Float to integer conversion first truncates toward zero, so
kono
parents:
diff changeset
1803 even signed char c = 127.875f; is not problematic.
kono
parents:
diff changeset
1804 Therefore, we should complain only if EXPR is unordered or smaller
kono
parents:
diff changeset
1805 or equal than TYPE_MIN_VALUE - 1.0 or greater or equal than
kono
parents:
diff changeset
1806 TYPE_MAX_VALUE + 1.0. */
kono
parents:
diff changeset
1807 if (REAL_MODE_FORMAT (mode)->b == 2)
kono
parents:
diff changeset
1808 {
kono
parents:
diff changeset
1809 /* For maximum, TYPE_MAX_VALUE might not be representable
kono
parents:
diff changeset
1810 in EXPR_TYPE, e.g. if TYPE is 64-bit long long and
kono
parents:
diff changeset
1811 EXPR_TYPE is IEEE single float, but TYPE_MAX_VALUE + 1.0 is
kono
parents:
diff changeset
1812 either representable or infinity. */
kono
parents:
diff changeset
1813 REAL_VALUE_TYPE maxval = dconst1;
kono
parents:
diff changeset
1814 SET_REAL_EXP (&maxval, REAL_EXP (&maxval) + prec - !uns_p);
kono
parents:
diff changeset
1815 real_convert (&maxval, mode, &maxval);
kono
parents:
diff changeset
1816 max = build_real (expr_type, maxval);
kono
parents:
diff changeset
1817
kono
parents:
diff changeset
1818 /* For unsigned, assume -1.0 is always representable. */
kono
parents:
diff changeset
1819 if (uns_p)
kono
parents:
diff changeset
1820 min = build_minus_one_cst (expr_type);
kono
parents:
diff changeset
1821 else
kono
parents:
diff changeset
1822 {
kono
parents:
diff changeset
1823 /* TYPE_MIN_VALUE is generally representable (or -inf),
kono
parents:
diff changeset
1824 but TYPE_MIN_VALUE - 1.0 might not be. */
kono
parents:
diff changeset
1825 REAL_VALUE_TYPE minval = dconstm1, minval2;
kono
parents:
diff changeset
1826 SET_REAL_EXP (&minval, REAL_EXP (&minval) + prec - 1);
kono
parents:
diff changeset
1827 real_convert (&minval, mode, &minval);
kono
parents:
diff changeset
1828 real_arithmetic (&minval2, MINUS_EXPR, &minval, &dconst1);
kono
parents:
diff changeset
1829 real_convert (&minval2, mode, &minval2);
kono
parents:
diff changeset
1830 if (real_compare (EQ_EXPR, &minval, &minval2)
kono
parents:
diff changeset
1831 && !real_isinf (&minval))
kono
parents:
diff changeset
1832 {
kono
parents:
diff changeset
1833 /* If TYPE_MIN_VALUE - 1.0 is not representable and
kono
parents:
diff changeset
1834 rounds to TYPE_MIN_VALUE, we need to subtract
kono
parents:
diff changeset
1835 more. As REAL_MODE_FORMAT (mode)->p is the number
kono
parents:
diff changeset
1836 of base digits, we want to subtract a number that
kono
parents:
diff changeset
1837 will be 1 << (REAL_MODE_FORMAT (mode)->p - 1)
kono
parents:
diff changeset
1838 times smaller than minval. */
kono
parents:
diff changeset
1839 minval2 = dconst1;
kono
parents:
diff changeset
1840 gcc_assert (prec > REAL_MODE_FORMAT (mode)->p);
kono
parents:
diff changeset
1841 SET_REAL_EXP (&minval2,
kono
parents:
diff changeset
1842 REAL_EXP (&minval2) + prec - 1
kono
parents:
diff changeset
1843 - REAL_MODE_FORMAT (mode)->p + 1);
kono
parents:
diff changeset
1844 real_arithmetic (&minval2, MINUS_EXPR, &minval, &minval2);
kono
parents:
diff changeset
1845 real_convert (&minval2, mode, &minval2);
kono
parents:
diff changeset
1846 }
kono
parents:
diff changeset
1847 min = build_real (expr_type, minval2);
kono
parents:
diff changeset
1848 }
kono
parents:
diff changeset
1849 }
kono
parents:
diff changeset
1850 else if (REAL_MODE_FORMAT (mode)->b == 10)
kono
parents:
diff changeset
1851 {
kono
parents:
diff changeset
1852 /* For _Decimal128 up to 34 decimal digits, - sign,
kono
parents:
diff changeset
1853 dot, e, exponent. */
kono
parents:
diff changeset
1854 char buf[64];
kono
parents:
diff changeset
1855 mpfr_t m;
kono
parents:
diff changeset
1856 int p = REAL_MODE_FORMAT (mode)->p;
kono
parents:
diff changeset
1857 REAL_VALUE_TYPE maxval, minval;
kono
parents:
diff changeset
1858
kono
parents:
diff changeset
1859 /* Use mpfr_snprintf rounding to compute the smallest
kono
parents:
diff changeset
1860 representable decimal number greater or equal than
kono
parents:
diff changeset
1861 1 << (prec - !uns_p). */
kono
parents:
diff changeset
1862 mpfr_init2 (m, prec + 2);
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1863 mpfr_set_ui_2exp (m, 1, prec - !uns_p, MPFR_RNDN);
111
kono
parents:
diff changeset
1864 mpfr_snprintf (buf, sizeof buf, "%.*RUe", p - 1, m);
kono
parents:
diff changeset
1865 decimal_real_from_string (&maxval, buf);
kono
parents:
diff changeset
1866 max = build_real (expr_type, maxval);
kono
parents:
diff changeset
1867
kono
parents:
diff changeset
1868 /* For unsigned, assume -1.0 is always representable. */
kono
parents:
diff changeset
1869 if (uns_p)
kono
parents:
diff changeset
1870 min = build_minus_one_cst (expr_type);
kono
parents:
diff changeset
1871 else
kono
parents:
diff changeset
1872 {
kono
parents:
diff changeset
1873 /* Use mpfr_snprintf rounding to compute the largest
kono
parents:
diff changeset
1874 representable decimal number less or equal than
kono
parents:
diff changeset
1875 (-1 << (prec - 1)) - 1. */
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1876 mpfr_set_si_2exp (m, -1, prec - 1, MPFR_RNDN);
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
1877 mpfr_sub_ui (m, m, 1, MPFR_RNDN);
111
kono
parents:
diff changeset
1878 mpfr_snprintf (buf, sizeof buf, "%.*RDe", p - 1, m);
kono
parents:
diff changeset
1879 decimal_real_from_string (&minval, buf);
kono
parents:
diff changeset
1880 min = build_real (expr_type, minval);
kono
parents:
diff changeset
1881 }
kono
parents:
diff changeset
1882 mpfr_clear (m);
kono
parents:
diff changeset
1883 }
kono
parents:
diff changeset
1884 else
kono
parents:
diff changeset
1885 return NULL_TREE;
kono
parents:
diff changeset
1886
kono
parents:
diff changeset
1887 t = fold_build2 (UNLE_EXPR, boolean_type_node, expr, min);
kono
parents:
diff changeset
1888 tt = fold_build2 (UNGE_EXPR, boolean_type_node, expr, max);
kono
parents:
diff changeset
1889 t = fold_build2 (TRUTH_OR_EXPR, boolean_type_node, t, tt);
kono
parents:
diff changeset
1890 if (integer_zerop (t))
kono
parents:
diff changeset
1891 return NULL_TREE;
kono
parents:
diff changeset
1892
kono
parents:
diff changeset
1893 if (flag_sanitize_undefined_trap_on_error)
kono
parents:
diff changeset
1894 fn = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
kono
parents:
diff changeset
1895 else
kono
parents:
diff changeset
1896 {
kono
parents:
diff changeset
1897 location_t *loc_ptr = NULL;
kono
parents:
diff changeset
1898 unsigned num_locations = 0;
kono
parents:
diff changeset
1899 /* Figure out if we can propagate location to ubsan_data and use new
kono
parents:
diff changeset
1900 style handlers in libubsan. */
kono
parents:
diff changeset
1901 if (ubsan_use_new_style_p (loc))
kono
parents:
diff changeset
1902 {
kono
parents:
diff changeset
1903 loc_ptr = &loc;
kono
parents:
diff changeset
1904 num_locations = 1;
kono
parents:
diff changeset
1905 }
kono
parents:
diff changeset
1906 /* Create the __ubsan_handle_float_cast_overflow fn call. */
kono
parents:
diff changeset
1907 tree data = ubsan_create_data ("__ubsan_float_cast_overflow_data",
kono
parents:
diff changeset
1908 num_locations, loc_ptr,
kono
parents:
diff changeset
1909 ubsan_type_descriptor (expr_type),
kono
parents:
diff changeset
1910 ubsan_type_descriptor (type), NULL_TREE,
kono
parents:
diff changeset
1911 NULL_TREE);
kono
parents:
diff changeset
1912 enum built_in_function bcode
kono
parents:
diff changeset
1913 = (flag_sanitize_recover & SANITIZE_FLOAT_CAST)
kono
parents:
diff changeset
1914 ? BUILT_IN_UBSAN_HANDLE_FLOAT_CAST_OVERFLOW
kono
parents:
diff changeset
1915 : BUILT_IN_UBSAN_HANDLE_FLOAT_CAST_OVERFLOW_ABORT;
kono
parents:
diff changeset
1916 fn = builtin_decl_explicit (bcode);
kono
parents:
diff changeset
1917 fn = build_call_expr_loc (loc, fn, 2,
kono
parents:
diff changeset
1918 build_fold_addr_expr_loc (loc, data),
kono
parents:
diff changeset
1919 ubsan_encode_value (expr));
kono
parents:
diff changeset
1920 }
kono
parents:
diff changeset
1921
kono
parents:
diff changeset
1922 return fold_build3 (COND_EXPR, void_type_node, t, fn, integer_zero_node);
kono
parents:
diff changeset
1923 }
kono
parents:
diff changeset
1924
kono
parents:
diff changeset
1925 /* Instrument values passed to function arguments with nonnull attribute. */
kono
parents:
diff changeset
1926
kono
parents:
diff changeset
1927 static void
kono
parents:
diff changeset
1928 instrument_nonnull_arg (gimple_stmt_iterator *gsi)
kono
parents:
diff changeset
1929 {
kono
parents:
diff changeset
1930 gimple *stmt = gsi_stmt (*gsi);
kono
parents:
diff changeset
1931 location_t loc[2];
kono
parents:
diff changeset
1932 /* infer_nonnull_range needs flag_delete_null_pointer_checks set,
kono
parents:
diff changeset
1933 while for nonnull sanitization it is clear. */
kono
parents:
diff changeset
1934 int save_flag_delete_null_pointer_checks = flag_delete_null_pointer_checks;
kono
parents:
diff changeset
1935 flag_delete_null_pointer_checks = 1;
kono
parents:
diff changeset
1936 loc[0] = gimple_location (stmt);
kono
parents:
diff changeset
1937 loc[1] = UNKNOWN_LOCATION;
kono
parents:
diff changeset
1938 for (unsigned int i = 0; i < gimple_call_num_args (stmt); i++)
kono
parents:
diff changeset
1939 {
kono
parents:
diff changeset
1940 tree arg = gimple_call_arg (stmt, i);
kono
parents:
diff changeset
1941 if (POINTER_TYPE_P (TREE_TYPE (arg))
kono
parents:
diff changeset
1942 && infer_nonnull_range_by_attribute (stmt, arg))
kono
parents:
diff changeset
1943 {
kono
parents:
diff changeset
1944 gimple *g;
kono
parents:
diff changeset
1945 if (!is_gimple_val (arg))
kono
parents:
diff changeset
1946 {
kono
parents:
diff changeset
1947 g = gimple_build_assign (make_ssa_name (TREE_TYPE (arg)), arg);
kono
parents:
diff changeset
1948 gimple_set_location (g, loc[0]);
kono
parents:
diff changeset
1949 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1950 arg = gimple_assign_lhs (g);
kono
parents:
diff changeset
1951 }
kono
parents:
diff changeset
1952
kono
parents:
diff changeset
1953 basic_block then_bb, fallthru_bb;
kono
parents:
diff changeset
1954 *gsi = create_cond_insert_point (gsi, true, false, true,
kono
parents:
diff changeset
1955 &then_bb, &fallthru_bb);
kono
parents:
diff changeset
1956 g = gimple_build_cond (EQ_EXPR, arg,
kono
parents:
diff changeset
1957 build_zero_cst (TREE_TYPE (arg)),
kono
parents:
diff changeset
1958 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
1959 gimple_set_location (g, loc[0]);
kono
parents:
diff changeset
1960 gsi_insert_after (gsi, g, GSI_NEW_STMT);
kono
parents:
diff changeset
1961
kono
parents:
diff changeset
1962 *gsi = gsi_after_labels (then_bb);
kono
parents:
diff changeset
1963 if (flag_sanitize_undefined_trap_on_error)
kono
parents:
diff changeset
1964 g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
kono
parents:
diff changeset
1965 else
kono
parents:
diff changeset
1966 {
kono
parents:
diff changeset
1967 tree data = ubsan_create_data ("__ubsan_nonnull_arg_data",
kono
parents:
diff changeset
1968 2, loc, NULL_TREE,
kono
parents:
diff changeset
1969 build_int_cst (integer_type_node,
kono
parents:
diff changeset
1970 i + 1),
kono
parents:
diff changeset
1971 NULL_TREE);
kono
parents:
diff changeset
1972 data = build_fold_addr_expr_loc (loc[0], data);
kono
parents:
diff changeset
1973 enum built_in_function bcode
kono
parents:
diff changeset
1974 = (flag_sanitize_recover & SANITIZE_NONNULL_ATTRIBUTE)
kono
parents:
diff changeset
1975 ? BUILT_IN_UBSAN_HANDLE_NONNULL_ARG
kono
parents:
diff changeset
1976 : BUILT_IN_UBSAN_HANDLE_NONNULL_ARG_ABORT;
kono
parents:
diff changeset
1977 tree fn = builtin_decl_explicit (bcode);
kono
parents:
diff changeset
1978
kono
parents:
diff changeset
1979 g = gimple_build_call (fn, 1, data);
kono
parents:
diff changeset
1980 }
kono
parents:
diff changeset
1981 gimple_set_location (g, loc[0]);
kono
parents:
diff changeset
1982 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
1983 ubsan_create_edge (g);
kono
parents:
diff changeset
1984 }
kono
parents:
diff changeset
1985 *gsi = gsi_for_stmt (stmt);
kono
parents:
diff changeset
1986 }
kono
parents:
diff changeset
1987 flag_delete_null_pointer_checks = save_flag_delete_null_pointer_checks;
kono
parents:
diff changeset
1988 }
kono
parents:
diff changeset
1989
kono
parents:
diff changeset
1990 /* Instrument returns in functions with returns_nonnull attribute. */
kono
parents:
diff changeset
1991
kono
parents:
diff changeset
1992 static void
kono
parents:
diff changeset
1993 instrument_nonnull_return (gimple_stmt_iterator *gsi)
kono
parents:
diff changeset
1994 {
kono
parents:
diff changeset
1995 greturn *stmt = as_a <greturn *> (gsi_stmt (*gsi));
kono
parents:
diff changeset
1996 location_t loc[2];
kono
parents:
diff changeset
1997 tree arg = gimple_return_retval (stmt);
kono
parents:
diff changeset
1998 /* infer_nonnull_range needs flag_delete_null_pointer_checks set,
kono
parents:
diff changeset
1999 while for nonnull return sanitization it is clear. */
kono
parents:
diff changeset
2000 int save_flag_delete_null_pointer_checks = flag_delete_null_pointer_checks;
kono
parents:
diff changeset
2001 flag_delete_null_pointer_checks = 1;
kono
parents:
diff changeset
2002 loc[0] = gimple_location (stmt);
kono
parents:
diff changeset
2003 loc[1] = UNKNOWN_LOCATION;
kono
parents:
diff changeset
2004 if (arg
kono
parents:
diff changeset
2005 && POINTER_TYPE_P (TREE_TYPE (arg))
kono
parents:
diff changeset
2006 && is_gimple_val (arg)
kono
parents:
diff changeset
2007 && infer_nonnull_range_by_attribute (stmt, arg))
kono
parents:
diff changeset
2008 {
kono
parents:
diff changeset
2009 basic_block then_bb, fallthru_bb;
kono
parents:
diff changeset
2010 *gsi = create_cond_insert_point (gsi, true, false, true,
kono
parents:
diff changeset
2011 &then_bb, &fallthru_bb);
kono
parents:
diff changeset
2012 gimple *g = gimple_build_cond (EQ_EXPR, arg,
kono
parents:
diff changeset
2013 build_zero_cst (TREE_TYPE (arg)),
kono
parents:
diff changeset
2014 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
2015 gimple_set_location (g, loc[0]);
kono
parents:
diff changeset
2016 gsi_insert_after (gsi, g, GSI_NEW_STMT);
kono
parents:
diff changeset
2017
kono
parents:
diff changeset
2018 *gsi = gsi_after_labels (then_bb);
kono
parents:
diff changeset
2019 if (flag_sanitize_undefined_trap_on_error)
kono
parents:
diff changeset
2020 g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
kono
parents:
diff changeset
2021 else
kono
parents:
diff changeset
2022 {
kono
parents:
diff changeset
2023 tree data = ubsan_create_data ("__ubsan_nonnull_return_data",
kono
parents:
diff changeset
2024 1, &loc[1], NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
2025 data = build_fold_addr_expr_loc (loc[0], data);
kono
parents:
diff changeset
2026 tree data2 = ubsan_create_data ("__ubsan_nonnull_return_data",
kono
parents:
diff changeset
2027 1, &loc[0], NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
2028 data2 = build_fold_addr_expr_loc (loc[0], data2);
kono
parents:
diff changeset
2029 enum built_in_function bcode
kono
parents:
diff changeset
2030 = (flag_sanitize_recover & SANITIZE_RETURNS_NONNULL_ATTRIBUTE)
kono
parents:
diff changeset
2031 ? BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_V1
kono
parents:
diff changeset
2032 : BUILT_IN_UBSAN_HANDLE_NONNULL_RETURN_V1_ABORT;
kono
parents:
diff changeset
2033 tree fn = builtin_decl_explicit (bcode);
kono
parents:
diff changeset
2034
kono
parents:
diff changeset
2035 g = gimple_build_call (fn, 2, data, data2);
kono
parents:
diff changeset
2036 }
kono
parents:
diff changeset
2037 gimple_set_location (g, loc[0]);
kono
parents:
diff changeset
2038 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
2039 ubsan_create_edge (g);
kono
parents:
diff changeset
2040 *gsi = gsi_for_stmt (stmt);
kono
parents:
diff changeset
2041 }
kono
parents:
diff changeset
2042 flag_delete_null_pointer_checks = save_flag_delete_null_pointer_checks;
kono
parents:
diff changeset
2043 }
kono
parents:
diff changeset
2044
kono
parents:
diff changeset
2045 /* Instrument memory references. Here we check whether the pointer
kono
parents:
diff changeset
2046 points to an out-of-bounds location. */
kono
parents:
diff changeset
2047
kono
parents:
diff changeset
2048 static void
kono
parents:
diff changeset
2049 instrument_object_size (gimple_stmt_iterator *gsi, tree t, bool is_lhs)
kono
parents:
diff changeset
2050 {
kono
parents:
diff changeset
2051 gimple *stmt = gsi_stmt (*gsi);
kono
parents:
diff changeset
2052 location_t loc = gimple_location (stmt);
kono
parents:
diff changeset
2053 tree type;
kono
parents:
diff changeset
2054 tree index = NULL_TREE;
kono
parents:
diff changeset
2055 HOST_WIDE_INT size_in_bytes;
kono
parents:
diff changeset
2056
kono
parents:
diff changeset
2057 type = TREE_TYPE (t);
kono
parents:
diff changeset
2058 if (VOID_TYPE_P (type))
kono
parents:
diff changeset
2059 return;
kono
parents:
diff changeset
2060
kono
parents:
diff changeset
2061 switch (TREE_CODE (t))
kono
parents:
diff changeset
2062 {
kono
parents:
diff changeset
2063 case COMPONENT_REF:
kono
parents:
diff changeset
2064 if (TREE_CODE (t) == COMPONENT_REF
kono
parents:
diff changeset
2065 && DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1)) != NULL_TREE)
kono
parents:
diff changeset
2066 {
kono
parents:
diff changeset
2067 tree repr = DECL_BIT_FIELD_REPRESENTATIVE (TREE_OPERAND (t, 1));
kono
parents:
diff changeset
2068 t = build3 (COMPONENT_REF, TREE_TYPE (repr), TREE_OPERAND (t, 0),
kono
parents:
diff changeset
2069 repr, TREE_OPERAND (t, 2));
kono
parents:
diff changeset
2070 }
kono
parents:
diff changeset
2071 break;
kono
parents:
diff changeset
2072 case ARRAY_REF:
kono
parents:
diff changeset
2073 index = TREE_OPERAND (t, 1);
kono
parents:
diff changeset
2074 break;
kono
parents:
diff changeset
2075 case INDIRECT_REF:
kono
parents:
diff changeset
2076 case MEM_REF:
kono
parents:
diff changeset
2077 case VAR_DECL:
kono
parents:
diff changeset
2078 case PARM_DECL:
kono
parents:
diff changeset
2079 case RESULT_DECL:
kono
parents:
diff changeset
2080 break;
kono
parents:
diff changeset
2081 default:
kono
parents:
diff changeset
2082 return;
kono
parents:
diff changeset
2083 }
kono
parents:
diff changeset
2084
kono
parents:
diff changeset
2085 size_in_bytes = int_size_in_bytes (type);
kono
parents:
diff changeset
2086 if (size_in_bytes <= 0)
kono
parents:
diff changeset
2087 return;
kono
parents:
diff changeset
2088
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2089 poly_int64 bitsize, bitpos;
111
kono
parents:
diff changeset
2090 tree offset;
kono
parents:
diff changeset
2091 machine_mode mode;
kono
parents:
diff changeset
2092 int volatilep = 0, reversep, unsignedp = 0;
kono
parents:
diff changeset
2093 tree inner = get_inner_reference (t, &bitsize, &bitpos, &offset, &mode,
kono
parents:
diff changeset
2094 &unsignedp, &reversep, &volatilep);
kono
parents:
diff changeset
2095
131
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2096 if (!multiple_p (bitpos, BITS_PER_UNIT)
84e7813d76e9 gcc-8.2
mir3636
parents: 111
diff changeset
2097 || maybe_ne (bitsize, size_in_bytes * BITS_PER_UNIT))
111
kono
parents:
diff changeset
2098 return;
kono
parents:
diff changeset
2099
kono
parents:
diff changeset
2100 bool decl_p = DECL_P (inner);
kono
parents:
diff changeset
2101 tree base;
kono
parents:
diff changeset
2102 if (decl_p)
kono
parents:
diff changeset
2103 {
kono
parents:
diff changeset
2104 if (DECL_REGISTER (inner))
kono
parents:
diff changeset
2105 return;
kono
parents:
diff changeset
2106 base = inner;
kono
parents:
diff changeset
2107 }
kono
parents:
diff changeset
2108 else if (TREE_CODE (inner) == MEM_REF)
kono
parents:
diff changeset
2109 base = TREE_OPERAND (inner, 0);
kono
parents:
diff changeset
2110 else
kono
parents:
diff changeset
2111 return;
kono
parents:
diff changeset
2112 tree ptr = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (t)), t);
kono
parents:
diff changeset
2113
kono
parents:
diff changeset
2114 while (TREE_CODE (base) == SSA_NAME)
kono
parents:
diff changeset
2115 {
kono
parents:
diff changeset
2116 gimple *def_stmt = SSA_NAME_DEF_STMT (base);
kono
parents:
diff changeset
2117 if (gimple_assign_ssa_name_copy_p (def_stmt)
kono
parents:
diff changeset
2118 || (gimple_assign_cast_p (def_stmt)
kono
parents:
diff changeset
2119 && POINTER_TYPE_P (TREE_TYPE (gimple_assign_rhs1 (def_stmt))))
kono
parents:
diff changeset
2120 || (is_gimple_assign (def_stmt)
kono
parents:
diff changeset
2121 && gimple_assign_rhs_code (def_stmt) == POINTER_PLUS_EXPR))
kono
parents:
diff changeset
2122 {
kono
parents:
diff changeset
2123 tree rhs1 = gimple_assign_rhs1 (def_stmt);
kono
parents:
diff changeset
2124 if (TREE_CODE (rhs1) == SSA_NAME
kono
parents:
diff changeset
2125 && SSA_NAME_OCCURS_IN_ABNORMAL_PHI (rhs1))
kono
parents:
diff changeset
2126 break;
kono
parents:
diff changeset
2127 else
kono
parents:
diff changeset
2128 base = rhs1;
kono
parents:
diff changeset
2129 }
kono
parents:
diff changeset
2130 else
kono
parents:
diff changeset
2131 break;
kono
parents:
diff changeset
2132 }
kono
parents:
diff changeset
2133
kono
parents:
diff changeset
2134 if (!POINTER_TYPE_P (TREE_TYPE (base)) && !DECL_P (base))
kono
parents:
diff changeset
2135 return;
kono
parents:
diff changeset
2136
kono
parents:
diff changeset
2137 tree sizet;
kono
parents:
diff changeset
2138 tree base_addr = base;
kono
parents:
diff changeset
2139 gimple *bos_stmt = NULL;
kono
parents:
diff changeset
2140 if (decl_p)
kono
parents:
diff changeset
2141 base_addr = build1 (ADDR_EXPR,
kono
parents:
diff changeset
2142 build_pointer_type (TREE_TYPE (base)), base);
kono
parents:
diff changeset
2143 unsigned HOST_WIDE_INT size;
kono
parents:
diff changeset
2144 if (compute_builtin_object_size (base_addr, 0, &size))
kono
parents:
diff changeset
2145 sizet = build_int_cst (sizetype, size);
kono
parents:
diff changeset
2146 else if (optimize)
kono
parents:
diff changeset
2147 {
kono
parents:
diff changeset
2148 if (LOCATION_LOCUS (loc) == UNKNOWN_LOCATION)
kono
parents:
diff changeset
2149 loc = input_location;
kono
parents:
diff changeset
2150 /* Generate __builtin_object_size call. */
kono
parents:
diff changeset
2151 sizet = builtin_decl_explicit (BUILT_IN_OBJECT_SIZE);
kono
parents:
diff changeset
2152 sizet = build_call_expr_loc (loc, sizet, 2, base_addr,
kono
parents:
diff changeset
2153 integer_zero_node);
kono
parents:
diff changeset
2154 sizet = force_gimple_operand_gsi (gsi, sizet, false, NULL_TREE, true,
kono
parents:
diff changeset
2155 GSI_SAME_STMT);
kono
parents:
diff changeset
2156 /* If the call above didn't end up being an integer constant, go one
kono
parents:
diff changeset
2157 statement back and get the __builtin_object_size stmt. Save it,
kono
parents:
diff changeset
2158 we might need it later. */
kono
parents:
diff changeset
2159 if (SSA_VAR_P (sizet))
kono
parents:
diff changeset
2160 {
kono
parents:
diff changeset
2161 gsi_prev (gsi);
kono
parents:
diff changeset
2162 bos_stmt = gsi_stmt (*gsi);
kono
parents:
diff changeset
2163
kono
parents:
diff changeset
2164 /* Move on to where we were. */
kono
parents:
diff changeset
2165 gsi_next (gsi);
kono
parents:
diff changeset
2166 }
kono
parents:
diff changeset
2167 }
kono
parents:
diff changeset
2168 else
kono
parents:
diff changeset
2169 return;
kono
parents:
diff changeset
2170
kono
parents:
diff changeset
2171 /* Generate UBSAN_OBJECT_SIZE (ptr, ptr+sizeof(*ptr)-base, objsize, ckind)
kono
parents:
diff changeset
2172 call. */
kono
parents:
diff changeset
2173 /* ptr + sizeof (*ptr) - base */
kono
parents:
diff changeset
2174 t = fold_build2 (MINUS_EXPR, sizetype,
kono
parents:
diff changeset
2175 fold_convert (pointer_sized_int_node, ptr),
kono
parents:
diff changeset
2176 fold_convert (pointer_sized_int_node, base_addr));
kono
parents:
diff changeset
2177 t = fold_build2 (PLUS_EXPR, sizetype, t, TYPE_SIZE_UNIT (type));
kono
parents:
diff changeset
2178
kono
parents:
diff changeset
2179 /* Perhaps we can omit the check. */
kono
parents:
diff changeset
2180 if (TREE_CODE (t) == INTEGER_CST
kono
parents:
diff changeset
2181 && TREE_CODE (sizet) == INTEGER_CST
kono
parents:
diff changeset
2182 && tree_int_cst_le (t, sizet))
kono
parents:
diff changeset
2183 return;
kono
parents:
diff changeset
2184
kono
parents:
diff changeset
2185 if (index != NULL_TREE
kono
parents:
diff changeset
2186 && TREE_CODE (index) == SSA_NAME
kono
parents:
diff changeset
2187 && TREE_CODE (sizet) == INTEGER_CST)
kono
parents:
diff changeset
2188 {
kono
parents:
diff changeset
2189 gimple *def = SSA_NAME_DEF_STMT (index);
kono
parents:
diff changeset
2190 if (is_gimple_assign (def)
kono
parents:
diff changeset
2191 && gimple_assign_rhs_code (def) == BIT_AND_EXPR
kono
parents:
diff changeset
2192 && TREE_CODE (gimple_assign_rhs2 (def)) == INTEGER_CST)
kono
parents:
diff changeset
2193 {
kono
parents:
diff changeset
2194 tree cst = gimple_assign_rhs2 (def);
kono
parents:
diff changeset
2195 tree sz = fold_build2 (EXACT_DIV_EXPR, sizetype, sizet,
kono
parents:
diff changeset
2196 TYPE_SIZE_UNIT (type));
kono
parents:
diff changeset
2197 if (tree_int_cst_sgn (cst) >= 0
kono
parents:
diff changeset
2198 && tree_int_cst_lt (cst, sz))
kono
parents:
diff changeset
2199 return;
kono
parents:
diff changeset
2200 }
kono
parents:
diff changeset
2201 }
kono
parents:
diff changeset
2202
kono
parents:
diff changeset
2203 if (bos_stmt && gimple_call_builtin_p (bos_stmt, BUILT_IN_OBJECT_SIZE))
kono
parents:
diff changeset
2204 ubsan_create_edge (bos_stmt);
kono
parents:
diff changeset
2205
kono
parents:
diff changeset
2206 /* We have to emit the check. */
kono
parents:
diff changeset
2207 t = force_gimple_operand_gsi (gsi, t, true, NULL_TREE, true,
kono
parents:
diff changeset
2208 GSI_SAME_STMT);
kono
parents:
diff changeset
2209 ptr = force_gimple_operand_gsi (gsi, ptr, true, NULL_TREE, true,
kono
parents:
diff changeset
2210 GSI_SAME_STMT);
kono
parents:
diff changeset
2211 tree ckind = build_int_cst (unsigned_char_type_node,
kono
parents:
diff changeset
2212 is_lhs ? UBSAN_STORE_OF : UBSAN_LOAD_OF);
kono
parents:
diff changeset
2213 gimple *g = gimple_build_call_internal (IFN_UBSAN_OBJECT_SIZE, 4,
kono
parents:
diff changeset
2214 ptr, t, sizet, ckind);
kono
parents:
diff changeset
2215 gimple_set_location (g, loc);
kono
parents:
diff changeset
2216 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
2217 }
kono
parents:
diff changeset
2218
kono
parents:
diff changeset
2219 /* Instrument values passed to builtin functions. */
kono
parents:
diff changeset
2220
kono
parents:
diff changeset
2221 static void
kono
parents:
diff changeset
2222 instrument_builtin (gimple_stmt_iterator *gsi)
kono
parents:
diff changeset
2223 {
kono
parents:
diff changeset
2224 gimple *stmt = gsi_stmt (*gsi);
kono
parents:
diff changeset
2225 location_t loc = gimple_location (stmt);
kono
parents:
diff changeset
2226 tree arg;
kono
parents:
diff changeset
2227 enum built_in_function fcode
kono
parents:
diff changeset
2228 = DECL_FUNCTION_CODE (gimple_call_fndecl (stmt));
kono
parents:
diff changeset
2229 int kind = 0;
kono
parents:
diff changeset
2230 switch (fcode)
kono
parents:
diff changeset
2231 {
kono
parents:
diff changeset
2232 CASE_INT_FN (BUILT_IN_CLZ):
kono
parents:
diff changeset
2233 kind = 1;
kono
parents:
diff changeset
2234 gcc_fallthrough ();
kono
parents:
diff changeset
2235 CASE_INT_FN (BUILT_IN_CTZ):
kono
parents:
diff changeset
2236 arg = gimple_call_arg (stmt, 0);
kono
parents:
diff changeset
2237 if (!integer_nonzerop (arg))
kono
parents:
diff changeset
2238 {
kono
parents:
diff changeset
2239 gimple *g;
kono
parents:
diff changeset
2240 if (!is_gimple_val (arg))
kono
parents:
diff changeset
2241 {
kono
parents:
diff changeset
2242 g = gimple_build_assign (make_ssa_name (TREE_TYPE (arg)), arg);
kono
parents:
diff changeset
2243 gimple_set_location (g, loc);
kono
parents:
diff changeset
2244 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
2245 arg = gimple_assign_lhs (g);
kono
parents:
diff changeset
2246 }
kono
parents:
diff changeset
2247
kono
parents:
diff changeset
2248 basic_block then_bb, fallthru_bb;
kono
parents:
diff changeset
2249 *gsi = create_cond_insert_point (gsi, true, false, true,
kono
parents:
diff changeset
2250 &then_bb, &fallthru_bb);
kono
parents:
diff changeset
2251 g = gimple_build_cond (EQ_EXPR, arg,
kono
parents:
diff changeset
2252 build_zero_cst (TREE_TYPE (arg)),
kono
parents:
diff changeset
2253 NULL_TREE, NULL_TREE);
kono
parents:
diff changeset
2254 gimple_set_location (g, loc);
kono
parents:
diff changeset
2255 gsi_insert_after (gsi, g, GSI_NEW_STMT);
kono
parents:
diff changeset
2256
kono
parents:
diff changeset
2257 *gsi = gsi_after_labels (then_bb);
kono
parents:
diff changeset
2258 if (flag_sanitize_undefined_trap_on_error)
kono
parents:
diff changeset
2259 g = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
kono
parents:
diff changeset
2260 else
kono
parents:
diff changeset
2261 {
kono
parents:
diff changeset
2262 tree t = build_int_cst (unsigned_char_type_node, kind);
kono
parents:
diff changeset
2263 tree data = ubsan_create_data ("__ubsan_builtin_data",
kono
parents:
diff changeset
2264 1, &loc, NULL_TREE, t, NULL_TREE);
kono
parents:
diff changeset
2265 data = build_fold_addr_expr_loc (loc, data);
kono
parents:
diff changeset
2266 enum built_in_function bcode
kono
parents:
diff changeset
2267 = (flag_sanitize_recover & SANITIZE_BUILTIN)
kono
parents:
diff changeset
2268 ? BUILT_IN_UBSAN_HANDLE_INVALID_BUILTIN
kono
parents:
diff changeset
2269 : BUILT_IN_UBSAN_HANDLE_INVALID_BUILTIN_ABORT;
kono
parents:
diff changeset
2270 tree fn = builtin_decl_explicit (bcode);
kono
parents:
diff changeset
2271
kono
parents:
diff changeset
2272 g = gimple_build_call (fn, 1, data);
kono
parents:
diff changeset
2273 }
kono
parents:
diff changeset
2274 gimple_set_location (g, loc);
kono
parents:
diff changeset
2275 gsi_insert_before (gsi, g, GSI_SAME_STMT);
kono
parents:
diff changeset
2276 ubsan_create_edge (g);
kono
parents:
diff changeset
2277 }
kono
parents:
diff changeset
2278 *gsi = gsi_for_stmt (stmt);
kono
parents:
diff changeset
2279 break;
kono
parents:
diff changeset
2280 default:
kono
parents:
diff changeset
2281 break;
kono
parents:
diff changeset
2282 }
kono
parents:
diff changeset
2283 }
kono
parents:
diff changeset
2284
kono
parents:
diff changeset
2285 namespace {
kono
parents:
diff changeset
2286
kono
parents:
diff changeset
2287 const pass_data pass_data_ubsan =
kono
parents:
diff changeset
2288 {
kono
parents:
diff changeset
2289 GIMPLE_PASS, /* type */
kono
parents:
diff changeset
2290 "ubsan", /* name */
kono
parents:
diff changeset
2291 OPTGROUP_NONE, /* optinfo_flags */
kono
parents:
diff changeset
2292 TV_TREE_UBSAN, /* tv_id */
kono
parents:
diff changeset
2293 ( PROP_cfg | PROP_ssa ), /* properties_required */
kono
parents:
diff changeset
2294 0, /* properties_provided */
kono
parents:
diff changeset
2295 0, /* properties_destroyed */
kono
parents:
diff changeset
2296 0, /* todo_flags_start */
kono
parents:
diff changeset
2297 TODO_update_ssa, /* todo_flags_finish */
kono
parents:
diff changeset
2298 };
kono
parents:
diff changeset
2299
kono
parents:
diff changeset
2300 class pass_ubsan : public gimple_opt_pass
kono
parents:
diff changeset
2301 {
kono
parents:
diff changeset
2302 public:
kono
parents:
diff changeset
2303 pass_ubsan (gcc::context *ctxt)
kono
parents:
diff changeset
2304 : gimple_opt_pass (pass_data_ubsan, ctxt)
kono
parents:
diff changeset
2305 {}
kono
parents:
diff changeset
2306
kono
parents:
diff changeset
2307 /* opt_pass methods: */
kono
parents:
diff changeset
2308 virtual bool gate (function *)
kono
parents:
diff changeset
2309 {
kono
parents:
diff changeset
2310 return sanitize_flags_p ((SANITIZE_NULL | SANITIZE_SI_OVERFLOW
kono
parents:
diff changeset
2311 | SANITIZE_BOOL | SANITIZE_ENUM
kono
parents:
diff changeset
2312 | SANITIZE_ALIGNMENT
kono
parents:
diff changeset
2313 | SANITIZE_NONNULL_ATTRIBUTE
kono
parents:
diff changeset
2314 | SANITIZE_RETURNS_NONNULL_ATTRIBUTE
kono
parents:
diff changeset
2315 | SANITIZE_OBJECT_SIZE
kono
parents:
diff changeset
2316 | SANITIZE_POINTER_OVERFLOW
kono
parents:
diff changeset
2317 | SANITIZE_BUILTIN));
kono
parents:
diff changeset
2318 }
kono
parents:
diff changeset
2319
kono
parents:
diff changeset
2320 virtual unsigned int execute (function *);
kono
parents:
diff changeset
2321
kono
parents:
diff changeset
2322 }; // class pass_ubsan
kono
parents:
diff changeset
2323
kono
parents:
diff changeset
2324 unsigned int
kono
parents:
diff changeset
2325 pass_ubsan::execute (function *fun)
kono
parents:
diff changeset
2326 {
kono
parents:
diff changeset
2327 basic_block bb;
kono
parents:
diff changeset
2328 gimple_stmt_iterator gsi;
kono
parents:
diff changeset
2329 unsigned int ret = 0;
kono
parents:
diff changeset
2330
kono
parents:
diff changeset
2331 initialize_sanitizer_builtins ();
kono
parents:
diff changeset
2332
kono
parents:
diff changeset
2333 FOR_EACH_BB_FN (bb, fun)
kono
parents:
diff changeset
2334 {
kono
parents:
diff changeset
2335 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
kono
parents:
diff changeset
2336 {
kono
parents:
diff changeset
2337 gimple *stmt = gsi_stmt (gsi);
kono
parents:
diff changeset
2338 if (is_gimple_debug (stmt) || gimple_clobber_p (stmt))
kono
parents:
diff changeset
2339 {
kono
parents:
diff changeset
2340 gsi_next (&gsi);
kono
parents:
diff changeset
2341 continue;
kono
parents:
diff changeset
2342 }
kono
parents:
diff changeset
2343
kono
parents:
diff changeset
2344 if ((sanitize_flags_p (SANITIZE_SI_OVERFLOW, fun->decl))
kono
parents:
diff changeset
2345 && is_gimple_assign (stmt))
kono
parents:
diff changeset
2346 instrument_si_overflow (gsi);
kono
parents:
diff changeset
2347
kono
parents:
diff changeset
2348 if (sanitize_flags_p (SANITIZE_NULL | SANITIZE_ALIGNMENT, fun->decl))
kono
parents:
diff changeset
2349 {
kono
parents:
diff changeset
2350 if (gimple_store_p (stmt))
kono
parents:
diff changeset
2351 instrument_null (gsi, gimple_get_lhs (stmt), true);
kono
parents:
diff changeset
2352 if (gimple_assign_single_p (stmt))
kono
parents:
diff changeset
2353 instrument_null (gsi, gimple_assign_rhs1 (stmt), false);
kono
parents:
diff changeset
2354 if (is_gimple_call (stmt))
kono
parents:
diff changeset
2355 {
kono
parents:
diff changeset
2356 unsigned args_num = gimple_call_num_args (stmt);
kono
parents:
diff changeset
2357 for (unsigned i = 0; i < args_num; ++i)
kono
parents:
diff changeset
2358 {
kono
parents:
diff changeset
2359 tree arg = gimple_call_arg (stmt, i);
kono
parents:
diff changeset
2360 if (is_gimple_reg (arg) || is_gimple_min_invariant (arg))
kono
parents:
diff changeset
2361 continue;
kono
parents:
diff changeset
2362 instrument_null (gsi, arg, false);
kono
parents:
diff changeset
2363 }
kono
parents:
diff changeset
2364 }
kono
parents:
diff changeset
2365 }
kono
parents:
diff changeset
2366
kono
parents:
diff changeset
2367 if (sanitize_flags_p (SANITIZE_BOOL | SANITIZE_ENUM, fun->decl)
kono
parents:
diff changeset
2368 && gimple_assign_load_p (stmt))
kono
parents:
diff changeset
2369 {
kono
parents:
diff changeset
2370 instrument_bool_enum_load (&gsi);
kono
parents:
diff changeset
2371 bb = gimple_bb (stmt);
kono
parents:
diff changeset
2372 }
kono
parents:
diff changeset
2373
kono
parents:
diff changeset
2374 if (sanitize_flags_p (SANITIZE_NONNULL_ATTRIBUTE, fun->decl)
kono
parents:
diff changeset
2375 && is_gimple_call (stmt)
kono
parents:
diff changeset
2376 && !gimple_call_internal_p (stmt))
kono
parents:
diff changeset
2377 {
kono
parents:
diff changeset
2378 instrument_nonnull_arg (&gsi);
kono
parents:
diff changeset
2379 bb = gimple_bb (stmt);
kono
parents:
diff changeset
2380 }
kono
parents:
diff changeset
2381
kono
parents:
diff changeset
2382 if (sanitize_flags_p (SANITIZE_BUILTIN, fun->decl)
kono
parents:
diff changeset
2383 && gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
kono
parents:
diff changeset
2384 {
kono
parents:
diff changeset
2385 instrument_builtin (&gsi);
kono
parents:
diff changeset
2386 bb = gimple_bb (stmt);
kono
parents:
diff changeset
2387 }
kono
parents:
diff changeset
2388
kono
parents:
diff changeset
2389 if (sanitize_flags_p (SANITIZE_RETURNS_NONNULL_ATTRIBUTE, fun->decl)
kono
parents:
diff changeset
2390 && gimple_code (stmt) == GIMPLE_RETURN)
kono
parents:
diff changeset
2391 {
kono
parents:
diff changeset
2392 instrument_nonnull_return (&gsi);
kono
parents:
diff changeset
2393 bb = gimple_bb (stmt);
kono
parents:
diff changeset
2394 }
kono
parents:
diff changeset
2395
kono
parents:
diff changeset
2396 if (sanitize_flags_p (SANITIZE_OBJECT_SIZE, fun->decl))
kono
parents:
diff changeset
2397 {
kono
parents:
diff changeset
2398 if (gimple_store_p (stmt))
kono
parents:
diff changeset
2399 instrument_object_size (&gsi, gimple_get_lhs (stmt), true);
kono
parents:
diff changeset
2400 if (gimple_assign_load_p (stmt))
kono
parents:
diff changeset
2401 instrument_object_size (&gsi, gimple_assign_rhs1 (stmt),
kono
parents:
diff changeset
2402 false);
kono
parents:
diff changeset
2403 if (is_gimple_call (stmt))
kono
parents:
diff changeset
2404 {
kono
parents:
diff changeset
2405 unsigned args_num = gimple_call_num_args (stmt);
kono
parents:
diff changeset
2406 for (unsigned i = 0; i < args_num; ++i)
kono
parents:
diff changeset
2407 {
kono
parents:
diff changeset
2408 tree arg = gimple_call_arg (stmt, i);
kono
parents:
diff changeset
2409 if (is_gimple_reg (arg) || is_gimple_min_invariant (arg))
kono
parents:
diff changeset
2410 continue;
kono
parents:
diff changeset
2411 instrument_object_size (&gsi, arg, false);
kono
parents:
diff changeset
2412 }
kono
parents:
diff changeset
2413 }
kono
parents:
diff changeset
2414 }
kono
parents:
diff changeset
2415
kono
parents:
diff changeset
2416 if (sanitize_flags_p (SANITIZE_POINTER_OVERFLOW, fun->decl))
kono
parents:
diff changeset
2417 {
kono
parents:
diff changeset
2418 if (is_gimple_assign (stmt)
kono
parents:
diff changeset
2419 && gimple_assign_rhs_code (stmt) == POINTER_PLUS_EXPR)
kono
parents:
diff changeset
2420 instrument_pointer_overflow (&gsi,
kono
parents:
diff changeset
2421 gimple_assign_rhs1 (stmt),
kono
parents:
diff changeset
2422 gimple_assign_rhs2 (stmt));
kono
parents:
diff changeset
2423 if (gimple_store_p (stmt))
kono
parents:
diff changeset
2424 maybe_instrument_pointer_overflow (&gsi,
kono
parents:
diff changeset
2425 gimple_get_lhs (stmt));
kono
parents:
diff changeset
2426 if (gimple_assign_single_p (stmt))
kono
parents:
diff changeset
2427 maybe_instrument_pointer_overflow (&gsi,
kono
parents:
diff changeset
2428 gimple_assign_rhs1 (stmt));
kono
parents:
diff changeset
2429 if (is_gimple_call (stmt))
kono
parents:
diff changeset
2430 {
kono
parents:
diff changeset
2431 unsigned args_num = gimple_call_num_args (stmt);
kono
parents:
diff changeset
2432 for (unsigned i = 0; i < args_num; ++i)
kono
parents:
diff changeset
2433 {
kono
parents:
diff changeset
2434 tree arg = gimple_call_arg (stmt, i);
kono
parents:
diff changeset
2435 if (is_gimple_reg (arg))
kono
parents:
diff changeset
2436 continue;
kono
parents:
diff changeset
2437 maybe_instrument_pointer_overflow (&gsi, arg);
kono
parents:
diff changeset
2438 }
kono
parents:
diff changeset
2439 }
kono
parents:
diff changeset
2440 }
kono
parents:
diff changeset
2441
kono
parents:
diff changeset
2442 gsi_next (&gsi);
kono
parents:
diff changeset
2443 }
kono
parents:
diff changeset
2444 if (gimple_purge_dead_eh_edges (bb))
kono
parents:
diff changeset
2445 ret = TODO_cleanup_cfg;
kono
parents:
diff changeset
2446 }
kono
parents:
diff changeset
2447 return ret;
kono
parents:
diff changeset
2448 }
kono
parents:
diff changeset
2449
kono
parents:
diff changeset
2450 } // anon namespace
kono
parents:
diff changeset
2451
kono
parents:
diff changeset
2452 gimple_opt_pass *
kono
parents:
diff changeset
2453 make_pass_ubsan (gcc::context *ctxt)
kono
parents:
diff changeset
2454 {
kono
parents:
diff changeset
2455 return new pass_ubsan (ctxt);
kono
parents:
diff changeset
2456 }
kono
parents:
diff changeset
2457
kono
parents:
diff changeset
2458 #include "gt-ubsan.h"