2013-10-18 Jan-Benedict Glaw <jbglaw@lug-owl.de>
[official-gcc.git] / gcc / ubsan.c
blob9dc19c9d29add73ab8d44e5ff5fa6539fefbddc8
1 /* UndefinedBehaviorSanitizer, undefined behavior detector.
2 Copyright (C) 2013 Free Software Foundation, Inc.
3 Contributed by Marek Polacek <polacek@redhat.com>
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
10 version.
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "tree.h"
25 #include "cgraph.h"
26 #include "gimple.h"
27 #include "hashtab.h"
28 #include "pointer-set.h"
29 #include "output.h"
30 #include "tm_p.h"
31 #include "toplev.h"
32 #include "ubsan.h"
33 #include "c-family/c-common.h"
35 /* Map from a tree to a VAR_DECL tree. */
37 struct GTY(()) tree_type_map {
38 struct tree_map_base type;
39 tree decl;
42 #define tree_type_map_eq tree_map_base_eq
43 #define tree_type_map_hash tree_map_base_hash
44 #define tree_type_map_marked_p tree_map_base_marked_p
46 static GTY ((if_marked ("tree_type_map_marked_p"), param_is (struct tree_type_map)))
47 htab_t decl_tree_for_type;
49 /* Lookup a VAR_DECL for TYPE, and return it if we find one. */
51 static tree
52 decl_for_type_lookup (tree type)
54 /* If the hash table is not initialized yet, create it now. */
55 if (decl_tree_for_type == NULL)
57 decl_tree_for_type = htab_create_ggc (10, tree_type_map_hash,
58 tree_type_map_eq, 0);
59 /* That also means we don't have to bother with the lookup. */
60 return NULL_TREE;
63 struct tree_type_map *h, in;
64 in.type.from = type;
66 h = (struct tree_type_map *)
67 htab_find_with_hash (decl_tree_for_type, &in, TYPE_UID (type));
68 return h ? h->decl : NULL_TREE;
71 /* Insert a mapping TYPE->DECL in the VAR_DECL for type hashtable. */
73 static void
74 decl_for_type_insert (tree type, tree decl)
76 struct tree_type_map *h;
77 void **slot;
79 h = ggc_alloc_tree_type_map ();
80 h->type.from = type;
81 h->decl = decl;
82 slot = htab_find_slot_with_hash (decl_tree_for_type, h, TYPE_UID (type),
83 INSERT);
84 *(struct tree_type_map **) slot = h;
87 /* Helper routine, which encodes a value in the pointer_sized_int_node.
88 Arguments with precision <= POINTER_SIZE are passed directly,
89 the rest is passed by reference. T is a value we are to encode. */
91 tree
92 ubsan_encode_value (tree t)
94 tree type = TREE_TYPE (t);
95 switch (TREE_CODE (type))
97 case INTEGER_TYPE:
98 if (TYPE_PRECISION (type) <= POINTER_SIZE)
99 return fold_build1 (NOP_EXPR, pointer_sized_int_node, t);
100 else
101 return build_fold_addr_expr (t);
102 case REAL_TYPE:
104 unsigned int bitsize = GET_MODE_BITSIZE (TYPE_MODE (type));
105 if (bitsize <= POINTER_SIZE)
107 tree itype = build_nonstandard_integer_type (bitsize, true);
108 t = fold_build1 (VIEW_CONVERT_EXPR, itype, t);
109 return fold_convert (pointer_sized_int_node, t);
111 else
113 if (!TREE_ADDRESSABLE (t))
115 /* The reason for this is that we don't want to pessimize
116 code by making vars unnecessarily addressable. */
117 tree var = create_tmp_var (TREE_TYPE (t), NULL);
118 tree tem = build2 (MODIFY_EXPR, void_type_node, var, t);
119 t = build_fold_addr_expr (var);
120 return build2 (COMPOUND_EXPR, TREE_TYPE (t), tem, t);
122 else
123 return build_fold_addr_expr (t);
126 default:
127 gcc_unreachable ();
131 /* Build
132 struct __ubsan_type_descriptor
134 unsigned short __typekind;
135 unsigned short __typeinfo;
136 char __typename[];
138 type. */
140 static tree
141 ubsan_type_descriptor_type (void)
143 static const char *field_names[3]
144 = { "__typekind", "__typeinfo", "__typename" };
145 tree fields[3], ret;
146 tree itype = build_range_type (sizetype, size_zero_node, NULL_TREE);
147 tree flex_arr_type = build_array_type (char_type_node, itype);
149 ret = make_node (RECORD_TYPE);
150 for (int i = 0; i < 3; i++)
152 fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
153 get_identifier (field_names[i]),
154 (i == 2) ? flex_arr_type
155 : short_unsigned_type_node);
156 DECL_CONTEXT (fields[i]) = ret;
157 if (i)
158 DECL_CHAIN (fields[i - 1]) = fields[i];
160 TYPE_FIELDS (ret) = fields[0];
161 TYPE_NAME (ret) = get_identifier ("__ubsan_type_descriptor");
162 layout_type (ret);
163 return ret;
166 /* Build
167 struct __ubsan_source_location
169 const char *__filename;
170 unsigned int __line;
171 unsigned int __column;
173 type. */
175 static tree
176 ubsan_source_location_type (void)
178 static const char *field_names[3]
179 = { "__filename", "__line", "__column" };
180 tree fields[3], ret;
181 tree const_char_type = build_qualified_type (char_type_node,
182 TYPE_QUAL_CONST);
184 ret = make_node (RECORD_TYPE);
185 for (int i = 0; i < 3; i++)
187 fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL,
188 get_identifier (field_names[i]),
189 (i == 0) ? build_pointer_type (const_char_type)
190 : unsigned_type_node);
191 DECL_CONTEXT (fields[i]) = ret;
192 if (i)
193 DECL_CHAIN (fields[i - 1]) = fields[i];
195 TYPE_FIELDS (ret) = fields[0];
196 TYPE_NAME (ret) = get_identifier ("__ubsan_source_location");
197 layout_type (ret);
198 return ret;
201 /* Helper routine that returns a CONSTRUCTOR of __ubsan_source_location
202 type with its fields filled from a location_t LOC. */
204 static tree
205 ubsan_source_location (location_t loc)
207 expanded_location xloc;
208 tree type = ubsan_source_location_type ();
210 xloc = expand_location (loc);
212 /* Fill in the values from LOC. */
213 size_t len = strlen (xloc.file);
214 tree str = build_string (len + 1, xloc.file);
215 TREE_TYPE (str) = build_array_type (char_type_node,
216 build_index_type (size_int (len)));
217 TREE_READONLY (str) = 1;
218 TREE_STATIC (str) = 1;
219 str = build_fold_addr_expr_loc (loc, str);
220 tree ctor = build_constructor_va (type, 3, NULL_TREE, str, NULL_TREE,
221 build_int_cst (unsigned_type_node,
222 xloc.line), NULL_TREE,
223 build_int_cst (unsigned_type_node,
224 xloc.column));
225 TREE_CONSTANT (ctor) = 1;
226 TREE_STATIC (ctor) = 1;
228 return ctor;
231 /* This routine returns a magic number for TYPE. */
233 static unsigned short
234 get_ubsan_type_info_for_type (tree type)
236 gcc_assert (TYPE_SIZE (type) && host_integerp (TYPE_SIZE (type), 1));
237 int prec = exact_log2 (tree_low_cst (TYPE_SIZE (type), 1));
238 gcc_assert (prec != -1);
239 return (prec << 1) | !TYPE_UNSIGNED (type);
242 /* Helper routine that returns ADDR_EXPR of a VAR_DECL of a type
243 descriptor. It first looks into the pointer map; if not found,
244 create the VAR_DECL, put it into the pointer map and return the
245 ADDR_EXPR of it. TYPE describes a particular type. */
247 tree
248 ubsan_type_descriptor (tree type)
250 /* See through any typedefs. */
251 type = TYPE_MAIN_VARIANT (type);
253 tree decl = decl_for_type_lookup (type);
254 if (decl != NULL_TREE)
255 return decl;
257 tree dtype = ubsan_type_descriptor_type ();
258 const char *tname;
259 unsigned short tkind, tinfo;
261 /* At least for INTEGER_TYPE/REAL_TYPE/COMPLEX_TYPE, this should work.
262 For e.g. type_unsigned_for (type) or bit-fields, the TYPE_NAME
263 would be NULL. */
264 if (TYPE_NAME (type) != NULL)
266 if (TREE_CODE (TYPE_NAME (type)) == IDENTIFIER_NODE)
267 tname = IDENTIFIER_POINTER (TYPE_NAME (type));
268 else
269 tname = IDENTIFIER_POINTER (DECL_NAME (TYPE_NAME (type)));
271 else
272 tname = "<unknown>";
274 if (TREE_CODE (type) == INTEGER_TYPE)
276 /* For INTEGER_TYPE, this is 0x0000. */
277 tkind = 0x000;
278 tinfo = get_ubsan_type_info_for_type (type);
280 else if (TREE_CODE (type) == REAL_TYPE)
281 /* We don't have float support yet. */
282 gcc_unreachable ();
283 else
284 gcc_unreachable ();
286 /* Create a new VAR_DECL of type descriptor. */
287 char tmp_name[32];
288 static unsigned int type_var_id_num;
289 ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lubsan_type", type_var_id_num++);
290 decl = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (tmp_name),
291 dtype);
292 TREE_STATIC (decl) = 1;
293 TREE_PUBLIC (decl) = 0;
294 DECL_ARTIFICIAL (decl) = 1;
295 DECL_IGNORED_P (decl) = 1;
296 DECL_EXTERNAL (decl) = 0;
298 size_t len = strlen (tname);
299 tree str = build_string (len + 1, tname);
300 TREE_TYPE (str) = build_array_type (char_type_node,
301 build_index_type (size_int (len)));
302 TREE_READONLY (str) = 1;
303 TREE_STATIC (str) = 1;
304 tree ctor = build_constructor_va (dtype, 3, NULL_TREE,
305 build_int_cst (short_unsigned_type_node,
306 tkind), NULL_TREE,
307 build_int_cst (short_unsigned_type_node,
308 tinfo), NULL_TREE, str);
309 TREE_CONSTANT (ctor) = 1;
310 TREE_STATIC (ctor) = 1;
311 DECL_INITIAL (decl) = ctor;
312 rest_of_decl_compilation (decl, 1, 0);
314 /* Save the address of the VAR_DECL into the pointer map. */
315 decl = build_fold_addr_expr (decl);
316 decl_for_type_insert (type, decl);
318 return decl;
321 /* Create a structure for the ubsan library. NAME is a name of the new
322 structure. The arguments in ... are of __ubsan_type_descriptor type
323 and there are at most two of them. */
325 tree
326 ubsan_create_data (const char *name, location_t loc, ...)
328 va_list args;
329 tree ret, t;
330 tree fields[3];
331 vec<tree, va_gc> *saved_args = NULL;
332 size_t i = 0;
334 /* Firstly, create a pointer to type descriptor type. */
335 tree td_type = ubsan_type_descriptor_type ();
336 TYPE_READONLY (td_type) = 1;
337 td_type = build_pointer_type (td_type);
339 /* Create the structure type. */
340 ret = make_node (RECORD_TYPE);
341 if (loc != UNKNOWN_LOCATION)
343 fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
344 ubsan_source_location_type ());
345 DECL_CONTEXT (fields[i]) = ret;
346 i++;
349 va_start (args, loc);
350 for (t = va_arg (args, tree); t != NULL_TREE;
351 i++, t = va_arg (args, tree))
353 gcc_checking_assert (i < 3);
354 /* Save the tree argument for later use. */
355 vec_safe_push (saved_args, t);
356 fields[i] = build_decl (UNKNOWN_LOCATION, FIELD_DECL, NULL_TREE,
357 td_type);
358 DECL_CONTEXT (fields[i]) = ret;
359 if (i)
360 DECL_CHAIN (fields[i - 1]) = fields[i];
362 TYPE_FIELDS (ret) = fields[0];
363 TYPE_NAME (ret) = get_identifier (name);
364 layout_type (ret);
365 va_end (args);
367 /* Now, fill in the type. */
368 char tmp_name[32];
369 static unsigned int ubsan_var_id_num;
370 ASM_GENERATE_INTERNAL_LABEL (tmp_name, "Lubsan_data", ubsan_var_id_num++);
371 tree var = build_decl (UNKNOWN_LOCATION, VAR_DECL, get_identifier (tmp_name),
372 ret);
373 TREE_STATIC (var) = 1;
374 TREE_PUBLIC (var) = 0;
375 DECL_ARTIFICIAL (var) = 1;
376 DECL_IGNORED_P (var) = 1;
377 DECL_EXTERNAL (var) = 0;
379 vec<constructor_elt, va_gc> *v;
380 vec_alloc (v, i);
381 tree ctor = build_constructor (ret, v);
383 /* If desirable, set the __ubsan_source_location element. */
384 if (loc != UNKNOWN_LOCATION)
385 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, ubsan_source_location (loc));
387 size_t nelts = vec_safe_length (saved_args);
388 for (i = 0; i < nelts; i++)
390 t = (*saved_args)[i];
391 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE, t);
394 TREE_CONSTANT (ctor) = 1;
395 TREE_STATIC (ctor) = 1;
396 DECL_INITIAL (var) = ctor;
397 rest_of_decl_compilation (var, 1, 0);
399 return var;
402 /* Instrument the __builtin_unreachable call. We just call the libubsan
403 routine instead. */
405 tree
406 ubsan_instrument_unreachable (location_t loc)
408 tree data = ubsan_create_data ("__ubsan_unreachable_data", loc, NULL_TREE);
409 tree t = builtin_decl_explicit (BUILT_IN_UBSAN_HANDLE_BUILTIN_UNREACHABLE);
410 return build_call_expr_loc (loc, t, 1, build_fold_addr_expr_loc (loc, data));
413 /* Return true if T is a call to a libubsan routine. */
415 bool
416 is_ubsan_builtin_p (tree t)
418 gcc_checking_assert (TREE_CODE (t) == FUNCTION_DECL);
419 return strncmp (IDENTIFIER_POINTER (DECL_NAME (t)),
420 "__builtin___ubsan_", 18) == 0;
423 #include "gt-ubsan.h"