Fixups after merge
[official-gcc.git] / gcc / sanopt.c
blobe1d11e0d5e60f31e104f88700d7d458b77bfc2f3
1 /* Optimize and expand sanitizer functions.
2 Copyright (C) 2014 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 "hash-table.h"
26 #include "predict.h"
27 #include "vec.h"
28 #include "hashtab.h"
29 #include "hash-set.h"
30 #include "tm.h"
31 #include "hard-reg-set.h"
32 #include "function.h"
33 #include "dominance.h"
34 #include "cfg.h"
35 #include "basic-block.h"
36 #include "tree-ssa-alias.h"
37 #include "internal-fn.h"
38 #include "gimple-expr.h"
39 #include "is-a.h"
40 #include "gimple.h"
41 #include "gimplify.h"
42 #include "gimple-iterator.h"
43 #include "hash-map.h"
44 #include "plugin-api.h"
45 #include "tree-pass.h"
46 #include "asan.h"
47 #include "gimple-pretty-print.h"
48 #include "tm_p.h"
49 #include "langhooks.h"
50 #include "ubsan.h"
51 #include "params.h"
52 #include "tree-ssa-operands.h"
55 /* This is used to carry information about basic blocks. It is
56 attached to the AUX field of the standard CFG block. */
58 struct sanopt_info
60 /* True if this BB might call (directly or indirectly) free/munmap
61 or similar operation. */
62 bool has_freeing_call_p;
64 /* True if HAS_FREEING_CALL_P flag has been computed. */
65 bool has_freeing_call_computed_p;
67 /* True if there is a block with HAS_FREEING_CALL_P flag set
68 on any path between an immediate dominator of BB, denoted
69 imm(BB), and BB. */
70 bool imm_dom_path_with_freeing_call_p;
72 /* True if IMM_DOM_PATH_WITH_FREEING_CALL_P has been computed. */
73 bool imm_dom_path_with_freeing_call_computed_p;
75 /* Number of possibly freeing calls encountered in this bb
76 (so far). */
77 uint64_t freeing_call_events;
79 /* True if BB is currently being visited during computation
80 of IMM_DOM_PATH_WITH_FREEING_CALL_P flag. */
81 bool being_visited_p;
83 /* True if this BB has been visited in the dominator walk. */
84 bool visited_p;
87 /* This is used to carry various hash maps and variables used
88 in sanopt_optimize_walker. */
90 struct sanopt_ctx
92 /* This map maps a pointer (the first argument of UBSAN_NULL) to
93 a vector of UBSAN_NULL call statements that check this pointer. */
94 hash_map<tree, auto_vec<gimple> > null_check_map;
96 /* This map maps a pointer (the second argument of ASAN_CHECK) to
97 a vector of ASAN_CHECK call statements that check the access. */
98 hash_map<tree, auto_vec<gimple> > asan_check_map;
100 /* Number of IFN_ASAN_CHECK statements. */
101 int asan_num_accesses;
105 /* Return true if there might be any call to free/munmap operation
106 on any path in between DOM (which should be imm(BB)) and BB. */
108 static bool
109 imm_dom_path_with_freeing_call (basic_block bb, basic_block dom)
111 sanopt_info *info = (sanopt_info *) bb->aux;
112 edge e;
113 edge_iterator ei;
115 if (info->imm_dom_path_with_freeing_call_computed_p)
116 return info->imm_dom_path_with_freeing_call_p;
118 info->being_visited_p = true;
120 FOR_EACH_EDGE (e, ei, bb->preds)
122 sanopt_info *pred_info = (sanopt_info *) e->src->aux;
124 if (e->src == dom)
125 continue;
127 if ((pred_info->imm_dom_path_with_freeing_call_computed_p
128 && pred_info->imm_dom_path_with_freeing_call_p)
129 || (pred_info->has_freeing_call_computed_p
130 && pred_info->has_freeing_call_p))
132 info->imm_dom_path_with_freeing_call_computed_p = true;
133 info->imm_dom_path_with_freeing_call_p = true;
134 info->being_visited_p = false;
135 return true;
139 FOR_EACH_EDGE (e, ei, bb->preds)
141 sanopt_info *pred_info = (sanopt_info *) e->src->aux;
143 if (e->src == dom)
144 continue;
146 if (pred_info->has_freeing_call_computed_p)
147 continue;
149 gimple_stmt_iterator gsi;
150 for (gsi = gsi_start_bb (e->src); !gsi_end_p (gsi); gsi_next (&gsi))
152 gimple stmt = gsi_stmt (gsi);
154 if (is_gimple_call (stmt) && !nonfreeing_call_p (stmt))
156 pred_info->has_freeing_call_p = true;
157 break;
161 pred_info->has_freeing_call_computed_p = true;
162 if (pred_info->has_freeing_call_p)
164 info->imm_dom_path_with_freeing_call_computed_p = true;
165 info->imm_dom_path_with_freeing_call_p = true;
166 info->being_visited_p = false;
167 return true;
171 FOR_EACH_EDGE (e, ei, bb->preds)
173 if (e->src == dom)
174 continue;
176 basic_block src;
177 for (src = e->src; src != dom; )
179 sanopt_info *pred_info = (sanopt_info *) src->aux;
180 if (pred_info->being_visited_p)
181 break;
182 basic_block imm = get_immediate_dominator (CDI_DOMINATORS, src);
183 if (imm_dom_path_with_freeing_call (src, imm))
185 info->imm_dom_path_with_freeing_call_computed_p = true;
186 info->imm_dom_path_with_freeing_call_p = true;
187 info->being_visited_p = false;
188 return true;
190 src = imm;
194 info->imm_dom_path_with_freeing_call_computed_p = true;
195 info->imm_dom_path_with_freeing_call_p = false;
196 info->being_visited_p = false;
197 return false;
200 /* Optimize away redundant UBSAN_NULL calls. */
202 static bool
203 maybe_optimize_ubsan_null_ifn (struct sanopt_ctx *ctx, gimple stmt)
205 gcc_assert (gimple_call_num_args (stmt) == 3);
206 tree ptr = gimple_call_arg (stmt, 0);
207 tree cur_align = gimple_call_arg (stmt, 2);
208 gcc_assert (TREE_CODE (cur_align) == INTEGER_CST);
209 bool remove = false;
211 auto_vec<gimple> &v = ctx->null_check_map.get_or_insert (ptr);
212 if (v.is_empty ())
214 /* For this PTR we don't have any UBSAN_NULL stmts recorded, so there's
215 nothing to optimize yet. */
216 v.safe_push (stmt);
217 return false;
220 /* We already have recorded a UBSAN_NULL check for this pointer. Perhaps we
221 can drop this one. But only if this check doesn't specify stricter
222 alignment. */
223 while (!v.is_empty ())
225 gimple g = v.last ();
226 /* Remove statements for BBs that have been already processed. */
227 sanopt_info *si = (sanopt_info *) gimple_bb (g)->aux;
228 if (si->visited_p)
230 v.pop ();
231 continue;
234 /* At this point we shouldn't have any statements that aren't dominating
235 the current BB. */
236 tree align = gimple_call_arg (g, 2);
237 int kind = tree_to_shwi (gimple_call_arg (g, 1));
238 /* If this is a NULL pointer check where we had segv anyway, we can
239 remove it. */
240 if (integer_zerop (align)
241 && (kind == UBSAN_LOAD_OF
242 || kind == UBSAN_STORE_OF
243 || kind == UBSAN_MEMBER_ACCESS))
244 remove = true;
245 /* Otherwise remove the check in non-recovering mode, or if the
246 stmts have same location. */
247 else if (integer_zerop (align))
248 remove = (flag_sanitize_recover & SANITIZE_NULL) == 0
249 || flag_sanitize_undefined_trap_on_error
250 || gimple_location (g) == gimple_location (stmt);
251 else if (tree_int_cst_le (cur_align, align))
252 remove = (flag_sanitize_recover & SANITIZE_ALIGNMENT) == 0
253 || flag_sanitize_undefined_trap_on_error
254 || gimple_location (g) == gimple_location (stmt);
255 if (!remove && gimple_bb (g) == gimple_bb (stmt)
256 && tree_int_cst_compare (cur_align, align) == 0)
257 v.pop ();
258 break;
261 if (!remove)
262 v.safe_push (stmt);
263 return remove;
266 /* Optimize away redundant ASAN_CHECK calls. */
268 static bool
269 maybe_optimize_asan_check_ifn (struct sanopt_ctx *ctx, gimple stmt)
271 gcc_assert (gimple_call_num_args (stmt) == 4);
272 tree ptr = gimple_call_arg (stmt, 1);
273 tree len = gimple_call_arg (stmt, 2);
274 basic_block bb = gimple_bb (stmt);
275 sanopt_info *info = (sanopt_info *) bb->aux;
277 if (TREE_CODE (len) != INTEGER_CST)
278 return false;
279 if (integer_zerop (len))
280 return false;
282 gimple_set_uid (stmt, info->freeing_call_events);
284 auto_vec<gimple> &v = ctx->asan_check_map.get_or_insert (ptr);
285 if (v.is_empty ())
287 /* For this PTR we don't have any ASAN_CHECK stmts recorded, so there's
288 nothing to optimize yet. */
289 v.safe_push (stmt);
290 return false;
293 /* We already have recorded a ASAN_CHECK check for this pointer. Perhaps
294 we can drop this one. But only if this check doesn't specify larger
295 size. */
296 while (!v.is_empty ())
298 gimple g = v.last ();
299 /* Remove statements for BBs that have been already processed. */
300 sanopt_info *si = (sanopt_info *) gimple_bb (g)->aux;
301 if (si->visited_p)
302 v.pop ();
303 else
304 break;
307 unsigned int i;
308 gimple g;
309 gimple to_pop = NULL;
310 bool remove = false;
311 basic_block last_bb = bb;
312 bool cleanup = false;
314 FOR_EACH_VEC_ELT_REVERSE (v, i, g)
316 basic_block gbb = gimple_bb (g);
317 sanopt_info *si = (sanopt_info *) gbb->aux;
318 if (gimple_uid (g) < si->freeing_call_events)
320 /* If there is a potentially freeing call after g in gbb, we should
321 remove it from the vector, can't use in optimization. */
322 cleanup = true;
323 continue;
326 if (TREE_CODE (len) != INTEGER_CST)
328 /* If there is some stmts not followed by freeing call event
329 for ptr already in the current bb, no need to insert anything.
330 Non-constant len is treated just as length 1. */
331 if (gbb == bb)
332 return false;
333 break;
336 tree glen = gimple_call_arg (g, 2);
337 /* If we've checked only smaller length than we want to check now,
338 we can't remove the current stmt. If g is in the same basic block,
339 we want to remove it though, as the current stmt is better. */
340 if (tree_int_cst_lt (glen, len))
342 if (gbb == bb)
344 to_pop = g;
345 cleanup = true;
347 continue;
350 while (last_bb != gbb)
352 /* Paths from last_bb to bb have been checked before.
353 gbb is necessarily a dominator of last_bb, but not necessarily
354 immediate dominator. */
355 if (((sanopt_info *) last_bb->aux)->freeing_call_events)
356 break;
358 basic_block imm = get_immediate_dominator (CDI_DOMINATORS, last_bb);
359 gcc_assert (imm);
360 if (imm_dom_path_with_freeing_call (last_bb, imm))
361 break;
363 last_bb = imm;
365 if (last_bb == gbb)
366 remove = true;
367 break;
370 if (cleanup)
372 unsigned int j = 0, l = v.length ();
373 for (i = 0; i < l; i++)
374 if (v[i] != to_pop
375 && (gimple_uid (v[i])
376 == ((sanopt_info *)
377 gimple_bb (v[i])->aux)->freeing_call_events))
379 if (i != j)
380 v[j] = v[i];
381 j++;
383 v.truncate (j);
386 if (!remove)
387 v.safe_push (stmt);
388 return remove;
391 /* Try to optimize away redundant UBSAN_NULL and ASAN_CHECK calls.
393 We walk blocks in the CFG via a depth first search of the dominator
394 tree; we push unique UBSAN_NULL or ASAN_CHECK statements into a vector
395 in the NULL_CHECK_MAP or ASAN_CHECK_MAP hash maps as we enter the
396 blocks. When leaving a block, we mark the block as visited; then
397 when checking the statements in the vector, we ignore statements that
398 are coming from already visited blocks, because these cannot dominate
399 anything anymore. CTX is a sanopt context. */
401 static void
402 sanopt_optimize_walker (basic_block bb, struct sanopt_ctx *ctx)
404 basic_block son;
405 gimple_stmt_iterator gsi;
406 sanopt_info *info = (sanopt_info *) bb->aux;
407 bool asan_check_optimize
408 = (flag_sanitize & SANITIZE_ADDRESS)
409 && ((flag_sanitize & flag_sanitize_recover
410 & SANITIZE_KERNEL_ADDRESS) == 0);
412 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
414 gimple stmt = gsi_stmt (gsi);
415 bool remove = false;
417 if (!is_gimple_call (stmt))
419 /* Handle asm volatile or asm with "memory" clobber
420 the same as potentionally freeing call. */
421 gasm *asm_stmt = dyn_cast <gasm *> (stmt);
422 if (asm_stmt
423 && asan_check_optimize
424 && (gimple_asm_clobbers_memory_p (asm_stmt)
425 || gimple_asm_volatile_p (asm_stmt)))
426 info->freeing_call_events++;
427 gsi_next (&gsi);
428 continue;
431 if (asan_check_optimize && !nonfreeing_call_p (stmt))
432 info->freeing_call_events++;
434 if (gimple_call_internal_p (stmt))
435 switch (gimple_call_internal_fn (stmt))
437 case IFN_UBSAN_NULL:
438 remove = maybe_optimize_ubsan_null_ifn (ctx, stmt);
439 break;
440 case IFN_ASAN_CHECK:
441 if (asan_check_optimize)
442 remove = maybe_optimize_asan_check_ifn (ctx, stmt);
443 if (!remove)
444 ctx->asan_num_accesses++;
445 break;
446 default:
447 break;
450 if (remove)
452 /* Drop this check. */
453 if (dump_file && (dump_flags & TDF_DETAILS))
455 fprintf (dump_file, "Optimizing out\n ");
456 print_gimple_stmt (dump_file, stmt, 0, dump_flags);
457 fprintf (dump_file, "\n");
459 unlink_stmt_vdef (stmt);
460 gsi_remove (&gsi, true);
462 else
463 gsi_next (&gsi);
466 if (asan_check_optimize)
468 info->has_freeing_call_p = info->freeing_call_events != 0;
469 info->has_freeing_call_computed_p = true;
472 for (son = first_dom_son (CDI_DOMINATORS, bb);
473 son;
474 son = next_dom_son (CDI_DOMINATORS, son))
475 sanopt_optimize_walker (son, ctx);
477 /* We're leaving this BB, so mark it to that effect. */
478 info->visited_p = true;
481 /* Try to remove redundant sanitizer checks in function FUN. */
483 static int
484 sanopt_optimize (function *fun)
486 struct sanopt_ctx ctx;
487 ctx.asan_num_accesses = 0;
489 /* Set up block info for each basic block. */
490 alloc_aux_for_blocks (sizeof (sanopt_info));
492 /* We're going to do a dominator walk, so ensure that we have
493 dominance information. */
494 calculate_dominance_info (CDI_DOMINATORS);
496 /* Recursively walk the dominator tree optimizing away
497 redundant checks. */
498 sanopt_optimize_walker (ENTRY_BLOCK_PTR_FOR_FN (fun), &ctx);
500 free_aux_for_blocks ();
502 return ctx.asan_num_accesses;
505 /* Perform optimization of sanitize functions. */
507 namespace {
509 const pass_data pass_data_sanopt =
511 GIMPLE_PASS, /* type */
512 "sanopt", /* name */
513 OPTGROUP_NONE, /* optinfo_flags */
514 TV_NONE, /* tv_id */
515 ( PROP_ssa | PROP_cfg | PROP_gimple_leh ), /* properties_required */
516 0, /* properties_provided */
517 0, /* properties_destroyed */
518 0, /* todo_flags_start */
519 TODO_update_ssa, /* todo_flags_finish */
522 class pass_sanopt : public gimple_opt_pass
524 public:
525 pass_sanopt (gcc::context *ctxt)
526 : gimple_opt_pass (pass_data_sanopt, ctxt)
529 /* opt_pass methods: */
530 virtual bool gate (function *) { return flag_sanitize; }
531 virtual unsigned int execute (function *);
533 }; // class pass_sanopt
535 unsigned int
536 pass_sanopt::execute (function *fun)
538 basic_block bb;
539 int asan_num_accesses = 0;
541 /* Try to remove redundant checks. */
542 if (optimize
543 && (flag_sanitize
544 & (SANITIZE_NULL | SANITIZE_ALIGNMENT | SANITIZE_ADDRESS)))
545 asan_num_accesses = sanopt_optimize (fun);
546 else if (flag_sanitize & SANITIZE_ADDRESS)
548 gimple_stmt_iterator gsi;
549 FOR_EACH_BB_FN (bb, fun)
550 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
552 gimple stmt = gsi_stmt (gsi);
553 if (is_gimple_call (stmt) && gimple_call_internal_p (stmt)
554 && gimple_call_internal_fn (stmt) == IFN_ASAN_CHECK)
555 ++asan_num_accesses;
559 bool use_calls = ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD < INT_MAX
560 && asan_num_accesses >= ASAN_INSTRUMENTATION_WITH_CALL_THRESHOLD;
562 FOR_EACH_BB_FN (bb, fun)
564 gimple_stmt_iterator gsi;
565 for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
567 gimple stmt = gsi_stmt (gsi);
568 bool no_next = false;
570 if (!is_gimple_call (stmt))
572 gsi_next (&gsi);
573 continue;
576 if (gimple_call_internal_p (stmt))
578 enum internal_fn ifn = gimple_call_internal_fn (stmt);
579 switch (ifn)
581 case IFN_UBSAN_NULL:
582 no_next = ubsan_expand_null_ifn (&gsi);
583 break;
584 case IFN_UBSAN_BOUNDS:
585 no_next = ubsan_expand_bounds_ifn (&gsi);
586 break;
587 case IFN_UBSAN_OBJECT_SIZE:
588 no_next = ubsan_expand_objsize_ifn (&gsi);
589 break;
590 case IFN_ASAN_CHECK:
591 no_next = asan_expand_check_ifn (&gsi, use_calls);
592 break;
593 default:
594 break;
597 else if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
599 tree callee = gimple_call_fndecl (stmt);
600 switch (DECL_FUNCTION_CODE (callee))
602 case BUILT_IN_UNREACHABLE:
603 if (flag_sanitize & SANITIZE_UNREACHABLE
604 && !lookup_attribute ("no_sanitize_undefined",
605 DECL_ATTRIBUTES (fun->decl)))
606 no_next = ubsan_instrument_unreachable (&gsi);
607 break;
608 default:
609 break;
613 if (dump_file && (dump_flags & TDF_DETAILS))
615 fprintf (dump_file, "Expanded\n ");
616 print_gimple_stmt (dump_file, stmt, 0, dump_flags);
617 fprintf (dump_file, "\n");
620 if (!no_next)
621 gsi_next (&gsi);
624 return 0;
627 } // anon namespace
629 gimple_opt_pass *
630 make_pass_sanopt (gcc::context *ctxt)
632 return new pass_sanopt (ctxt);