c++: retval dtor on rethrow [PR112301]
[official-gcc.git] / gcc / sancov.cc
blob0ff346bd76fd671fca4b3fa980c5baa334f23f07
1 /* Code coverage instrumentation for fuzzing.
2 Copyright (C) 2015-2023 Free Software Foundation, Inc.
3 Contributed by Dmitry Vyukov <dvyukov@google.com> and
4 Wish Wu <wishwu007@gmail.com>
6 This file is part of GCC.
8 GCC is free software; you can redistribute it and/or modify it under
9 the terms of the GNU General Public License as published by the Free
10 Software Foundation; either version 3, or (at your option) any later
11 version.
13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY
14 WARRANTY; without even the implied warranty of MERCHANTABILITY or
15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
16 for more details.
18 You should have received a copy of the GNU General Public License
19 along with GCC; see the file COPYING3. If not see
20 <http://www.gnu.org/licenses/>. */
22 #include "config.h"
23 #include "system.h"
24 #include "coretypes.h"
25 #include "backend.h"
26 #include "tree.h"
27 #include "gimple.h"
28 #include "basic-block.h"
29 #include "options.h"
30 #include "flags.h"
31 #include "memmodel.h"
32 #include "tm_p.h"
33 #include "stmt.h"
34 #include "gimple-iterator.h"
35 #include "gimple-builder.h"
36 #include "tree-cfg.h"
37 #include "tree-pass.h"
38 #include "tree-iterator.h"
39 #include "fold-const.h"
40 #include "stringpool.h"
41 #include "attribs.h"
42 #include "output.h"
43 #include "cgraph.h"
44 #include "asan.h"
46 namespace {
48 /* Instrument one comparison operation, which compares lhs and rhs.
49 Call the instrumentation function with the comparison operand.
50 For integral comparisons if exactly one of the comparison operands is
51 constant, call __sanitizer_cov_trace_const_cmp* instead of
52 __sanitizer_cov_trace_cmp*. */
54 static void
55 instrument_comparison (gimple_stmt_iterator *gsi, tree lhs, tree rhs)
57 tree type = TREE_TYPE (lhs);
58 enum built_in_function fncode = END_BUILTINS;
59 tree to_type = NULL_TREE;
60 bool c = false;
62 if (INTEGRAL_TYPE_P (type))
64 c = (is_gimple_min_invariant (lhs)
65 ^ is_gimple_min_invariant (rhs));
66 switch (int_size_in_bytes (type))
68 case 1:
69 fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP1
70 : BUILT_IN_SANITIZER_COV_TRACE_CMP1;
71 to_type = unsigned_char_type_node;
72 break;
73 case 2:
74 fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP2
75 : BUILT_IN_SANITIZER_COV_TRACE_CMP2;
76 to_type = uint16_type_node;
77 break;
78 case 4:
79 fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP4
80 : BUILT_IN_SANITIZER_COV_TRACE_CMP4;
81 to_type = uint32_type_node;
82 break;
83 default:
84 fncode = c ? BUILT_IN_SANITIZER_COV_TRACE_CONST_CMP8
85 : BUILT_IN_SANITIZER_COV_TRACE_CMP8;
86 to_type = uint64_type_node;
87 break;
90 else if (SCALAR_FLOAT_TYPE_P (type))
92 if (TYPE_MODE (type) == TYPE_MODE (float_type_node))
94 fncode = BUILT_IN_SANITIZER_COV_TRACE_CMPF;
95 to_type = float_type_node;
97 else if (TYPE_MODE (type) == TYPE_MODE (double_type_node))
99 fncode = BUILT_IN_SANITIZER_COV_TRACE_CMPD;
100 to_type = double_type_node;
104 if (to_type != NULL_TREE)
106 gimple_seq seq = NULL;
108 if (!useless_type_conversion_p (to_type, type))
110 if (TREE_CODE (lhs) == INTEGER_CST)
111 lhs = fold_convert (to_type, lhs);
112 else
114 gimple_seq_add_stmt (&seq, build_type_cast (to_type, lhs));
115 lhs = gimple_assign_lhs (gimple_seq_last_stmt (seq));
118 if (TREE_CODE (rhs) == INTEGER_CST)
119 rhs = fold_convert (to_type, rhs);
120 else
122 gimple_seq_add_stmt (&seq, build_type_cast (to_type, rhs));
123 rhs = gimple_assign_lhs (gimple_seq_last_stmt (seq));
127 if (c && !is_gimple_min_invariant (lhs))
128 std::swap (lhs, rhs);
130 tree fndecl = builtin_decl_implicit (fncode);
131 gimple *gcall = gimple_build_call (fndecl, 2, lhs, rhs);
132 gimple_seq_add_stmt (&seq, gcall);
134 gimple_seq_set_location (seq, gimple_location (gsi_stmt (*gsi)));
135 gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT);
139 /* Instrument switch statement. Call __sanitizer_cov_trace_switch with
140 the value of the index and array that contains number of case values,
141 the bitsize of the index and the case values converted to uint64_t. */
143 static void
144 instrument_switch (gimple_stmt_iterator *gsi, gimple *stmt, function *fun)
146 gswitch *switch_stmt = as_a<gswitch *> (stmt);
147 tree index = gimple_switch_index (switch_stmt);
148 HOST_WIDE_INT size_in_bytes = int_size_in_bytes (TREE_TYPE (index));
149 if (size_in_bytes == -1 || size_in_bytes > 8)
150 return;
152 location_t loc = gimple_location (stmt);
153 unsigned i, n = gimple_switch_num_labels (switch_stmt), num = 0;
154 for (i = 1; i < n; ++i)
156 tree label = gimple_switch_label (switch_stmt, i);
158 tree low_case = CASE_LOW (label);
159 if (low_case != NULL_TREE)
160 num++;
162 tree high_case = CASE_HIGH (label);
163 if (high_case != NULL_TREE)
164 num++;
167 tree case_array_type
168 = build_array_type (build_type_variant (uint64_type_node, 1, 0),
169 build_index_type (size_int (num + 2 - 1)));
171 char name[64];
172 static size_t case_array_count = 0;
173 ASM_GENERATE_INTERNAL_LABEL (name, "LCASEARRAY", case_array_count++);
174 tree case_array_var = build_decl (loc, VAR_DECL, get_identifier (name),
175 case_array_type);
176 TREE_STATIC (case_array_var) = 1;
177 TREE_PUBLIC (case_array_var) = 0;
178 TREE_CONSTANT (case_array_var) = 1;
179 TREE_READONLY (case_array_var) = 1;
180 DECL_EXTERNAL (case_array_var) = 0;
181 DECL_ARTIFICIAL (case_array_var) = 1;
182 DECL_IGNORED_P (case_array_var) = 1;
184 vec <constructor_elt, va_gc> *v = NULL;
185 vec_alloc (v, num + 2);
186 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
187 build_int_cst (uint64_type_node, num));
188 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
189 build_int_cst (uint64_type_node,
190 size_in_bytes * BITS_PER_UNIT));
191 for (i = 1; i < n; ++i)
193 tree label = gimple_switch_label (switch_stmt, i);
195 tree low_case = CASE_LOW (label);
196 if (low_case != NULL_TREE)
197 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
198 fold_convert (uint64_type_node, low_case));
200 tree high_case = CASE_HIGH (label);
201 if (high_case != NULL_TREE)
202 CONSTRUCTOR_APPEND_ELT (v, NULL_TREE,
203 fold_convert (uint64_type_node, high_case));
205 tree ctor = build_constructor (case_array_type, v);
206 TREE_STATIC (ctor) = 1;
207 TREE_PUBLIC (ctor) = 0;
208 TREE_CONSTANT (ctor) = 1;
209 TREE_READONLY (ctor) = 1;
210 DECL_INITIAL (case_array_var) = ctor;
211 varpool_node::finalize_decl (case_array_var);
212 add_local_decl (fun, case_array_var);
214 gimple_seq seq = NULL;
216 if (!useless_type_conversion_p (uint64_type_node, TREE_TYPE (index)))
218 if (TREE_CODE (index) == INTEGER_CST)
219 index = fold_convert (uint64_type_node, index);
220 else
222 gimple_seq_add_stmt (&seq, build_type_cast (uint64_type_node, index));
223 index = gimple_assign_lhs (gimple_seq_last_stmt (seq));
227 tree fndecl = builtin_decl_implicit (BUILT_IN_SANITIZER_COV_TRACE_SWITCH);
228 gimple *gcall = gimple_build_call (fndecl, 2, index,
229 build_fold_addr_expr (case_array_var));
230 gimple_seq_add_stmt (&seq, gcall);
232 gimple_seq_set_location (seq, loc);
233 gsi_insert_seq_before (gsi, seq, GSI_SAME_STMT);
236 unsigned
237 sancov_pass (function *fun)
239 initialize_sanitizer_builtins ();
241 /* Insert callback into beginning of every BB. */
242 if (flag_sanitize_coverage & SANITIZE_COV_TRACE_PC)
244 basic_block bb;
245 tree fndecl = builtin_decl_implicit (BUILT_IN_SANITIZER_COV_TRACE_PC);
246 FOR_EACH_BB_FN (bb, fun)
248 gimple_stmt_iterator gsi = gsi_start_nondebug_after_labels_bb (bb);
249 if (gsi_end_p (gsi))
250 continue;
251 gimple *stmt = gsi_stmt (gsi);
252 gimple *gcall = gimple_build_call (fndecl, 0);
253 gimple_set_location (gcall, gimple_location (stmt));
254 gsi_insert_before (&gsi, gcall, GSI_SAME_STMT);
258 /* Insert callback into every comparison related operation. */
259 if (flag_sanitize_coverage & SANITIZE_COV_TRACE_CMP)
261 basic_block bb;
262 FOR_EACH_BB_FN (bb, fun)
264 gimple_stmt_iterator gsi;
265 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
267 gimple *stmt = gsi_stmt (gsi);
268 enum tree_code rhs_code;
269 switch (gimple_code (stmt))
271 case GIMPLE_ASSIGN:
272 rhs_code = gimple_assign_rhs_code (stmt);
273 if (TREE_CODE_CLASS (rhs_code) == tcc_comparison)
274 instrument_comparison (&gsi,
275 gimple_assign_rhs1 (stmt),
276 gimple_assign_rhs2 (stmt));
277 else if (rhs_code == COND_EXPR
278 && COMPARISON_CLASS_P (gimple_assign_rhs1 (stmt)))
280 tree cond = gimple_assign_rhs1 (stmt);
281 instrument_comparison (&gsi, TREE_OPERAND (cond, 0),
282 TREE_OPERAND (cond, 1));
284 break;
285 case GIMPLE_COND:
286 instrument_comparison (&gsi,
287 gimple_cond_lhs (stmt),
288 gimple_cond_rhs (stmt));
289 break;
291 case GIMPLE_SWITCH:
292 instrument_switch (&gsi, stmt, fun);
293 break;
295 default:
296 break;
301 return 0;
304 template <bool O0> class pass_sancov : public gimple_opt_pass
306 public:
307 pass_sancov (gcc::context *ctxt) : gimple_opt_pass (data, ctxt) {}
309 static const pass_data data;
310 opt_pass *
311 clone () final override
313 return new pass_sancov<O0> (m_ctxt);
315 bool
316 gate (function *fun) final override
318 return sanitize_coverage_p (fun->decl) && (!O0 || !optimize);
320 unsigned int
321 execute (function *fun) final override
323 return sancov_pass (fun);
325 }; // class pass_sancov
327 template <bool O0>
328 const pass_data pass_sancov<O0>::data = {
329 GIMPLE_PASS, /* type */
330 O0 ? "sancov_O0" : "sancov", /* name */
331 OPTGROUP_NONE, /* optinfo_flags */
332 TV_NONE, /* tv_id */
333 (PROP_cfg), /* properties_required */
334 0, /* properties_provided */
335 0, /* properties_destroyed */
336 0, /* todo_flags_start */
337 TODO_update_ssa, /* todo_flags_finish */
340 } // anon namespace
342 gimple_opt_pass *
343 make_pass_sancov (gcc::context *ctxt)
345 return new pass_sancov<false> (ctxt);
348 gimple_opt_pass *
349 make_pass_sancov_O0 (gcc::context *ctxt)
351 return new pass_sancov<true> (ctxt);