]> git.ipfire.org Git - thirdparty/gcc.git/blob - gcc/cp/cp-ubsan.c
re PR sanitizer/64717 (-fsanitize=vptr leads to warning: ‘<anonymous>’ may be used...
[thirdparty/gcc.git] / gcc / cp / cp-ubsan.c
1 /* UndefinedBehaviorSanitizer, undefined behavior detector.
2 Copyright (C) 2014 Free Software Foundation, Inc.
3 Contributed by Jakub Jelinek <jakub@redhat.com>
4
5 This file is part of GCC.
6
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.
11
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.
16
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/>. */
20
21 #include "config.h"
22 #include "system.h"
23 #include "coretypes.h"
24 #include "hash-set.h"
25 #include "machmode.h"
26 #include "vec.h"
27 #include "double-int.h"
28 #include "input.h"
29 #include "alias.h"
30 #include "symtab.h"
31 #include "options.h"
32 #include "wide-int.h"
33 #include "inchash.h"
34 #include "tree.h"
35 #include "alloc-pool.h"
36 #include "output.h"
37 #include "toplev.h"
38 #include "ubsan.h"
39 #include "cp-tree.h"
40 #include "c-family/c-common.h"
41 #include "c-family/c-ubsan.h"
42 #include "asan.h"
43 #include "internal-fn.h"
44 #include "stor-layout.h"
45 #include "builtins.h"
46 #include "fold-const.h"
47 #include "stringpool.h"
48 #include "is-a.h"
49 #include "predict.h"
50 #include "tree-ssa-alias.h"
51 #include "basic-block.h"
52 #include "gimple-expr.h"
53 #include "gimple.h"
54 #include "ipa-ref.h"
55 #include "lto-streamer.h"
56 #include "cgraph.h"
57
58 /* Test if we should instrument vptr access. */
59
60 static bool
61 cp_ubsan_instrument_vptr_p (tree type)
62 {
63 if (!flag_rtti || flag_sanitize_undefined_trap_on_error)
64 return false;
65
66 if (current_function_decl
67 && lookup_attribute ("no_sanitize_undefined",
68 DECL_ATTRIBUTES (current_function_decl)))
69 return false;
70
71 if (type)
72 {
73 type = TYPE_MAIN_VARIANT (type);
74 if (!CLASS_TYPE_P (type) || !CLASSTYPE_VTABLES (type))
75 return false;
76 }
77
78 return true;
79 }
80
81 /* Helper function for
82 cp_ubsan_maybe_instrument_{member_{call,access},downcast}.
83 Instrument vptr access. */
84
85 static tree
86 cp_ubsan_instrument_vptr (location_t loc, tree op, tree type, bool is_addr,
87 enum ubsan_null_ckind ckind)
88 {
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)
95 | str_hash2, 64));
96 if (!is_addr)
97 op = build_fold_addr_expr_loc (loc, op);
98 op = save_expr (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);
111 mark_used (ti_decl);
112 tree ptype = build_pointer_type (type);
113 tree call
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);
120 }
121
122 /* Helper function for
123 cp_ubsan_maybe_instrument_{member_{call,access},downcast}.
124 Instrument vptr access if it should be instrumented, otherwise return
125 NULL_TREE. */
126
127 static tree
128 cp_ubsan_maybe_instrument_vptr (location_t loc, tree op, tree type,
129 bool is_addr, enum ubsan_null_ckind ckind)
130 {
131 if (!cp_ubsan_instrument_vptr_p (type))
132 return NULL_TREE;
133 return cp_ubsan_instrument_vptr (loc, op, type, is_addr, ckind);
134 }
135
136 /* Instrument a member call (but not constructor call) if needed. */
137
138 void
139 cp_ubsan_maybe_instrument_member_call (tree stmt)
140 {
141 if (call_expr_nargs (stmt) == 0)
142 return;
143 tree *opp = &CALL_EXPR_ARG (stmt, 0);
144 tree op = *opp;
145 if (op == error_mark_node
146 || !POINTER_TYPE_P (TREE_TYPE (op)))
147 return;
148 while (TREE_CODE (op) == COMPOUND_EXPR)
149 {
150 opp = &TREE_OPERAND (op, 1);
151 op = *opp;
152 }
153 op = cp_ubsan_maybe_instrument_vptr (EXPR_LOCATION (stmt), op,
154 TREE_TYPE (TREE_TYPE (op)),
155 true, UBSAN_MEMBER_CALL);
156 if (op)
157 *opp = op;
158 }
159
160 /* Data passed to cp_ubsan_check_member_access_r. */
161
162 struct cp_ubsan_check_member_access_data
163 {
164 hash_set<tree> *pset;
165 bool is_addr;
166 };
167
168 static tree cp_ubsan_check_member_access_r (tree *, int *, void *);
169
170 /* Instrument a member access. */
171
172 static bool
173 cp_ubsan_maybe_instrument_member_access
174 (tree stmt, cp_ubsan_check_member_access_data *ucmd)
175 {
176 if (DECL_ARTIFICIAL (TREE_OPERAND (stmt, 1)))
177 return false;
178
179 tree base = TREE_OPERAND (stmt, 0);
180 if (!cp_ubsan_instrument_vptr_p (TREE_TYPE (base)))
181 return false;
182
183 cp_walk_tree (&base, cp_ubsan_check_member_access_r, ucmd, ucmd->pset);
184
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);
190 return true;
191 }
192
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
200 not on *x.y. */
201
202 static tree
203 cp_ubsan_check_member_access_r (tree *stmt_p, int *walk_subtrees, void *data)
204 {
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))
209 {
210 case ADDR_EXPR:
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))
216 {
217 *walk_subtrees = 0;
218 ucmd->is_addr = true;
219 cp_walk_tree (&t, cp_ubsan_check_member_access_r,
220 data, ucmd->pset);
221 ucmd->is_addr = false;
222 }
223 break;
224 case MEM_REF:
225 case INDIRECT_REF:
226 t = TREE_OPERAND (stmt, 0);
227 if (TREE_CODE (t) == ADDR_EXPR)
228 {
229 *walk_subtrees = 0;
230 t = TREE_OPERAND (stmt, 0);
231 cp_walk_tree (&t, cp_ubsan_check_member_access_r, data, ucmd->pset);
232 }
233 break;
234 case COMPONENT_REF:
235 if (!ucmd->is_addr && cp_ubsan_maybe_instrument_member_access (stmt, ucmd))
236 {
237 *walk_subtrees = 0;
238 break;
239 }
240 /* FALLTHRU */
241 default:
242 if (ucmd->is_addr && handled_component_p (stmt))
243 {
244 int i, len = TREE_OPERAND_LENGTH (stmt);
245 *walk_subtrees = 0;
246 if (!handled_component_p (TREE_OPERAND (stmt, 0)))
247 ucmd->is_addr = false;
248 for (i = 0; i < len; i++)
249 {
250 cp_walk_tree (&TREE_OPERAND (stmt, i),
251 cp_ubsan_check_member_access_r, data, ucmd->pset);
252 ucmd->is_addr = false;
253 }
254 ucmd->is_addr = true;
255 }
256 break;
257 }
258 return NULL_TREE;
259 }
260
261 /* Instrument all member accesses inside GENERIC *T_P. */
262
263 void
264 cp_ubsan_instrument_member_accesses (tree *t_p)
265 {
266 if (cp_ubsan_instrument_vptr_p (NULL_TREE))
267 {
268 hash_set<tree> pset;
269 cp_ubsan_check_member_access_data ucmd;
270 ucmd.pset = &pset;
271 ucmd.is_addr = false;
272 cp_walk_tree (t_p, cp_ubsan_check_member_access_r, &ucmd, &pset);
273 }
274 }
275
276 /* Instrument downcast. */
277
278 tree
279 cp_ubsan_maybe_instrument_downcast (location_t loc, tree type, tree op)
280 {
281 if (!POINTER_TYPE_P (type)
282 || !POINTER_TYPE_P (TREE_TYPE (op))
283 || !CLASS_TYPE_P (TREE_TYPE (type))
284 || !CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (op)))
285 || !DERIVED_FROM_P (TREE_TYPE (TREE_TYPE (op)), TREE_TYPE (type)))
286 return NULL_TREE;
287
288 return cp_ubsan_maybe_instrument_vptr (loc, op, TREE_TYPE (type), true,
289 TREE_CODE (type) == POINTER_TYPE
290 ? UBSAN_DOWNCAST_POINTER
291 : UBSAN_DOWNCAST_REFERENCE);
292 }
293
294 /* Instrument cast to virtual base. */
295
296 tree
297 cp_ubsan_maybe_instrument_cast_to_vbase (location_t loc, tree type, tree op)
298 {
299 return cp_ubsan_maybe_instrument_vptr (loc, op, type, true,
300 UBSAN_CAST_TO_VBASE);
301 }