1 /* UndefinedBehaviorSanitizer, undefined behavior detector.
2 Copyright (C) 2014 Free Software Foundation, Inc.
3 Contributed by Jakub Jelinek <jakub@redhat.com>
5 This file is part of GCC.
7 GCC is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 3, or (at your option) any later
12 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License
18 along with GCC; see the file COPYING3. If not see
19 <http://www.gnu.org/licenses/>. */
23 #include "coretypes.h"
27 #include "double-int.h"
35 #include "alloc-pool.h"
40 #include "c-family/c-common.h"
41 #include "c-family/c-ubsan.h"
43 #include "internal-fn.h"
44 #include "stor-layout.h"
46 #include "fold-const.h"
47 #include "stringpool.h"
50 #include "tree-ssa-alias.h"
51 #include "basic-block.h"
52 #include "gimple-expr.h"
55 #include "lto-streamer.h"
58 /* Test if we should instrument vptr access. */
61 cp_ubsan_instrument_vptr_p (tree type
)
63 if (!flag_rtti
|| flag_sanitize_undefined_trap_on_error
)
66 if (current_function_decl
67 && lookup_attribute ("no_sanitize_undefined",
68 DECL_ATTRIBUTES (current_function_decl
)))
73 type
= TYPE_MAIN_VARIANT (type
);
74 if (!CLASS_TYPE_P (type
) || !CLASSTYPE_VTABLES (type
))
81 /* Helper function for
82 cp_ubsan_maybe_instrument_{member_{call,access},downcast}.
83 Instrument vptr access. */
86 cp_ubsan_instrument_vptr (location_t loc
, tree op
, tree type
, bool is_addr
,
87 enum ubsan_null_ckind ckind
)
89 type
= TYPE_MAIN_VARIANT (type
);
90 const char *mangled
= mangle_type_string (type
);
91 hashval_t str_hash1
= htab_hash_string (mangled
);
92 hashval_t str_hash2
= iterative_hash (mangled
, strlen (mangled
), 0);
93 tree str_hash
= wide_int_to_tree (uint64_type_node
,
94 wi::uhwi (((uint64_t) str_hash1
<< 32)
97 op
= build_fold_addr_expr_loc (loc
, op
);
99 tree vptr
= fold_build3_loc (loc
, COMPONENT_REF
,
100 TREE_TYPE (TYPE_VFIELD (type
)),
101 build_fold_indirect_ref_loc (loc
, op
),
102 TYPE_VFIELD (type
), NULL_TREE
);
103 vptr
= fold_convert_loc (loc
, pointer_sized_int_node
, vptr
);
104 vptr
= fold_convert_loc (loc
, uint64_type_node
, vptr
);
105 if (ckind
== UBSAN_DOWNCAST_POINTER
)
106 vptr
= fold_build3 (COND_EXPR
, uint64_type_node
,
107 fold_build2 (NE_EXPR
, boolean_type_node
, op
,
108 build_zero_cst (TREE_TYPE (op
))),
109 vptr
, build_int_cst (uint64_type_node
, 0));
110 tree ti_decl
= get_tinfo_decl (type
);
112 tree ptype
= build_pointer_type (type
);
114 = build_call_expr_internal_loc (loc
, IFN_UBSAN_VPTR
,
115 void_type_node
, 5, op
, vptr
, str_hash
,
116 build_address (ti_decl
),
117 build_int_cst (ptype
, ckind
));
118 TREE_SIDE_EFFECTS (call
) = 1;
119 return fold_build2 (COMPOUND_EXPR
, TREE_TYPE (op
), call
, op
);
122 /* Helper function for
123 cp_ubsan_maybe_instrument_{member_{call,access},downcast}.
124 Instrument vptr access if it should be instrumented, otherwise return
128 cp_ubsan_maybe_instrument_vptr (location_t loc
, tree op
, tree type
,
129 bool is_addr
, enum ubsan_null_ckind ckind
)
131 if (!cp_ubsan_instrument_vptr_p (type
))
133 return cp_ubsan_instrument_vptr (loc
, op
, type
, is_addr
, ckind
);
136 /* Instrument a member call (but not constructor call) if needed. */
139 cp_ubsan_maybe_instrument_member_call (tree stmt
)
141 if (call_expr_nargs (stmt
) == 0)
143 tree
*opp
= &CALL_EXPR_ARG (stmt
, 0);
145 if (op
== error_mark_node
146 || !POINTER_TYPE_P (TREE_TYPE (op
)))
148 while (TREE_CODE (op
) == COMPOUND_EXPR
)
150 opp
= &TREE_OPERAND (op
, 1);
153 op
= cp_ubsan_maybe_instrument_vptr (EXPR_LOCATION (stmt
), op
,
154 TREE_TYPE (TREE_TYPE (op
)),
155 true, UBSAN_MEMBER_CALL
);
160 /* Data passed to cp_ubsan_check_member_access_r. */
162 struct cp_ubsan_check_member_access_data
164 hash_set
<tree
> *pset
;
168 static tree
cp_ubsan_check_member_access_r (tree
*, int *, void *);
170 /* Instrument a member access. */
173 cp_ubsan_maybe_instrument_member_access
174 (tree stmt
, cp_ubsan_check_member_access_data
*ucmd
)
176 if (DECL_ARTIFICIAL (TREE_OPERAND (stmt
, 1)))
179 tree base
= TREE_OPERAND (stmt
, 0);
180 if (!cp_ubsan_instrument_vptr_p (TREE_TYPE (base
)))
183 cp_walk_tree (&base
, cp_ubsan_check_member_access_r
, ucmd
, ucmd
->pset
);
185 base
= cp_ubsan_instrument_vptr (EXPR_LOCATION (stmt
), base
,
186 TREE_TYPE (base
), false,
187 UBSAN_MEMBER_ACCESS
);
188 TREE_OPERAND (stmt
, 0)
189 = build_fold_indirect_ref_loc (EXPR_LOCATION (stmt
), base
);
193 /* Attempt to instrument member accesses inside of the function.
194 cp_ubsan_maybe_instrument_member_access should be called on COMPONENT_REFs
195 in the GENERIC IL, but only when the field is actually accessed, not
196 merely when it's address is taken. Therefore we track in is_addr field
197 whether in the current context we are processing address taken
198 handled components or not. E.g. for &x->y[w->z] we want to call
199 cp_ubsan_maybe_instrument_member_access on *w.z COMPONENT_REF, but
203 cp_ubsan_check_member_access_r (tree
*stmt_p
, int *walk_subtrees
, void *data
)
205 tree stmt
= *stmt_p
, t
;
206 cp_ubsan_check_member_access_data
*ucmd
207 = (cp_ubsan_check_member_access_data
*) data
;
208 switch (TREE_CODE (stmt
))
211 t
= TREE_OPERAND (stmt
, 0);
212 while ((TREE_CODE (t
) == MEM_REF
|| TREE_CODE (t
) == INDIRECT_REF
)
213 && TREE_CODE (TREE_OPERAND (t
, 0)) == ADDR_EXPR
)
214 t
= TREE_OPERAND (TREE_OPERAND (t
, 0), 0);
215 if (handled_component_p (t
))
218 ucmd
->is_addr
= true;
219 cp_walk_tree (&t
, cp_ubsan_check_member_access_r
,
221 ucmd
->is_addr
= false;
226 t
= TREE_OPERAND (stmt
, 0);
227 if (TREE_CODE (t
) == ADDR_EXPR
)
230 t
= TREE_OPERAND (stmt
, 0);
231 cp_walk_tree (&t
, cp_ubsan_check_member_access_r
, data
, ucmd
->pset
);
235 if (!ucmd
->is_addr
&& cp_ubsan_maybe_instrument_member_access (stmt
, ucmd
))
242 if (ucmd
->is_addr
&& handled_component_p (stmt
))
244 int i
, len
= TREE_OPERAND_LENGTH (stmt
);
246 if (!handled_component_p (TREE_OPERAND (stmt
, 0)))
247 ucmd
->is_addr
= false;
248 for (i
= 0; i
< len
; i
++)
250 cp_walk_tree (&TREE_OPERAND (stmt
, i
),
251 cp_ubsan_check_member_access_r
, data
, ucmd
->pset
);
252 ucmd
->is_addr
= false;
254 ucmd
->is_addr
= true;
261 /* Instrument all member accesses inside GENERIC *T_P. */
264 cp_ubsan_instrument_member_accesses (tree
*t_p
)
266 if (cp_ubsan_instrument_vptr_p (NULL_TREE
))
269 cp_ubsan_check_member_access_data ucmd
;
271 ucmd
.is_addr
= false;
272 cp_walk_tree (t_p
, cp_ubsan_check_member_access_r
, &ucmd
, &pset
);
276 /* Instrument downcast. */
279 cp_ubsan_maybe_instrument_downcast (location_t loc
, tree type
,
280 tree intype
, tree op
)
282 if (!POINTER_TYPE_P (type
)
283 || !POINTER_TYPE_P (intype
)
284 || !POINTER_TYPE_P (TREE_TYPE (op
))
285 || !CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (op
)))
286 || !is_properly_derived_from (TREE_TYPE (type
), TREE_TYPE (intype
)))
289 return cp_ubsan_maybe_instrument_vptr (loc
, op
, TREE_TYPE (type
), true,
290 TREE_CODE (type
) == POINTER_TYPE
291 ? UBSAN_DOWNCAST_POINTER
292 : UBSAN_DOWNCAST_REFERENCE
);
295 /* Instrument cast to virtual base. */
298 cp_ubsan_maybe_instrument_cast_to_vbase (location_t loc
, tree type
, tree op
)
300 return cp_ubsan_maybe_instrument_vptr (loc
, op
, type
, true,
301 UBSAN_CAST_TO_VBASE
);