Line data Source code
1 : /* Optimize and expand sanitizer functions.
2 : Copyright (C) 2014-2026 Free Software Foundation, Inc.
3 : Contributed by Marek Polacek <polacek@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 "backend.h"
25 : #include "tree.h"
26 : #include "gimple.h"
27 : #include "ssa.h"
28 : #include "tree-pass.h"
29 : #include "tree-ssa-operands.h"
30 : #include "gimple-pretty-print.h"
31 : #include "fold-const.h"
32 : #include "gimple-iterator.h"
33 : #include "stringpool.h"
34 : #include "attribs.h"
35 : #include "asan.h"
36 : #include "ubsan.h"
37 : #include "tree-hash-traits.h"
38 : #include "gimple-ssa.h"
39 : #include "tree-phinodes.h"
40 : #include "ssa-iterators.h"
41 : #include "gimplify.h"
42 : #include "gimple-walk.h"
43 : #include "cfghooks.h"
44 : #include "tree-dfa.h"
45 : #include "tree-ssa.h"
46 : #include "varasm.h"
47 :
48 : /* This is used to carry information about basic blocks. It is
49 : attached to the AUX field of the standard CFG block. */
50 :
51 : struct sanopt_info
52 : {
53 : /* True if this BB might call (directly or indirectly) free/munmap
54 : or similar operation. */
55 : bool has_freeing_call_p;
56 :
57 : /* True if HAS_FREEING_CALL_P flag has been computed. */
58 : bool has_freeing_call_computed_p;
59 :
60 : /* True if there is a block with HAS_FREEING_CALL_P flag set
61 : on any path between an immediate dominator of BB, denoted
62 : imm(BB), and BB. */
63 : bool imm_dom_path_with_freeing_call_p;
64 :
65 : /* True if IMM_DOM_PATH_WITH_FREEING_CALL_P has been computed. */
66 : bool imm_dom_path_with_freeing_call_computed_p;
67 :
68 : /* Number of possibly freeing calls encountered in this bb
69 : (so far). */
70 : uint64_t freeing_call_events;
71 :
72 : /* True if BB is currently being visited during computation
73 : of IMM_DOM_PATH_WITH_FREEING_CALL_P flag. */
74 : bool being_visited_p;
75 :
76 : /* True if this BB has been visited in the dominator walk. */
77 : bool visited_p;
78 : };
79 :
80 : /* If T has a single definition of form T = T2, return T2. */
81 :
82 : static gimple *
83 17329 : maybe_get_single_definition (tree t)
84 : {
85 17329 : if (TREE_CODE (t) == SSA_NAME)
86 : {
87 10978 : gimple *g = SSA_NAME_DEF_STMT (t);
88 10978 : if (gimple_assign_single_p (g))
89 5976 : return g;
90 : }
91 : return NULL;
92 : }
93 :
94 : /* Tree triplet for vptr_check_map. */
95 : struct sanopt_tree_triplet
96 : {
97 : tree t1, t2, t3;
98 : };
99 :
100 : /* Traits class for tree triplet hash maps below. */
101 :
102 : struct sanopt_tree_triplet_hash : typed_noop_remove <sanopt_tree_triplet>
103 : {
104 : typedef sanopt_tree_triplet value_type;
105 : typedef sanopt_tree_triplet compare_type;
106 :
107 : static hashval_t
108 121 : hash (const sanopt_tree_triplet &ref)
109 : {
110 121 : inchash::hash hstate (0);
111 121 : inchash::add_expr (ref.t1, hstate);
112 121 : inchash::add_expr (ref.t2, hstate);
113 121 : inchash::add_expr (ref.t3, hstate);
114 121 : return hstate.end ();
115 : }
116 :
117 : static bool
118 53 : equal (const sanopt_tree_triplet &ref1, const sanopt_tree_triplet &ref2)
119 : {
120 53 : return operand_equal_p (ref1.t1, ref2.t1, 0)
121 16 : && operand_equal_p (ref1.t2, ref2.t2, 0)
122 61 : && operand_equal_p (ref1.t3, ref2.t3, 0);
123 : }
124 :
125 : static void
126 : mark_deleted (sanopt_tree_triplet &ref)
127 : {
128 : ref.t1 = reinterpret_cast<tree> (1);
129 : }
130 :
131 : static const bool empty_zero_p = true;
132 :
133 : static void
134 0 : mark_empty (sanopt_tree_triplet &ref)
135 : {
136 0 : ref.t1 = NULL;
137 : }
138 :
139 : static bool
140 129 : is_deleted (const sanopt_tree_triplet &ref)
141 : {
142 129 : return ref.t1 == reinterpret_cast<tree> (1);
143 : }
144 :
145 : static bool
146 101314 : is_empty (const sanopt_tree_triplet &ref)
147 : {
148 101246 : return ref.t1 == NULL;
149 : }
150 : };
151 :
152 : /* Tree couple for ptr_check_map. */
153 : struct sanopt_tree_couple
154 : {
155 : tree ptr;
156 : bool pos_p;
157 : };
158 :
159 : /* Traits class for tree triplet hash maps below. */
160 :
161 : struct sanopt_tree_couple_hash : typed_noop_remove <sanopt_tree_couple>
162 : {
163 : typedef sanopt_tree_couple value_type;
164 : typedef sanopt_tree_couple compare_type;
165 :
166 : static hashval_t
167 5638 : hash (const sanopt_tree_couple &ref)
168 : {
169 5638 : inchash::hash hstate (0);
170 5638 : inchash::add_expr (ref.ptr, hstate);
171 5638 : hstate.add_int (ref.pos_p);
172 5638 : return hstate.end ();
173 : }
174 :
175 : static bool
176 4113 : equal (const sanopt_tree_couple &ref1, const sanopt_tree_couple &ref2)
177 : {
178 4113 : return operand_equal_p (ref1.ptr, ref2.ptr, 0)
179 4113 : && ref1.pos_p == ref2.pos_p;
180 : }
181 :
182 : static void
183 : mark_deleted (sanopt_tree_couple &ref)
184 : {
185 : ref.ptr = reinterpret_cast<tree> (1);
186 : }
187 :
188 : static const bool empty_zero_p = true;
189 :
190 : static void
191 0 : mark_empty (sanopt_tree_couple &ref)
192 : {
193 0 : ref.ptr = NULL;
194 : }
195 :
196 : static bool
197 5903 : is_deleted (const sanopt_tree_couple &ref)
198 : {
199 5903 : return ref.ptr == reinterpret_cast<tree> (1);
200 : }
201 :
202 : static bool
203 134933 : is_empty (const sanopt_tree_couple &ref)
204 : {
205 134365 : return ref.ptr == NULL;
206 : }
207 : };
208 :
209 : /* This is used to carry various hash maps and variables used
210 : in sanopt_optimize_walker. */
211 :
212 : class sanopt_ctx
213 : {
214 : public:
215 : /* This map maps a pointer (the first argument of UBSAN_NULL) to
216 : a vector of UBSAN_NULL call statements that check this pointer. */
217 : hash_map<tree, auto_vec<gimple *> > null_check_map;
218 :
219 : /* This map maps a pointer (the second argument of ASAN_CHECK) to
220 : a vector of ASAN_CHECK call statements that check the access. */
221 : hash_map<tree_operand_hash, auto_vec<gimple *> > asan_check_map;
222 :
223 : /* This map maps a tree triplet (the first, second and fourth argument
224 : of UBSAN_VPTR) to a vector of UBSAN_VPTR call statements that check
225 : that virtual table pointer. */
226 : hash_map<sanopt_tree_triplet_hash, auto_vec<gimple *> > vptr_check_map;
227 :
228 : /* This map maps a couple (tree and boolean) to a vector of UBSAN_PTR
229 : call statements that check that pointer overflow. */
230 : hash_map<sanopt_tree_couple_hash, auto_vec<gimple *> > ptr_check_map;
231 :
232 : /* Number of IFN_ASAN_CHECK statements. */
233 : int asan_num_accesses;
234 :
235 : /* True when the current functions contains an ASAN_MARK. */
236 : bool contains_asan_mark;
237 : };
238 :
239 : /* Return true if there might be any call to free/munmap operation
240 : on any path in between DOM (which should be imm(BB)) and BB. */
241 :
242 : static bool
243 3566 : imm_dom_path_with_freeing_call (basic_block bb, basic_block dom)
244 : {
245 3566 : sanopt_info *info = (sanopt_info *) bb->aux;
246 3566 : edge e;
247 3566 : edge_iterator ei;
248 :
249 3566 : if (info->imm_dom_path_with_freeing_call_computed_p)
250 1280 : return info->imm_dom_path_with_freeing_call_p;
251 :
252 2286 : info->being_visited_p = true;
253 :
254 5439 : FOR_EACH_EDGE (e, ei, bb->preds)
255 : {
256 3169 : sanopt_info *pred_info = (sanopt_info *) e->src->aux;
257 :
258 3169 : if (e->src == dom)
259 1755 : continue;
260 :
261 1414 : if ((pred_info->imm_dom_path_with_freeing_call_computed_p
262 50 : && pred_info->imm_dom_path_with_freeing_call_p)
263 1414 : || (pred_info->has_freeing_call_computed_p
264 341 : && pred_info->has_freeing_call_p))
265 : {
266 16 : info->imm_dom_path_with_freeing_call_computed_p = true;
267 16 : info->imm_dom_path_with_freeing_call_p = true;
268 16 : info->being_visited_p = false;
269 16 : return true;
270 : }
271 : }
272 :
273 4980 : FOR_EACH_EDGE (e, ei, bb->preds)
274 : {
275 3015 : sanopt_info *pred_info = (sanopt_info *) e->src->aux;
276 :
277 3015 : if (e->src == dom)
278 1755 : continue;
279 :
280 1260 : if (pred_info->has_freeing_call_computed_p)
281 270 : continue;
282 :
283 990 : gimple_stmt_iterator gsi;
284 8487 : for (gsi = gsi_start_bb (e->src); !gsi_end_p (gsi); gsi_next (&gsi))
285 : {
286 6812 : gimple *stmt = gsi_stmt (gsi);
287 6812 : gasm *asm_stmt;
288 :
289 6812 : if ((is_gimple_call (stmt) && !nonfreeing_call_p (stmt))
290 13319 : || ((asm_stmt = dyn_cast <gasm *> (stmt))
291 18 : && (gimple_asm_clobbers_memory_p (asm_stmt)
292 0 : || gimple_asm_volatile_p (asm_stmt))))
293 : {
294 305 : pred_info->has_freeing_call_p = true;
295 305 : break;
296 : }
297 : }
298 :
299 990 : pred_info->has_freeing_call_computed_p = true;
300 990 : if (pred_info->has_freeing_call_p)
301 : {
302 305 : info->imm_dom_path_with_freeing_call_computed_p = true;
303 305 : info->imm_dom_path_with_freeing_call_p = true;
304 305 : info->being_visited_p = false;
305 305 : return true;
306 : }
307 : }
308 :
309 4158 : FOR_EACH_EDGE (e, ei, bb->preds)
310 : {
311 2307 : if (e->src == dom)
312 1709 : continue;
313 :
314 : basic_block src;
315 1528 : for (src = e->src; src != dom; )
316 : {
317 1129 : sanopt_info *pred_info = (sanopt_info *) src->aux;
318 1129 : if (pred_info->being_visited_p)
319 : break;
320 1044 : basic_block imm = get_immediate_dominator (CDI_DOMINATORS, src);
321 1044 : if (imm_dom_path_with_freeing_call (src, imm))
322 : {
323 114 : info->imm_dom_path_with_freeing_call_computed_p = true;
324 114 : info->imm_dom_path_with_freeing_call_p = true;
325 114 : info->being_visited_p = false;
326 114 : return true;
327 : }
328 : src = imm;
329 : }
330 : }
331 :
332 1851 : info->imm_dom_path_with_freeing_call_computed_p = true;
333 1851 : info->imm_dom_path_with_freeing_call_p = false;
334 1851 : info->being_visited_p = false;
335 1851 : return false;
336 : }
337 :
338 : /* Get the first dominating check from the list of stored checks.
339 : Non-dominating checks are silently dropped. */
340 :
341 : static gimple *
342 27118 : maybe_get_dominating_check (auto_vec<gimple *> &v)
343 : {
344 28737 : for (; !v.is_empty (); v.pop ())
345 : {
346 7165 : gimple *g = v.last ();
347 7165 : sanopt_info *si = (sanopt_info *) gimple_bb (g)->aux;
348 7165 : if (!si->visited_p)
349 : /* At this point we shouldn't have any statements
350 : that aren't dominating the current BB. */
351 : return g;
352 : }
353 : return NULL;
354 : }
355 :
356 : /* Optimize away redundant UBSAN_NULL calls. */
357 :
358 : static bool
359 2225 : maybe_optimize_ubsan_null_ifn (class sanopt_ctx *ctx, gimple *stmt)
360 : {
361 2225 : gcc_assert (gimple_call_num_args (stmt) == 3);
362 2225 : tree ptr = gimple_call_arg (stmt, 0);
363 2225 : tree cur_align = gimple_call_arg (stmt, 2);
364 2225 : gcc_assert (TREE_CODE (cur_align) == INTEGER_CST);
365 2225 : bool remove = false;
366 :
367 2225 : auto_vec<gimple *> &v = ctx->null_check_map.get_or_insert (ptr);
368 2225 : gimple *g = maybe_get_dominating_check (v);
369 2225 : if (!g)
370 : {
371 : /* For this PTR we don't have any UBSAN_NULL stmts recorded, so there's
372 : nothing to optimize yet. */
373 1338 : v.safe_push (stmt);
374 1338 : return false;
375 : }
376 :
377 : /* We already have recorded a UBSAN_NULL check for this pointer. Perhaps we
378 : can drop this one. But only if this check doesn't specify stricter
379 : alignment. */
380 :
381 887 : tree align = gimple_call_arg (g, 2);
382 887 : int kind = tree_to_shwi (gimple_call_arg (g, 1));
383 : /* If this is a NULL pointer check where we had segv anyway, we can
384 : remove it. */
385 887 : if (integer_zerop (align)
386 887 : && (kind == UBSAN_LOAD_OF
387 118 : || kind == UBSAN_STORE_OF
388 118 : || kind == UBSAN_MEMBER_ACCESS))
389 : remove = true;
390 : /* Otherwise remove the check in non-recovering mode, or if the
391 : stmts have same location. */
392 793 : else if (integer_zerop (align))
393 24 : remove = (flag_sanitize_recover & SANITIZE_NULL) == 0
394 12 : || (flag_sanitize_trap & SANITIZE_NULL) != 0
395 24 : || gimple_location (g) == gimple_location (stmt);
396 769 : else if (tree_int_cst_le (cur_align, align))
397 768 : remove = (flag_sanitize_recover & SANITIZE_ALIGNMENT) == 0
398 615 : || (flag_sanitize_trap & SANITIZE_ALIGNMENT) != 0
399 1343 : || gimple_location (g) == gimple_location (stmt);
400 :
401 362 : if (!remove && gimple_bb (g) == gimple_bb (stmt)
402 252 : && tree_int_cst_compare (cur_align, align) == 0)
403 252 : v.pop ();
404 :
405 887 : if (!remove)
406 362 : v.safe_push (stmt);
407 : return remove;
408 : }
409 :
410 : /* Return true when pointer PTR for a given CUR_OFFSET is already sanitized
411 : in a given sanitization context CTX. */
412 :
413 : static bool
414 1512 : has_dominating_ubsan_ptr_check (sanopt_ctx *ctx, tree ptr,
415 : offset_int &cur_offset)
416 : {
417 1512 : bool pos_p = !wi::neg_p (cur_offset);
418 1512 : sanopt_tree_couple couple;
419 1512 : couple.ptr = ptr;
420 1512 : couple.pos_p = pos_p;
421 :
422 1512 : auto_vec<gimple *> &v = ctx->ptr_check_map.get_or_insert (couple);
423 1512 : gimple *g = maybe_get_dominating_check (v);
424 1512 : if (!g)
425 : return false;
426 :
427 : /* We already have recorded a UBSAN_PTR check for this pointer. Perhaps we
428 : can drop this one. But only if this check doesn't specify larger offset.
429 : */
430 659 : tree offset = gimple_call_arg (g, 1);
431 659 : gcc_assert (TREE_CODE (offset) == INTEGER_CST);
432 1318 : offset_int ooffset = wi::sext (wi::to_offset (offset), POINTER_SIZE);
433 :
434 659 : if (pos_p)
435 : {
436 564 : if (wi::les_p (cur_offset, ooffset))
437 373 : return true;
438 : }
439 95 : else if (!pos_p && wi::les_p (ooffset, cur_offset))
440 79 : return true;
441 :
442 : return false;
443 : }
444 :
445 : /* Record UBSAN_PTR check of given context CTX. Register pointer PTR on
446 : a given OFFSET that it's handled by GIMPLE STMT. */
447 :
448 : static void
449 738 : record_ubsan_ptr_check_stmt (sanopt_ctx *ctx, gimple *stmt, tree ptr,
450 : const offset_int &offset)
451 : {
452 738 : sanopt_tree_couple couple;
453 738 : couple.ptr = ptr;
454 738 : couple.pos_p = !wi::neg_p (offset);
455 :
456 738 : auto_vec<gimple *> &v = ctx->ptr_check_map.get_or_insert (couple);
457 738 : v.safe_push (stmt);
458 738 : }
459 :
460 : /* Optimize away redundant UBSAN_PTR calls. */
461 :
462 : static bool
463 1525 : maybe_optimize_ubsan_ptr_ifn (sanopt_ctx *ctx, gimple *stmt)
464 : {
465 1525 : poly_int64 bitsize, pbitpos;
466 1525 : machine_mode mode;
467 1525 : int volatilep = 0, reversep, unsignedp = 0;
468 1525 : tree offset;
469 :
470 1525 : gcc_assert (gimple_call_num_args (stmt) == 2);
471 1525 : tree ptr = gimple_call_arg (stmt, 0);
472 1525 : tree off = gimple_call_arg (stmt, 1);
473 :
474 1525 : if (TREE_CODE (off) != INTEGER_CST)
475 : return false;
476 :
477 1226 : if (integer_zerop (off))
478 : return true;
479 :
480 2452 : offset_int cur_offset = wi::sext (wi::to_offset (off), POINTER_SIZE);
481 1226 : if (has_dominating_ubsan_ptr_check (ctx, ptr, cur_offset))
482 : return true;
483 :
484 922 : tree base = ptr;
485 922 : if (TREE_CODE (base) == ADDR_EXPR)
486 : {
487 445 : base = TREE_OPERAND (base, 0);
488 :
489 445 : HOST_WIDE_INT bitpos;
490 445 : base = get_inner_reference (base, &bitsize, &pbitpos, &offset, &mode,
491 : &unsignedp, &reversep, &volatilep);
492 40 : if ((offset == NULL_TREE || TREE_CODE (offset) == INTEGER_CST)
493 445 : && DECL_P (base)
494 : && ((!VAR_P (base)
495 : && TREE_CODE (base) != PARM_DECL
496 : && TREE_CODE (base) != RESULT_DECL)
497 444 : || !DECL_REGISTER (base))
498 445 : && pbitpos.is_constant (&bitpos))
499 : {
500 445 : offset_int expr_offset;
501 445 : if (offset)
502 40 : expr_offset = wi::to_offset (offset) + bitpos / BITS_PER_UNIT;
503 : else
504 405 : expr_offset = bitpos / BITS_PER_UNIT;
505 445 : expr_offset = wi::sext (expr_offset, POINTER_SIZE);
506 445 : offset_int total_offset = expr_offset + cur_offset;
507 445 : if (total_offset != wi::sext (total_offset, POINTER_SIZE))
508 : {
509 8 : record_ubsan_ptr_check_stmt (ctx, stmt, ptr, cur_offset);
510 307 : return false;
511 : }
512 :
513 : /* If BASE is a fixed size automatic variable or
514 : global variable defined in the current TU, we don't have
515 : to instrument anything if offset is within address
516 : of the variable. */
517 437 : if ((VAR_P (base)
518 : || TREE_CODE (base) == PARM_DECL
519 : || TREE_CODE (base) == RESULT_DECL)
520 436 : && DECL_SIZE_UNIT (base)
521 436 : && TREE_CODE (DECL_SIZE_UNIT (base)) == INTEGER_CST
522 436 : && (!is_global_var (base) || decl_binds_to_current_def_p (base)))
523 : {
524 383 : offset_int base_size = wi::to_offset (DECL_SIZE_UNIT (base));
525 383 : if (!wi::neg_p (expr_offset)
526 702 : && wi::les_p (total_offset, base_size))
527 : {
528 255 : if (!wi::neg_p (total_offset)
529 470 : && wi::les_p (total_offset, base_size))
530 215 : return true;
531 : }
532 : }
533 :
534 : /* Following expression: UBSAN_PTR (&MEM_REF[ptr + x], y) can be
535 : handled as follows:
536 :
537 : 1) sign (x) == sign (y), then check for dominating check of (x + y)
538 : 2) sign (x) != sign (y), then first check if we have a dominating
539 : check for ptr + x. If so, then we have 2 situations:
540 : a) sign (x) == sign (x + y), here we are done, example:
541 : UBSAN_PTR (&MEM_REF[ptr + 100], -50)
542 : b) check for dominating check of ptr + x + y.
543 : */
544 :
545 222 : bool sign_cur_offset = !wi::neg_p (cur_offset);
546 222 : bool sign_expr_offset = !wi::neg_p (expr_offset);
547 :
548 222 : tree base_addr
549 222 : = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (base)), base);
550 :
551 222 : bool add = false;
552 222 : if (sign_cur_offset == sign_expr_offset)
553 : {
554 103 : if (has_dominating_ubsan_ptr_check (ctx, base_addr, total_offset))
555 : return true;
556 : else
557 : add = true;
558 : }
559 : else
560 : {
561 119 : if (!has_dominating_ubsan_ptr_check (ctx, base_addr, expr_offset))
562 : ; /* Don't record base_addr + expr_offset, it's not a guarding
563 : check. */
564 : else
565 : {
566 96 : bool sign_total_offset = !wi::neg_p (total_offset);
567 96 : if (sign_expr_offset == sign_total_offset)
568 : return true;
569 : else
570 : {
571 64 : if (has_dominating_ubsan_ptr_check (ctx, base_addr,
572 : total_offset))
573 : return true;
574 : else
575 : add = true;
576 : }
577 : }
578 : }
579 :
580 : /* Record a new dominating check for base_addr + total_offset. */
581 115 : if (add && !operand_equal_p (base, base_addr, 0))
582 115 : record_ubsan_ptr_check_stmt (ctx, stmt, base_addr,
583 : total_offset);
584 : }
585 : }
586 :
587 : /* For this PTR we don't have any UBSAN_PTR stmts recorded, so there's
588 : nothing to optimize yet. */
589 615 : record_ubsan_ptr_check_stmt (ctx, stmt, ptr, cur_offset);
590 :
591 615 : return false;
592 : }
593 :
594 : /* Optimize away redundant UBSAN_VPTR calls. The second argument
595 : is the value loaded from the virtual table, so rely on FRE to find out
596 : when we can actually optimize. */
597 :
598 : static bool
599 76 : maybe_optimize_ubsan_vptr_ifn (class sanopt_ctx *ctx, gimple *stmt)
600 : {
601 76 : gcc_assert (gimple_call_num_args (stmt) == 5);
602 76 : sanopt_tree_triplet triplet;
603 76 : triplet.t1 = gimple_call_arg (stmt, 0);
604 76 : triplet.t2 = gimple_call_arg (stmt, 1);
605 76 : triplet.t3 = gimple_call_arg (stmt, 3);
606 :
607 76 : auto_vec<gimple *> &v = ctx->vptr_check_map.get_or_insert (triplet);
608 76 : gimple *g = maybe_get_dominating_check (v);
609 76 : if (!g)
610 : {
611 : /* For this PTR we don't have any UBSAN_VPTR stmts recorded, so there's
612 : nothing to optimize yet. */
613 68 : v.safe_push (stmt);
614 68 : return false;
615 : }
616 :
617 : return true;
618 : }
619 :
620 : /* Checks whether value of T in CHECK and USE is the same. */
621 :
622 : static bool
623 16 : same_value_p (gimple *check, gimple *use, tree t)
624 : {
625 16 : tree check_vuse = gimple_vuse (check);
626 16 : tree use_vuse = gimple_vuse (use);
627 :
628 16 : if (TREE_CODE (t) == SSA_NAME
629 16 : || is_gimple_min_invariant (t)
630 32 : || ! use_vuse)
631 : return true;
632 :
633 14 : if (check_vuse == use_vuse)
634 0 : return true;
635 :
636 : return false;
637 : }
638 :
639 : /* Returns TRUE if ASan check of length LEN in block BB can be removed
640 : if preceded by checks in V. */
641 :
642 : static bool
643 3335 : can_remove_asan_check (auto_vec<gimple *> &v, tree len, basic_block bb,
644 : gimple *base_stmt, tree base_addr)
645 : {
646 3335 : unsigned int i;
647 3335 : gimple *g;
648 3335 : gimple *to_pop = NULL;
649 3335 : bool remove = false;
650 3335 : basic_block last_bb = bb;
651 3335 : bool cleanup = false;
652 :
653 7628 : FOR_EACH_VEC_ELT_REVERSE (v, i, g)
654 : {
655 3350 : basic_block gbb = gimple_bb (g);
656 3350 : sanopt_info *si = (sanopt_info *) gbb->aux;
657 3350 : if (gimple_uid (g) < si->freeing_call_events)
658 : {
659 : /* If there is a potentially freeing call after g in gbb, we should
660 : remove it from the vector, can't use in optimization. */
661 922 : cleanup = true;
662 922 : continue;
663 : }
664 :
665 2428 : tree glen = gimple_call_arg (g, 2);
666 2428 : gcc_assert (TREE_CODE (glen) == INTEGER_CST);
667 :
668 : /* If we've checked only smaller length than we want to check now,
669 : we can't remove the current stmt. If g is in the same basic block,
670 : we want to remove it though, as the current stmt is better. */
671 2428 : if (tree_int_cst_lt (glen, len))
672 : {
673 70 : if (gbb == bb)
674 : {
675 50 : to_pop = g;
676 50 : cleanup = true;
677 : }
678 70 : continue;
679 : }
680 :
681 4225 : while (last_bb != gbb)
682 : {
683 : /* Paths from last_bb to bb have been checked before.
684 : gbb is necessarily a dominator of last_bb, but not necessarily
685 : immediate dominator. */
686 3264 : if (((sanopt_info *) last_bb->aux)->freeing_call_events)
687 : break;
688 :
689 2522 : basic_block imm = get_immediate_dominator (CDI_DOMINATORS, last_bb);
690 2522 : gcc_assert (imm);
691 2522 : if (imm_dom_path_with_freeing_call (last_bb, imm))
692 : break;
693 :
694 : last_bb = imm;
695 : }
696 2358 : if (last_bb != gbb)
697 : break;
698 : // In case of base_addr residing in memory we also need to check aliasing
699 961 : remove = ! base_addr || same_value_p (g, base_stmt, base_addr);
700 : break;
701 : }
702 :
703 3335 : if (cleanup)
704 : {
705 972 : unsigned int j = 0, l = v.length ();
706 1996 : for (i = 0; i < l; i++)
707 1024 : if (v[i] != to_pop
708 1024 : && (gimple_uid (v[i])
709 : == ((sanopt_info *)
710 974 : gimple_bb (v[i])->aux)->freeing_call_events))
711 : {
712 52 : if (i != j)
713 0 : v[j] = v[i];
714 52 : j++;
715 : }
716 972 : v.truncate (j);
717 : }
718 :
719 3335 : return remove;
720 : }
721 :
722 : /* Optimize away redundant ASAN_CHECK calls. */
723 :
724 : static bool
725 17329 : maybe_optimize_asan_check_ifn (class sanopt_ctx *ctx, gimple *stmt)
726 : {
727 17329 : gcc_assert (gimple_call_num_args (stmt) == 4);
728 17329 : tree ptr = gimple_call_arg (stmt, 1);
729 17329 : tree len = gimple_call_arg (stmt, 2);
730 17329 : basic_block bb = gimple_bb (stmt);
731 17329 : sanopt_info *info = (sanopt_info *) bb->aux;
732 :
733 17329 : if (TREE_CODE (len) != INTEGER_CST)
734 : return false;
735 17329 : if (integer_zerop (len))
736 : return false;
737 :
738 17329 : gimple_set_uid (stmt, info->freeing_call_events);
739 :
740 17329 : auto_vec<gimple *> *ptr_checks = &ctx->asan_check_map.get_or_insert (ptr);
741 :
742 17329 : gimple *base_stmt = maybe_get_single_definition (ptr);
743 17329 : tree base_addr = base_stmt ? gimple_assign_rhs1 (base_stmt) : NULL_TREE;
744 17329 : auto_vec<gimple *> *base_checks = NULL;
745 17329 : if (base_addr)
746 : {
747 5976 : base_checks = &ctx->asan_check_map.get_or_insert (base_addr);
748 : /* Original pointer might have been invalidated. */
749 5976 : ptr_checks = ctx->asan_check_map.get (ptr);
750 : }
751 :
752 17329 : gimple *g = maybe_get_dominating_check (*ptr_checks);
753 17329 : gimple *g2 = NULL;
754 :
755 17329 : if (base_checks)
756 : /* Try with base address as well. */
757 5976 : g2 = maybe_get_dominating_check (*base_checks);
758 :
759 17329 : if (g == NULL && g2 == NULL)
760 : {
761 : /* For this PTR we don't have any ASAN_CHECK stmts recorded, so there's
762 : nothing to optimize yet. */
763 14477 : ptr_checks->safe_push (stmt);
764 14477 : if (base_checks)
765 4802 : base_checks->safe_push (stmt);
766 : return false;
767 : }
768 :
769 2852 : bool remove = false;
770 :
771 2852 : if (ptr_checks)
772 2852 : remove = can_remove_asan_check (*ptr_checks, len, bb, NULL, NULL);
773 :
774 2852 : if (!remove && base_checks)
775 : /* Try with base address as well. */
776 483 : remove = can_remove_asan_check (*base_checks, len, bb, base_stmt,
777 : base_addr);
778 :
779 2852 : if (!remove)
780 : {
781 1905 : ptr_checks->safe_push (stmt);
782 1905 : if (base_checks)
783 481 : base_checks->safe_push (stmt);
784 : }
785 :
786 : return remove;
787 : }
788 :
789 : /* Try to optimize away redundant UBSAN_NULL and ASAN_CHECK calls.
790 :
791 : We walk blocks in the CFG via a depth first search of the dominator
792 : tree; we push unique UBSAN_NULL or ASAN_CHECK statements into a vector
793 : in the NULL_CHECK_MAP or ASAN_CHECK_MAP hash maps as we enter the
794 : blocks. When leaving a block, we mark the block as visited; then
795 : when checking the statements in the vector, we ignore statements that
796 : are coming from already visited blocks, because these cannot dominate
797 : anything anymore. CTX is a sanopt context. */
798 :
799 : static void
800 40807 : sanopt_optimize_walker (basic_block bb, class sanopt_ctx *ctx)
801 : {
802 40807 : basic_block son;
803 40807 : gimple_stmt_iterator gsi;
804 40807 : sanopt_info *info = (sanopt_info *) bb->aux;
805 40807 : bool asan_check_optimize
806 40807 : = ((flag_sanitize & (SANITIZE_ADDRESS | SANITIZE_HWADDRESS)) != 0);
807 :
808 292789 : for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
809 : {
810 211175 : gimple *stmt = gsi_stmt (gsi);
811 211175 : bool remove = false;
812 :
813 211175 : if (!is_gimple_call (stmt))
814 : {
815 : /* Handle asm volatile or asm with "memory" clobber
816 : the same as potentially freeing call. */
817 165706 : gasm *asm_stmt = dyn_cast <gasm *> (stmt);
818 165706 : if (asm_stmt
819 165706 : && asan_check_optimize
820 165706 : && (gimple_asm_clobbers_memory_p (asm_stmt)
821 56 : || gimple_asm_volatile_p (asm_stmt)))
822 194 : info->freeing_call_events++;
823 165706 : gsi_next (&gsi);
824 165706 : continue;
825 165706 : }
826 :
827 45469 : if (asan_check_optimize && !nonfreeing_call_p (stmt))
828 14016 : info->freeing_call_events++;
829 :
830 : /* If __asan_before_dynamic_init ("module"); is followed by
831 : __asan_after_dynamic_init (); without intervening memory loads/stores,
832 : there is nothing to guard, so optimize both away. */
833 45469 : if (asan_check_optimize
834 45469 : && gimple_call_builtin_p (stmt, BUILT_IN_ASAN_BEFORE_DYNAMIC_INIT))
835 : {
836 19 : gcc_assert (!hwasan_sanitize_p ());
837 19 : use_operand_p use;
838 19 : gimple *use_stmt;
839 38 : if (single_imm_use (gimple_vdef (stmt), &use, &use_stmt))
840 : {
841 19 : if (is_gimple_call (use_stmt)
842 19 : && gimple_call_builtin_p (use_stmt,
843 : BUILT_IN_ASAN_AFTER_DYNAMIC_INIT))
844 : {
845 7 : unlink_stmt_vdef (use_stmt);
846 7 : gimple_stmt_iterator gsi2 = gsi_for_stmt (use_stmt);
847 7 : gsi_remove (&gsi2, true);
848 7 : remove = true;
849 : }
850 : }
851 : }
852 :
853 45469 : if (gimple_call_internal_p (stmt))
854 28855 : switch (gimple_call_internal_fn (stmt))
855 : {
856 2225 : case IFN_UBSAN_NULL:
857 2225 : remove = maybe_optimize_ubsan_null_ifn (ctx, stmt);
858 2225 : break;
859 76 : case IFN_UBSAN_VPTR:
860 76 : remove = maybe_optimize_ubsan_vptr_ifn (ctx, stmt);
861 76 : break;
862 1525 : case IFN_UBSAN_PTR:
863 1525 : remove = maybe_optimize_ubsan_ptr_ifn (ctx, stmt);
864 1525 : break;
865 17329 : case IFN_HWASAN_CHECK:
866 17329 : case IFN_ASAN_CHECK:
867 17329 : if (asan_check_optimize)
868 17329 : remove = maybe_optimize_asan_check_ifn (ctx, stmt);
869 17329 : if (!remove)
870 16382 : ctx->asan_num_accesses++;
871 : break;
872 6581 : case IFN_ASAN_MARK:
873 6581 : ctx->contains_asan_mark = true;
874 6581 : break;
875 : default:
876 : break;
877 : }
878 :
879 44522 : if (remove)
880 : {
881 : /* Drop this check. */
882 2090 : if (dump_file && (dump_flags & TDF_DETAILS))
883 : {
884 104 : fprintf (dump_file, "Optimizing out: ");
885 104 : print_gimple_stmt (dump_file, stmt, 0, dump_flags);
886 : }
887 2090 : unlink_stmt_vdef (stmt);
888 2090 : gsi_remove (&gsi, true);
889 : }
890 : else
891 : {
892 43379 : if (dump_file && (dump_flags & TDF_DETAILS))
893 : {
894 188 : fprintf (dump_file, "Leaving: ");
895 188 : print_gimple_stmt (dump_file, stmt, 0, dump_flags);
896 : }
897 :
898 43379 : gsi_next (&gsi);
899 : }
900 : }
901 :
902 40807 : if (asan_check_optimize)
903 : {
904 31620 : info->has_freeing_call_p = info->freeing_call_events != 0;
905 31620 : info->has_freeing_call_computed_p = true;
906 : }
907 :
908 40807 : for (son = first_dom_son (CDI_DOMINATORS, bb);
909 73917 : son;
910 33110 : son = next_dom_son (CDI_DOMINATORS, son))
911 33110 : sanopt_optimize_walker (son, ctx);
912 :
913 : /* We're leaving this BB, so mark it to that effect. */
914 40807 : info->visited_p = true;
915 40807 : }
916 :
917 : /* Try to remove redundant sanitizer checks in function FUN. */
918 :
919 : static int
920 7697 : sanopt_optimize (function *fun, bool *contains_asan_mark)
921 : {
922 7697 : class sanopt_ctx ctx;
923 7697 : ctx.asan_num_accesses = 0;
924 7697 : ctx.contains_asan_mark = false;
925 :
926 : /* Set up block info for each basic block. */
927 7697 : alloc_aux_for_blocks (sizeof (sanopt_info));
928 :
929 : /* We're going to do a dominator walk, so ensure that we have
930 : dominance information. */
931 7697 : calculate_dominance_info (CDI_DOMINATORS);
932 :
933 : /* Recursively walk the dominator tree optimizing away
934 : redundant checks. */
935 7697 : sanopt_optimize_walker (ENTRY_BLOCK_PTR_FOR_FN (fun), &ctx);
936 :
937 7697 : free_aux_for_blocks ();
938 :
939 7697 : *contains_asan_mark = ctx.contains_asan_mark;
940 15394 : return ctx.asan_num_accesses;
941 7697 : }
942 :
943 : /* Perform optimization of sanitize functions. */
944 :
945 : namespace {
946 :
947 : const pass_data pass_data_sanopt =
948 : {
949 : GIMPLE_PASS, /* type */
950 : "sanopt", /* name */
951 : OPTGROUP_NONE, /* optinfo_flags */
952 : TV_NONE, /* tv_id */
953 : ( PROP_ssa | PROP_cfg | PROP_gimple_leh ), /* properties_required */
954 : 0, /* properties_provided */
955 : 0, /* properties_destroyed */
956 : 0, /* todo_flags_start */
957 : TODO_update_ssa, /* todo_flags_finish */
958 : };
959 :
960 : class pass_sanopt : public gimple_opt_pass
961 : {
962 : public:
963 294536 : pass_sanopt (gcc::context *ctxt)
964 589072 : : gimple_opt_pass (pass_data_sanopt, ctxt)
965 : {}
966 :
967 : /* opt_pass methods: */
968 1516711 : bool gate (function *) final override
969 : {
970 : /* SANITIZE_RETURN is handled in the front-end. When trapping,
971 : SANITIZE_UNREACHABLE is handled by builtin_decl_unreachable. */
972 1516711 : unsigned int mask = SANITIZE_RETURN;
973 1516711 : if (flag_sanitize_trap & SANITIZE_UNREACHABLE)
974 328 : mask |= SANITIZE_UNREACHABLE;
975 1516711 : return flag_sanitize & ~mask;
976 : }
977 : unsigned int execute (function *) final override;
978 :
979 : }; // class pass_sanopt
980 :
981 : /* Sanitize all ASAN_MARK unpoison calls that are not reachable by a BB
982 : that contains an ASAN_MARK poison. All these ASAN_MARK unpoison call
983 : can be removed as all variables are unpoisoned in a function prologue. */
984 :
985 : static void
986 1483 : sanitize_asan_mark_unpoison (void)
987 : {
988 : /* 1) Find all BBs that contain an ASAN_MARK poison call. */
989 1483 : auto_bitmap with_poison;
990 1483 : basic_block bb;
991 :
992 15684 : FOR_EACH_BB_FN (bb, cfun)
993 : {
994 14201 : gimple_stmt_iterator gsi;
995 110908 : for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
996 : {
997 76441 : gimple *stmt = gsi_stmt (gsi);
998 76441 : if (asan_mark_p (stmt, ASAN_MARK_POISON))
999 : {
1000 3227 : bitmap_set_bit (with_poison, bb->index);
1001 3227 : break;
1002 : }
1003 : }
1004 : }
1005 :
1006 1483 : auto_sbitmap poisoned (last_basic_block_for_fn (cfun) + 1);
1007 1483 : bitmap_clear (poisoned);
1008 : /* We now treat with_poison as worklist. */
1009 1483 : bitmap worklist = with_poison;
1010 :
1011 : /* 2) Propagate the information to all reachable blocks. */
1012 14259 : while (!bitmap_empty_p (worklist))
1013 : {
1014 11293 : unsigned i = bitmap_clear_first_set_bit (worklist);
1015 11293 : basic_block bb = BASIC_BLOCK_FOR_FN (cfun, i);
1016 11293 : gcc_assert (bb);
1017 :
1018 11293 : edge e;
1019 11293 : edge_iterator ei;
1020 23399 : FOR_EACH_EDGE (e, ei, bb->succs)
1021 12106 : if (!bitmap_bit_p (poisoned, e->dest->index))
1022 : {
1023 8842 : bitmap_set_bit (poisoned, e->dest->index);
1024 8842 : bitmap_set_bit (worklist, e->dest->index);
1025 : }
1026 : }
1027 :
1028 : /* 3) Iterate all BBs not included in POISONED BBs and remove unpoison
1029 : ASAN_MARK preceding an ASAN_MARK poison (which can still happen). */
1030 15684 : FOR_EACH_BB_FN (bb, cfun)
1031 : {
1032 14201 : if (bitmap_bit_p (poisoned, bb->index))
1033 7387 : continue;
1034 :
1035 6814 : gimple_stmt_iterator gsi;
1036 57333 : for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi);)
1037 : {
1038 45495 : gimple *stmt = gsi_stmt (gsi);
1039 45495 : if (gimple_call_internal_p (stmt, IFN_ASAN_MARK))
1040 : {
1041 4200 : if (asan_mark_p (stmt, ASAN_MARK_POISON))
1042 : break;
1043 : else
1044 : {
1045 2410 : if (dump_file)
1046 2 : fprintf (dump_file, "Removing ASAN_MARK unpoison\n");
1047 2410 : unlink_stmt_vdef (stmt);
1048 2410 : release_defs (stmt);
1049 2410 : gsi_remove (&gsi, true);
1050 2410 : continue;
1051 : }
1052 : }
1053 :
1054 41295 : gsi_next (&gsi);
1055 : }
1056 : }
1057 1483 : }
1058 :
1059 : /* Return true when STMT is either ASAN_CHECK call or a call of a function
1060 : that can contain an ASAN_CHECK. */
1061 :
1062 : static bool
1063 62577 : maybe_contains_asan_check (gimple *stmt)
1064 : {
1065 62577 : if (is_gimple_call (stmt))
1066 : {
1067 14563 : if (gimple_call_internal_p (stmt, IFN_ASAN_MARK))
1068 : return false;
1069 : else
1070 7828 : return !(gimple_call_flags (stmt) & ECF_CONST);
1071 : }
1072 48014 : else if (is_a<gasm *> (stmt))
1073 86 : return true;
1074 :
1075 : return false;
1076 : }
1077 :
1078 : /* Sanitize all ASAN_MARK poison calls that are not followed by an ASAN_CHECK
1079 : call. These calls can be removed. */
1080 :
1081 : static void
1082 1483 : sanitize_asan_mark_poison (void)
1083 : {
1084 : /* 1) Find all BBs that possibly contain an ASAN_CHECK. */
1085 1483 : auto_bitmap with_check;
1086 1483 : basic_block bb;
1087 :
1088 15684 : FOR_EACH_BB_FN (bb, cfun)
1089 : {
1090 14201 : gimple_stmt_iterator gsi;
1091 75823 : for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi_prev (&gsi))
1092 : {
1093 46976 : gimple *stmt = gsi_stmt (gsi);
1094 46976 : if (maybe_contains_asan_check (stmt))
1095 : {
1096 6037 : bitmap_set_bit (with_check, bb->index);
1097 6037 : break;
1098 : }
1099 : }
1100 : }
1101 :
1102 1483 : auto_sbitmap can_reach_check (last_basic_block_for_fn (cfun) + 1);
1103 1483 : bitmap_clear (can_reach_check);
1104 : /* We now treat with_check as worklist. */
1105 1483 : bitmap worklist = with_check;
1106 :
1107 : /* 2) Propagate the information to all definitions blocks. */
1108 19472 : while (!bitmap_empty_p (worklist))
1109 : {
1110 16506 : unsigned i = bitmap_clear_first_set_bit (worklist);
1111 16506 : basic_block bb = BASIC_BLOCK_FOR_FN (cfun, i);
1112 16506 : gcc_assert (bb);
1113 :
1114 16506 : edge e;
1115 16506 : edge_iterator ei;
1116 35842 : FOR_EACH_EDGE (e, ei, bb->preds)
1117 19336 : if (!bitmap_bit_p (can_reach_check, e->src->index))
1118 : {
1119 10575 : bitmap_set_bit (can_reach_check, e->src->index);
1120 10575 : bitmap_set_bit (worklist, e->src->index);
1121 : }
1122 : }
1123 :
1124 : /* 3) Iterate all BBs not included in CAN_REACH_CHECK BBs and remove poison
1125 : ASAN_MARK not followed by a call to function having an ASAN_CHECK. */
1126 15684 : FOR_EACH_BB_FN (bb, cfun)
1127 : {
1128 14201 : if (bitmap_bit_p (can_reach_check, bb->index))
1129 9168 : continue;
1130 :
1131 5033 : gimple_stmt_iterator gsi;
1132 23850 : for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi);)
1133 : {
1134 15601 : gimple *stmt = gsi_stmt (gsi);
1135 15601 : if (maybe_contains_asan_check (stmt))
1136 : break;
1137 13784 : else if (asan_mark_p (stmt, ASAN_MARK_POISON))
1138 : {
1139 2829 : if (dump_file)
1140 2 : fprintf (dump_file, "Removing ASAN_MARK poison\n");
1141 2829 : unlink_stmt_vdef (stmt);
1142 2829 : release_defs (stmt);
1143 2829 : gimple_stmt_iterator gsi2 = gsi;
1144 2829 : gsi_prev (&gsi);
1145 2829 : gsi_remove (&gsi2, true);
1146 2829 : continue;
1147 2829 : }
1148 :
1149 16234 : gsi_prev (&gsi);
1150 : }
1151 : }
1152 1483 : }
1153 :
1154 : /* Rewrite all usages of tree OP which is a PARM_DECL with a VAR_DECL
1155 : that is it's DECL_VALUE_EXPR. */
1156 :
1157 : static tree
1158 6279 : rewrite_usage_of_param (tree *op, int *walk_subtrees, void *)
1159 : {
1160 6279 : if (TREE_CODE (*op) == PARM_DECL && DECL_HAS_VALUE_EXPR_P (*op))
1161 : {
1162 242 : *op = DECL_VALUE_EXPR (*op);
1163 242 : *walk_subtrees = 0;
1164 : }
1165 :
1166 6279 : return NULL;
1167 : }
1168 :
1169 : /* For a given function FUN, rewrite all addressable parameters so that
1170 : a new automatic variable is introduced. Right after function entry
1171 : a parameter is assigned to the variable. */
1172 :
1173 : static void
1174 6317 : sanitize_rewrite_addressable_params (function *fun)
1175 : {
1176 6317 : gimple *g;
1177 6317 : gimple_seq stmts = NULL;
1178 6317 : bool has_any_addressable_param = false;
1179 6317 : auto_vec<tree> clear_value_expr_list;
1180 :
1181 6317 : for (tree arg = DECL_ARGUMENTS (current_function_decl);
1182 12873 : arg; arg = DECL_CHAIN (arg))
1183 : {
1184 6556 : tree type = TREE_TYPE (arg);
1185 6556 : if (TREE_ADDRESSABLE (arg)
1186 133 : && !TREE_ADDRESSABLE (type)
1187 133 : && !TREE_THIS_VOLATILE (arg)
1188 6683 : && TREE_CODE (TYPE_SIZE (type)) == INTEGER_CST)
1189 : {
1190 121 : TREE_ADDRESSABLE (arg) = 0;
1191 121 : DECL_NOT_GIMPLE_REG_P (arg) = 0;
1192 : /* The parameter is no longer addressable. */
1193 121 : has_any_addressable_param = true;
1194 :
1195 : /* Create a new automatic variable. */
1196 121 : tree var = build_decl (DECL_SOURCE_LOCATION (arg),
1197 121 : VAR_DECL, DECL_NAME (arg), type);
1198 121 : TREE_ADDRESSABLE (var) = 1;
1199 121 : DECL_IGNORED_P (var) = 1;
1200 :
1201 121 : gimple_add_tmp_var (var);
1202 :
1203 : /* We skip parameters that have a DECL_VALUE_EXPR. */
1204 121 : if (DECL_HAS_VALUE_EXPR_P (arg))
1205 1 : continue;
1206 :
1207 120 : if (dump_file)
1208 : {
1209 0 : fprintf (dump_file,
1210 : "Rewriting parameter whose address is taken: ");
1211 0 : print_generic_expr (dump_file, arg, dump_flags);
1212 0 : fputc ('\n', dump_file);
1213 : }
1214 :
1215 120 : SET_DECL_PT_UID (var, DECL_PT_UID (arg));
1216 :
1217 : /* Assign value of parameter to newly created variable. */
1218 120 : if ((TREE_CODE (type) == COMPLEX_TYPE
1219 120 : || TREE_CODE (type) == VECTOR_TYPE))
1220 : {
1221 : /* We need to create a SSA name that will be used for the
1222 : assignment. */
1223 20 : tree tmp = get_or_create_ssa_default_def (cfun, arg);
1224 20 : g = gimple_build_assign (var, tmp);
1225 20 : gimple_set_location (g, DECL_SOURCE_LOCATION (arg));
1226 20 : gimple_seq_add_stmt (&stmts, g);
1227 : }
1228 : else
1229 : {
1230 100 : g = gimple_build_assign (var, arg);
1231 100 : gimple_set_location (g, DECL_SOURCE_LOCATION (arg));
1232 100 : gimple_seq_add_stmt (&stmts, g);
1233 : }
1234 :
1235 120 : if (target_for_debug_bind (arg))
1236 : {
1237 38 : g = gimple_build_debug_bind (arg, var, NULL);
1238 38 : gimple_seq_add_stmt (&stmts, g);
1239 38 : clear_value_expr_list.safe_push (arg);
1240 : }
1241 :
1242 120 : DECL_HAS_VALUE_EXPR_P (arg) = 1;
1243 120 : SET_DECL_VALUE_EXPR (arg, var);
1244 : }
1245 : }
1246 :
1247 6317 : if (!has_any_addressable_param)
1248 6223 : return;
1249 :
1250 : /* Replace all usages of PARM_DECLs with the newly
1251 : created variable VAR. */
1252 94 : basic_block bb;
1253 427 : FOR_EACH_BB_FN (bb, fun)
1254 : {
1255 333 : gimple_stmt_iterator gsi;
1256 3046 : for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1257 : {
1258 2380 : gimple *stmt = gsi_stmt (gsi);
1259 2380 : gimple_stmt_iterator it = gsi_for_stmt (stmt);
1260 2380 : walk_gimple_stmt (&it, NULL, rewrite_usage_of_param, NULL);
1261 : }
1262 431 : for (gsi = gsi_start_phis (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1263 : {
1264 98 : gphi *phi = dyn_cast<gphi *> (gsi_stmt (gsi));
1265 312 : for (unsigned i = 0; i < gimple_phi_num_args (phi); ++i)
1266 : {
1267 214 : hash_set<tree> visited_nodes;
1268 214 : walk_tree (gimple_phi_arg_def_ptr (phi, i),
1269 : rewrite_usage_of_param, NULL, &visited_nodes);
1270 214 : }
1271 : }
1272 : }
1273 :
1274 : /* Unset value expr for parameters for which we created debug bind
1275 : expressions. */
1276 208 : for (tree arg : clear_value_expr_list)
1277 : {
1278 38 : DECL_HAS_VALUE_EXPR_P (arg) = 0;
1279 38 : SET_DECL_VALUE_EXPR (arg, NULL_TREE);
1280 : }
1281 :
1282 : /* Insert default assignments at the beginning of a function. */
1283 94 : basic_block entry_bb = ENTRY_BLOCK_PTR_FOR_FN (fun);
1284 94 : entry_bb = split_edge (single_succ_edge (entry_bb));
1285 :
1286 94 : gimple_stmt_iterator gsi = gsi_start_bb (entry_bb);
1287 94 : gsi_insert_seq_before (&gsi, stmts, GSI_NEW_STMT);
1288 6317 : }
1289 :
1290 : unsigned int
1291 19867 : pass_sanopt::execute (function *fun)
1292 : {
1293 : /* n.b. ASAN_MARK is used for both HWASAN and ASAN.
1294 : asan_num_accesses is hence used to count either HWASAN_CHECK or ASAN_CHECK
1295 : stuff. This is fine because you can only have one of these active at a
1296 : time. */
1297 19867 : basic_block bb;
1298 19867 : int asan_num_accesses = 0;
1299 19867 : bool contains_asan_mark = false;
1300 19867 : int ret = 0;
1301 :
1302 : /* Try to remove redundant checks. */
1303 19867 : if (optimize
1304 14358 : && (flag_sanitize
1305 14358 : & (SANITIZE_NULL | SANITIZE_ALIGNMENT | SANITIZE_HWADDRESS
1306 : | SANITIZE_ADDRESS | SANITIZE_VPTR | SANITIZE_POINTER_OVERFLOW)))
1307 7697 : asan_num_accesses = sanopt_optimize (fun, &contains_asan_mark);
1308 12170 : else if (flag_sanitize & (SANITIZE_ADDRESS | SANITIZE_HWADDRESS))
1309 : {
1310 1429 : gimple_stmt_iterator gsi;
1311 7179 : FOR_EACH_BB_FN (bb, fun)
1312 36756 : for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); gsi_next (&gsi))
1313 : {
1314 25256 : gimple *stmt = gsi_stmt (gsi);
1315 25256 : if (gimple_call_internal_p (stmt, IFN_ASAN_CHECK))
1316 2839 : ++asan_num_accesses;
1317 22417 : else if (gimple_call_internal_p (stmt, IFN_ASAN_MARK))
1318 776 : contains_asan_mark = true;
1319 : }
1320 : }
1321 :
1322 17043 : if (asan_num_accesses || contains_asan_mark || asan_sanitize_stack_p ()
1323 22839 : || hwasan_sanitize_stack_p ())
1324 6408 : asan_maybe_insert_dynamic_shadow_at_function_entry (fun);
1325 :
1326 19867 : if (contains_asan_mark)
1327 : {
1328 1483 : sanitize_asan_mark_unpoison ();
1329 1483 : sanitize_asan_mark_poison ();
1330 : }
1331 :
1332 19867 : if (asan_sanitize_stack_p () || hwassist_sanitize_stack_p ())
1333 6317 : sanitize_rewrite_addressable_params (fun);
1334 :
1335 39734 : bool use_calls = param_asan_instrumentation_with_call_threshold < INT_MAX
1336 19867 : && asan_num_accesses >= param_asan_instrumentation_with_call_threshold;
1337 :
1338 19867 : hash_map<tree, tree> shadow_vars_mapping;
1339 19867 : bool need_commit_edge_insert = false;
1340 208897 : FOR_EACH_BB_FN (bb, fun)
1341 : {
1342 189030 : gimple_stmt_iterator gsi;
1343 1135139 : for (gsi = gsi_start_bb (bb); !gsi_end_p (gsi); )
1344 : {
1345 757079 : gimple *stmt = gsi_stmt (gsi);
1346 757079 : bool no_next = false;
1347 :
1348 757079 : if (!is_gimple_call (stmt))
1349 : {
1350 603814 : gsi_next (&gsi);
1351 603814 : continue;
1352 : }
1353 :
1354 153265 : if (gimple_call_internal_p (stmt))
1355 : {
1356 36603 : enum internal_fn ifn = gimple_call_internal_fn (stmt);
1357 36603 : int this_ret = TODO_cleanup_cfg;
1358 36603 : switch (ifn)
1359 : {
1360 2943 : case IFN_UBSAN_NULL:
1361 2943 : no_next = ubsan_expand_null_ifn (&gsi);
1362 2943 : break;
1363 1639 : case IFN_UBSAN_BOUNDS:
1364 1639 : no_next = ubsan_expand_bounds_ifn (&gsi);
1365 1639 : break;
1366 368 : case IFN_UBSAN_OBJECT_SIZE:
1367 368 : no_next = ubsan_expand_objsize_ifn (&gsi);
1368 368 : break;
1369 1561 : case IFN_UBSAN_PTR:
1370 1561 : no_next = ubsan_expand_ptr_ifn (&gsi);
1371 1561 : break;
1372 498 : case IFN_UBSAN_VPTR:
1373 498 : no_next = ubsan_expand_vptr_ifn (&gsi);
1374 498 : break;
1375 384 : case IFN_HWASAN_CHECK:
1376 384 : no_next = hwasan_expand_check_ifn (&gsi, use_calls);
1377 384 : break;
1378 18929 : case IFN_ASAN_CHECK:
1379 18929 : no_next = asan_expand_check_ifn (&gsi, use_calls);
1380 18929 : break;
1381 2149 : case IFN_ASAN_MARK:
1382 2149 : no_next = asan_expand_mark_ifn (&gsi);
1383 2149 : break;
1384 36 : case IFN_ASAN_POISON:
1385 36 : no_next = asan_expand_poison_ifn (&gsi,
1386 : &need_commit_edge_insert,
1387 : shadow_vars_mapping);
1388 36 : break;
1389 0 : case IFN_HWASAN_MARK:
1390 0 : no_next = hwasan_expand_mark_ifn (&gsi);
1391 0 : break;
1392 : default:
1393 : this_ret = 0;
1394 : break;
1395 : }
1396 36603 : ret |= this_ret;
1397 : }
1398 116662 : else if (gimple_call_builtin_p (stmt, BUILT_IN_NORMAL))
1399 : {
1400 36731 : tree callee = gimple_call_fndecl (stmt);
1401 36731 : switch (DECL_FUNCTION_CODE (callee))
1402 : {
1403 25 : case BUILT_IN_UNREACHABLE:
1404 25 : if (sanitize_flags_p (SANITIZE_UNREACHABLE))
1405 0 : no_next = ubsan_instrument_unreachable (&gsi);
1406 : break;
1407 : default:
1408 : break;
1409 : }
1410 : }
1411 :
1412 153265 : if (dump_file && (dump_flags & TDF_DETAILS))
1413 : {
1414 331 : fprintf (dump_file, "Expanded: ");
1415 331 : print_gimple_stmt (dump_file, stmt, 0, dump_flags);
1416 : }
1417 :
1418 153265 : if (!no_next)
1419 131878 : gsi_next (&gsi);
1420 : }
1421 : }
1422 :
1423 19867 : if (need_commit_edge_insert)
1424 0 : gsi_commit_edge_inserts ();
1425 :
1426 19867 : return ret;
1427 19867 : }
1428 :
1429 : } // anon namespace
1430 :
1431 : gimple_opt_pass *
1432 294536 : make_pass_sanopt (gcc::context *ctxt)
1433 : {
1434 294536 : return new pass_sanopt (ctxt);
1435 : }
|