* sv.po: Update.
[official-gcc.git] / gcc / cp / cp-ubsan.c
blob7454c0af6445ba7a6b6da3b557a306c419e856a0
1 /* UndefinedBehaviorSanitizer, undefined behavior detector.
2 Copyright (C) 2014-2016 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
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 "cp-tree.h"
25 #include "ubsan.h"
27 /* Test if we should instrument vptr access. */
29 static bool
30 cp_ubsan_instrument_vptr_p (tree type)
32 if (!flag_rtti || flag_sanitize_undefined_trap_on_error)
33 return false;
35 if (!do_ubsan_in_current_function ())
36 return false;
38 if (type)
40 type = TYPE_MAIN_VARIANT (type);
41 if (!CLASS_TYPE_P (type) || !CLASSTYPE_VTABLES (type))
42 return false;
45 return true;
48 /* Helper function for
49 cp_ubsan_maybe_instrument_{member_{call,access},downcast}.
50 Instrument vptr access. */
52 static tree
53 cp_ubsan_instrument_vptr (location_t loc, tree op, tree type, bool is_addr,
54 enum ubsan_null_ckind ckind)
56 type = TYPE_MAIN_VARIANT (type);
57 const char *mangled = mangle_type_string (type);
58 hashval_t str_hash1 = htab_hash_string (mangled);
59 hashval_t str_hash2 = iterative_hash (mangled, strlen (mangled), 0);
60 tree str_hash = wide_int_to_tree (uint64_type_node,
61 wi::uhwi (((uint64_t) str_hash1 << 32)
62 | str_hash2, 64));
63 if (!is_addr)
64 op = build_fold_addr_expr_loc (loc, op);
65 op = save_expr (op);
66 tree vptr = fold_build3_loc (loc, COMPONENT_REF,
67 TREE_TYPE (TYPE_VFIELD (type)),
68 build_fold_indirect_ref_loc (loc, op),
69 TYPE_VFIELD (type), NULL_TREE);
70 vptr = fold_convert_loc (loc, pointer_sized_int_node, vptr);
71 vptr = fold_convert_loc (loc, uint64_type_node, vptr);
72 if (ckind == UBSAN_DOWNCAST_POINTER)
73 vptr = fold_build3 (COND_EXPR, uint64_type_node,
74 fold_build2 (NE_EXPR, boolean_type_node, op,
75 build_zero_cst (TREE_TYPE (op))),
76 vptr, build_int_cst (uint64_type_node, 0));
77 tree ti_decl = get_tinfo_decl (type);
78 mark_used (ti_decl);
79 tree ptype = build_pointer_type (type);
80 tree call
81 = build_call_expr_internal_loc (loc, IFN_UBSAN_VPTR,
82 void_type_node, 5, op, vptr, str_hash,
83 build_address (ti_decl),
84 build_int_cst (ptype, ckind));
85 TREE_SIDE_EFFECTS (call) = 1;
86 return fold_build2 (COMPOUND_EXPR, TREE_TYPE (op), call, op);
89 /* Helper function for
90 cp_ubsan_maybe_instrument_{member_{call,access},downcast}.
91 Instrument vptr access if it should be instrumented, otherwise return
92 NULL_TREE. */
94 static tree
95 cp_ubsan_maybe_instrument_vptr (location_t loc, tree op, tree type,
96 bool is_addr, enum ubsan_null_ckind ckind)
98 if (!cp_ubsan_instrument_vptr_p (type))
99 return NULL_TREE;
100 return cp_ubsan_instrument_vptr (loc, op, type, is_addr, ckind);
103 /* Instrument a member call (but not constructor call) if needed. */
105 void
106 cp_ubsan_maybe_instrument_member_call (tree stmt)
108 if (call_expr_nargs (stmt) == 0)
109 return;
110 tree *opp = &CALL_EXPR_ARG (stmt, 0);
111 tree op = *opp;
112 if (op == error_mark_node
113 || !POINTER_TYPE_P (TREE_TYPE (op)))
114 return;
115 while (TREE_CODE (op) == COMPOUND_EXPR)
117 opp = &TREE_OPERAND (op, 1);
118 op = *opp;
120 op = cp_ubsan_maybe_instrument_vptr (EXPR_LOCATION (stmt), op,
121 TREE_TYPE (TREE_TYPE (op)),
122 true, UBSAN_MEMBER_CALL);
123 if (op)
124 *opp = op;
127 /* Data passed to cp_ubsan_check_member_access_r. */
129 struct cp_ubsan_check_member_access_data
131 hash_set<tree> *pset;
132 bool is_addr;
135 static tree cp_ubsan_check_member_access_r (tree *, int *, void *);
137 /* Instrument a member access. */
139 static bool
140 cp_ubsan_maybe_instrument_member_access
141 (tree stmt, cp_ubsan_check_member_access_data *ucmd)
143 if (DECL_ARTIFICIAL (TREE_OPERAND (stmt, 1)))
144 return false;
146 tree base = TREE_OPERAND (stmt, 0);
147 if (!cp_ubsan_instrument_vptr_p (TREE_TYPE (base)))
148 return false;
150 cp_walk_tree (&base, cp_ubsan_check_member_access_r, ucmd, ucmd->pset);
152 base = cp_ubsan_instrument_vptr (EXPR_LOCATION (stmt), base,
153 TREE_TYPE (base), false,
154 UBSAN_MEMBER_ACCESS);
155 TREE_OPERAND (stmt, 0)
156 = build_fold_indirect_ref_loc (EXPR_LOCATION (stmt), base);
157 return true;
160 /* Attempt to instrument member accesses inside of the function.
161 cp_ubsan_maybe_instrument_member_access should be called on COMPONENT_REFs
162 in the GENERIC IL, but only when the field is actually accessed, not
163 merely when it's address is taken. Therefore we track in is_addr field
164 whether in the current context we are processing address taken
165 handled components or not. E.g. for &x->y[w->z] we want to call
166 cp_ubsan_maybe_instrument_member_access on *w.z COMPONENT_REF, but
167 not on *x.y. */
169 static tree
170 cp_ubsan_check_member_access_r (tree *stmt_p, int *walk_subtrees, void *data)
172 tree stmt = *stmt_p, t;
173 cp_ubsan_check_member_access_data *ucmd
174 = (cp_ubsan_check_member_access_data *) data;
175 switch (TREE_CODE (stmt))
177 case ADDR_EXPR:
178 t = TREE_OPERAND (stmt, 0);
179 while ((TREE_CODE (t) == MEM_REF || INDIRECT_REF_P (t))
180 && TREE_CODE (TREE_OPERAND (t, 0)) == ADDR_EXPR)
181 t = TREE_OPERAND (TREE_OPERAND (t, 0), 0);
182 if (handled_component_p (t))
184 *walk_subtrees = 0;
185 ucmd->is_addr = true;
186 cp_walk_tree (&t, cp_ubsan_check_member_access_r,
187 data, ucmd->pset);
188 ucmd->is_addr = false;
190 break;
191 case MEM_REF:
192 case INDIRECT_REF:
193 t = TREE_OPERAND (stmt, 0);
194 if (TREE_CODE (t) == ADDR_EXPR)
196 *walk_subtrees = 0;
197 t = TREE_OPERAND (stmt, 0);
198 cp_walk_tree (&t, cp_ubsan_check_member_access_r, data, ucmd->pset);
200 break;
201 case COMPONENT_REF:
202 if (!ucmd->is_addr && cp_ubsan_maybe_instrument_member_access (stmt, ucmd))
204 *walk_subtrees = 0;
205 break;
207 /* FALLTHRU */
208 default:
209 if (ucmd->is_addr && handled_component_p (stmt))
211 int i, len = TREE_OPERAND_LENGTH (stmt);
212 *walk_subtrees = 0;
213 if (!handled_component_p (TREE_OPERAND (stmt, 0)))
214 ucmd->is_addr = false;
215 for (i = 0; i < len; i++)
217 cp_walk_tree (&TREE_OPERAND (stmt, i),
218 cp_ubsan_check_member_access_r, data, ucmd->pset);
219 ucmd->is_addr = false;
221 ucmd->is_addr = true;
223 break;
225 return NULL_TREE;
228 /* Instrument all member accesses inside GENERIC *T_P. */
230 void
231 cp_ubsan_instrument_member_accesses (tree *t_p)
233 if (cp_ubsan_instrument_vptr_p (NULL_TREE))
235 hash_set<tree> pset;
236 cp_ubsan_check_member_access_data ucmd;
237 ucmd.pset = &pset;
238 ucmd.is_addr = false;
239 cp_walk_tree (t_p, cp_ubsan_check_member_access_r, &ucmd, &pset);
243 /* Instrument downcast. */
245 tree
246 cp_ubsan_maybe_instrument_downcast (location_t loc, tree type,
247 tree intype, tree op)
249 if (!POINTER_TYPE_P (type)
250 || !POINTER_TYPE_P (intype)
251 || !POINTER_TYPE_P (TREE_TYPE (op))
252 || !CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (op)))
253 || !is_properly_derived_from (TREE_TYPE (type), TREE_TYPE (intype)))
254 return NULL_TREE;
256 return cp_ubsan_maybe_instrument_vptr (loc, op, TREE_TYPE (type), true,
257 TREE_CODE (type) == POINTER_TYPE
258 ? UBSAN_DOWNCAST_POINTER
259 : UBSAN_DOWNCAST_REFERENCE);
262 /* Instrument cast to virtual base. */
264 tree
265 cp_ubsan_maybe_instrument_cast_to_vbase (location_t loc, tree type, tree op)
267 return cp_ubsan_maybe_instrument_vptr (loc, op, type, true,
268 UBSAN_CAST_TO_VBASE);