Line data Source code
1 : /* Detect paths through the CFG which can never be executed in a conforming
2 : program and isolate them.
3 :
4 : Copyright (C) 2013-2026 Free Software Foundation, Inc.
5 :
6 : This file is part of GCC.
7 :
8 : GCC is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3, or (at your option)
11 : any later version.
12 :
13 : GCC is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
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/>. */
21 :
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 "cfghooks.h"
29 : #include "tree-pass.h"
30 : #include "ssa.h"
31 : #include "diagnostic-core.h"
32 : #include "fold-const.h"
33 : #include "gimple-iterator.h"
34 : #include "gimple-walk.h"
35 : #include "tree-ssa.h"
36 : #include "cfgloop.h"
37 : #include "tree-cfg.h"
38 : #include "cfganal.h"
39 : #include "intl.h"
40 :
41 :
42 : static bool cfg_altered;
43 :
44 : /* Callback for walk_stmt_load_store_ops.
45 :
46 : Return TRUE if OP will dereference the tree stored in DATA, FALSE
47 : otherwise.
48 :
49 : This routine only makes a superficial check for a dereference. Thus,
50 : it must only be used if it is safe to return a false negative. */
51 : static bool
52 3101 : check_loadstore (gimple *stmt, tree op, tree, void *data)
53 : {
54 6202 : if ((TREE_CODE (op) == MEM_REF
55 47 : || (TREE_CODE (op) == TARGET_MEM_REF
56 0 : && !TMR_INDEX2 (op)
57 0 : && (!TMR_INDEX (op)
58 0 : || (TMR_STEP (op)
59 0 : && expr_not_equal_to (TMR_STEP (op),
60 3101 : wi::one (TYPE_PRECISION (TREE_TYPE
61 : (TMR_STEP (op)))),
62 : stmt)))))
63 3101 : && operand_equal_p (TREE_OPERAND (op, 0), (tree)data, 0))
64 : {
65 2989 : TREE_THIS_VOLATILE (op) = 1;
66 2989 : TREE_SIDE_EFFECTS (op) = 1;
67 2989 : gimple_set_has_volatile_ops (stmt, true);
68 : return true;
69 : }
70 : return false;
71 : }
72 :
73 : static vec<gimple *> *bb_split_points;
74 :
75 : /* Insert a trap after SI and split the block after the trap. */
76 :
77 : static void
78 2493 : insert_trap (gimple_stmt_iterator *si_p, tree op)
79 : {
80 : /* We want the NULL pointer dereference to actually occur so that
81 : code that wishes to catch the signal can do so.
82 :
83 : If the dereference is a load, then there's nothing to do as the
84 : LHS will be a throw-away SSA_NAME and the RHS is the NULL dereference.
85 :
86 : If the dereference is a store and we can easily transform the RHS,
87 : then simplify the RHS to enable more DCE. Note that we require the
88 : statement to be a GIMPLE_ASSIGN which filters out calls on the RHS. */
89 2493 : gimple *stmt = gsi_stmt (*si_p);
90 2493 : if (walk_stmt_load_store_ops (stmt, (void *)op, NULL, check_loadstore)
91 802 : && is_gimple_assign (stmt)
92 3292 : && INTEGRAL_TYPE_P (TREE_TYPE (gimple_assign_lhs (stmt))))
93 : {
94 : /* We just need to turn the RHS into zero converted to the proper
95 : type. */
96 515 : tree type = TREE_TYPE (gimple_assign_lhs (stmt));
97 515 : gimple_assign_set_rhs_code (stmt, INTEGER_CST);
98 515 : gimple_assign_set_rhs1 (stmt, fold_convert (type, integer_zero_node));
99 515 : update_stmt (stmt);
100 : }
101 :
102 2493 : gcall *new_stmt
103 2493 : = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
104 2493 : gimple_seq seq = NULL;
105 2493 : gimple_seq_add_stmt (&seq, new_stmt);
106 :
107 : /* If we had a NULL pointer dereference, then we want to insert the
108 : __builtin_trap after the statement, for the other cases we want
109 : to insert before the statement. */
110 2493 : if (walk_stmt_load_store_ops (stmt, (void *)op,
111 : check_loadstore,
112 : check_loadstore))
113 : {
114 2187 : gsi_insert_after (si_p, seq, GSI_NEW_STMT);
115 2187 : if (stmt_ends_bb_p (stmt))
116 : {
117 1 : if (dom_info_available_p (CDI_POST_DOMINATORS))
118 0 : bb_split_points->safe_push (stmt);
119 : else
120 1 : split_block (gimple_bb (stmt), stmt);
121 1 : return;
122 : }
123 : }
124 : else
125 306 : gsi_insert_before (si_p, seq, GSI_NEW_STMT);
126 :
127 2492 : if (dom_info_available_p (CDI_POST_DOMINATORS))
128 1 : bb_split_points->safe_push (new_stmt);
129 : else
130 2491 : split_block (gimple_bb (new_stmt), new_stmt);
131 2492 : *si_p = gsi_for_stmt (stmt);
132 : }
133 :
134 : /* BB when reached via incoming edge E will exhibit undefined behavior
135 : at STMT. Isolate and optimize the path which exhibits undefined
136 : behavior.
137 :
138 : Isolation is simple. Duplicate BB and redirect E to BB'.
139 :
140 : Optimization is simple as well. Replace STMT in BB' with an
141 : unconditional trap and remove all outgoing edges from BB'.
142 :
143 : If RET_ZERO, do not trap, only return NULL.
144 :
145 : DUPLICATE is a pre-existing duplicate, use it as BB' if it exists.
146 :
147 : Return BB' (which may be equal to DUPLICATE). */
148 :
149 : ATTRIBUTE_RETURNS_NONNULL basic_block
150 1483 : isolate_path (basic_block bb, basic_block duplicate,
151 : edge e, gimple *stmt, tree op, bool ret_zero)
152 : {
153 1483 : gimple_stmt_iterator si, si2;
154 1483 : edge_iterator ei;
155 1483 : edge e2;
156 1483 : bool impossible = true;
157 1483 : profile_count count = e->count ();
158 :
159 22824 : for (si = gsi_start_bb (bb); gsi_stmt (si) != stmt; gsi_next (&si))
160 20077 : if (stmt_can_terminate_bb_p (gsi_stmt (si)))
161 : {
162 : impossible = false;
163 : break;
164 : }
165 1483 : force_edge_cold (e, impossible);
166 :
167 : /* First duplicate BB if we have not done so already and remove all
168 : the duplicate's outgoing edges as duplicate is going to unconditionally
169 : trap. Removing the outgoing edges is both an optimization and ensures
170 : we don't need to do any PHI node updates. */
171 1483 : if (!duplicate)
172 : {
173 899 : duplicate = duplicate_block (bb, NULL, NULL);
174 899 : duplicate->count = profile_count::zero ();
175 899 : if (!ret_zero)
176 2166 : for (ei = ei_start (duplicate->succs); (e2 = ei_safe_edge (ei)); )
177 1331 : remove_edge (e2);
178 : }
179 1483 : bb->count -= count;
180 :
181 : /* Complete the isolation step by redirecting E to reach DUPLICATE. */
182 1483 : e2 = redirect_edge_and_branch (e, duplicate);
183 1483 : if (e2)
184 : {
185 1045 : flush_pending_stmts (e2);
186 :
187 : /* Update profile only when redirection is really processed. */
188 1045 : bb->count += e->count ();
189 : }
190 :
191 : /* There may be more than one statement in DUPLICATE which exhibits
192 : undefined behavior. Ultimately we want the first such statement in
193 : DUPLCIATE so that we're able to delete as much code as possible.
194 :
195 : So each time we discover undefined behavior in DUPLICATE, search for
196 : the statement which triggers undefined behavior. If found, then
197 : transform the statement into a trap and delete everything after the
198 : statement. If not found, then this particular instance was subsumed by
199 : an earlier instance of undefined behavior and there's nothing to do.
200 :
201 : This is made more complicated by the fact that we have STMT, which is in
202 : BB rather than in DUPLICATE. So we set up two iterators, one for each
203 : block and walk forward looking for STMT in BB, advancing each iterator at
204 : each step.
205 :
206 : When we find STMT the second iterator should point to STMT's equivalent in
207 : duplicate. If DUPLICATE ends before STMT is found in BB, then there's
208 : nothing to do.
209 :
210 : Ignore labels and debug statements. */
211 1483 : si = gsi_start_nondebug_after_labels_bb (bb);
212 1483 : si2 = gsi_start_nondebug_after_labels_bb (duplicate);
213 7626 : while (!gsi_end_p (si) && !gsi_end_p (si2) && gsi_stmt (si) != stmt)
214 : {
215 6143 : gsi_next_nondebug (&si);
216 6143 : gsi_next_nondebug (&si2);
217 : }
218 :
219 : /* This would be an indicator that we never found STMT in BB, which should
220 : never happen. */
221 1483 : gcc_assert (!gsi_end_p (si));
222 :
223 : /* If we did not run to the end of DUPLICATE, then SI points to STMT and
224 : SI2 points to the duplicate of STMT in DUPLICATE. Insert a trap
225 : before SI2 and remove SI2 and all trailing statements. */
226 1483 : if (!gsi_end_p (si2))
227 : {
228 1401 : if (ret_zero)
229 : {
230 109 : greturn *ret = as_a <greturn *> (gsi_stmt (si2));
231 109 : tree zero = build_zero_cst (TREE_TYPE (gimple_return_retval (ret)));
232 109 : gimple_return_set_retval (ret, zero);
233 109 : update_stmt (ret);
234 : }
235 : else
236 1292 : insert_trap (&si2, op);
237 : }
238 :
239 1483 : return duplicate;
240 : }
241 :
242 : /* Return TRUE if STMT is a div/mod operation using DIVISOR as the divisor.
243 : FALSE otherwise. */
244 :
245 : static bool
246 68515611 : is_divmod_with_given_divisor (gimple *stmt, tree divisor)
247 : {
248 : /* Only assignments matter. */
249 68515611 : if (!is_gimple_assign (stmt))
250 : return false;
251 :
252 : /* Check for every DIV/MOD expression. */
253 15192705 : enum tree_code rhs_code = gimple_assign_rhs_code (stmt);
254 15192705 : if (rhs_code == TRUNC_DIV_EXPR
255 15192705 : || rhs_code == FLOOR_DIV_EXPR
256 15142948 : || rhs_code == CEIL_DIV_EXPR
257 15142948 : || rhs_code == EXACT_DIV_EXPR
258 : || rhs_code == ROUND_DIV_EXPR
259 15091188 : || rhs_code == TRUNC_MOD_EXPR
260 : || rhs_code == FLOOR_MOD_EXPR
261 15046458 : || rhs_code == CEIL_MOD_EXPR
262 15046015 : || rhs_code == ROUND_MOD_EXPR)
263 : {
264 : /* Pointer equality is fine when DIVISOR is an SSA_NAME, but
265 : not sufficient for constants which may have different types. */
266 146708 : if (operand_equal_p (gimple_assign_rhs2 (stmt), divisor, 0))
267 : return true;
268 : }
269 : return false;
270 : }
271 :
272 : /* NAME is an SSA_NAME that we have already determined has the value 0 or NULL.
273 :
274 : Return TRUE if USE_STMT uses NAME in a way where a 0 or NULL value results
275 : in undefined behavior, FALSE otherwise
276 :
277 : LOC is used for issuing diagnostics. This case represents potential
278 : undefined behavior exposed by path splitting and that's reflected in
279 : the diagnostic. */
280 :
281 : bool
282 747573 : stmt_uses_name_in_undefined_way (gimple *use_stmt, tree name, location_t loc)
283 : {
284 : /* If we are working with a non pointer type, then see
285 : if this use is a DIV/MOD operation using NAME as the
286 : divisor. */
287 747573 : if (!POINTER_TYPE_P (TREE_TYPE (name)))
288 : {
289 629144 : if (!cfun->can_throw_non_call_exceptions)
290 419718 : return is_divmod_with_given_divisor (use_stmt, name);
291 : return false;
292 : }
293 :
294 : /* NAME is a pointer, so see if it's used in a context where it must
295 : be non-NULL. */
296 118429 : bool by_dereference
297 118429 : = infer_nonnull_range_by_dereference (use_stmt, name);
298 :
299 118429 : if (by_dereference
300 118429 : || infer_nonnull_range_by_attribute (use_stmt, name))
301 : {
302 :
303 1510 : if (by_dereference)
304 : {
305 1335 : warning_at (loc, OPT_Wnull_dereference,
306 : "potential null pointer dereference");
307 1335 : if (!flag_isolate_erroneous_paths_dereference)
308 : return false;
309 : }
310 : else
311 : {
312 175 : if (!flag_isolate_erroneous_paths_attribute)
313 : return false;
314 : }
315 1337 : return true;
316 : }
317 : return false;
318 : }
319 :
320 : /* Return TRUE if USE_STMT uses 0 or NULL in a context which results in
321 : undefined behavior, FALSE otherwise.
322 :
323 : These cases are explicit in the IL. */
324 :
325 : bool
326 79070461 : stmt_uses_0_or_null_in_undefined_way (gimple *stmt)
327 : {
328 79070461 : if (!cfun->can_throw_non_call_exceptions
329 79070461 : && is_divmod_with_given_divisor (stmt, integer_zero_node))
330 : return true;
331 :
332 : /* By passing null_pointer_node, we can use the
333 : infer_nonnull_range functions to detect explicit NULL
334 : pointer dereferences and other uses where a non-NULL
335 : value is required. */
336 :
337 79070207 : bool by_dereference
338 79070207 : = infer_nonnull_range_by_dereference (stmt, null_pointer_node);
339 79070207 : if (by_dereference
340 79070207 : || infer_nonnull_range_by_attribute (stmt, null_pointer_node))
341 : {
342 1263 : if (by_dereference)
343 : {
344 946 : location_t loc = gimple_location (stmt);
345 946 : warning_at (loc, OPT_Wnull_dereference,
346 : "null pointer dereference");
347 946 : if (!flag_isolate_erroneous_paths_dereference)
348 : return false;
349 : }
350 : else
351 : {
352 317 : if (!flag_isolate_erroneous_paths_attribute)
353 : return false;
354 : }
355 947 : return true;
356 : }
357 : return false;
358 : }
359 :
360 : /* Describes the property of a return statement that may return
361 : the address of one or more local variables. The type must
362 : be safely assignable and copyable so that it can be stored in
363 : a hash_map. */
364 : class args_loc_t
365 : {
366 : public:
367 :
368 47374 : args_loc_t (): nargs (), locvec (), ptr (&ptr)
369 : {
370 47374 : locvec.create (4);
371 47374 : }
372 :
373 0 : args_loc_t (const args_loc_t &rhs)
374 0 : : nargs (rhs.nargs), locvec (rhs.locvec.copy ()), ptr (&ptr) { }
375 :
376 : args_loc_t& operator= (const args_loc_t &rhs)
377 : {
378 : nargs = rhs.nargs;
379 : locvec.release ();
380 : locvec = rhs.locvec.copy ();
381 : return *this;
382 : }
383 :
384 47374 : ~args_loc_t ()
385 : {
386 47374 : locvec.release ();
387 47374 : gcc_assert (ptr == &ptr);
388 47374 : }
389 :
390 : /* For a PHI in a return statement its number of arguments. When greater
391 : than LOCVEC.LENGTH () implies that an address of one of the locals in
392 : LOCVEC may but need not be returned by the statement. Otherwise,
393 : unless both are zero, it implies it definitely is returned. */
394 : unsigned nargs;
395 : /* The locations of local variables/alloca calls returned by the return
396 : statement. Avoid using auto_vec here since it's not safe to copy due
397 : to pr90904. */
398 : vec <location_t> locvec;
399 : void *ptr;
400 : };
401 :
402 : /* A mapping from a return statement to the locations of local variables
403 : whose addresses it may return. */
404 : typedef hash_map <gimple *, args_loc_t> locmap_t;
405 :
406 : /* Given the LOCMAP mapping, issue diagnostics about returning addresses
407 : of local variables. When MAYBE is set, all diagnostics will be of
408 : the "may return" kind. Otherwise each will be determined based on
409 : the equality of the corresponding NARGS and LOCVEC.LENGTH () values. */
410 :
411 : static void
412 981719 : diag_returned_locals (bool maybe, const locmap_t &locmap)
413 : {
414 982038 : for (locmap_t::iterator it = locmap.begin (); it != locmap.end (); ++it)
415 : {
416 319 : gimple *stmt = (*it).first;
417 319 : const args_loc_t &argsloc = (*it).second;
418 319 : location_t stmtloc = gimple_location (stmt);
419 319 : if (stmtloc == UNKNOWN_LOCATION)
420 : /* When multiple return statements are merged into one it
421 : may not have an associated location. Use the location
422 : of the closing brace instead. */
423 18 : stmtloc = cfun->function_end_locus;
424 :
425 319 : auto_diagnostic_group d;
426 319 : unsigned nargs = argsloc.locvec.length ();
427 638 : if (warning_at (stmtloc, OPT_Wreturn_local_addr,
428 151 : (maybe || argsloc.nargs > nargs
429 : ? G_("function may return address of local variable")
430 : : G_("function returns address of local variable"))))
431 : {
432 578 : for (unsigned i = 0; i != nargs; ++i)
433 322 : inform (argsloc.locvec[i], "declared here");
434 : }
435 319 : }
436 981719 : }
437 :
438 : /* Return true if EXPR is an expression of pointer type that refers
439 : to the address of one or more variables with automatic storage
440 : duration. If so, add an entry to *PLOCMAP and insert into
441 : PLOCMAP->LOCVEC the locations of the corresponding local variables
442 : whose address is returned by the RETURN_STMT (which may be set to
443 : (gimple*)-1 as a placeholder for such a statement). VISITED is
444 : a bitmap of PHI nodes already visited by recursive calls. When
445 : null, PHI expressions are not considered. */
446 :
447 : static bool
448 8706214 : is_addr_local (gimple *return_stmt, tree exp, locmap_t *plocmap,
449 : hash_set<gphi *> *visited)
450 : {
451 8706214 : if (TREE_CODE (exp) == ADDR_EXPR)
452 : {
453 109287 : tree baseaddr = get_base_address (TREE_OPERAND (exp, 0));
454 109287 : if (TREE_CODE (baseaddr) == MEM_REF)
455 24742 : return is_addr_local (return_stmt, TREE_OPERAND (baseaddr, 0),
456 24742 : plocmap, visited);
457 :
458 84545 : if ((!VAR_P (baseaddr)
459 60899 : || is_global_var (baseaddr))
460 110667 : && TREE_CODE (baseaddr) != PARM_DECL)
461 : return false;
462 :
463 34975 : args_loc_t &argsloc = plocmap->get_or_insert (return_stmt);
464 34975 : argsloc.locvec.safe_push (DECL_SOURCE_LOCATION (baseaddr));
465 34975 : return true;
466 : }
467 :
468 8596927 : if (!POINTER_TYPE_P (TREE_TYPE (exp)))
469 : return false;
470 :
471 1535394 : if (TREE_CODE (exp) == SSA_NAME)
472 : {
473 1430023 : gimple *def_stmt = SSA_NAME_DEF_STMT (exp);
474 1430023 : enum gimple_code code = gimple_code (def_stmt);
475 :
476 1430023 : if (is_gimple_assign (def_stmt))
477 : {
478 705147 : tree type = TREE_TYPE (gimple_assign_lhs (def_stmt));
479 705147 : if (POINTER_TYPE_P (type))
480 : {
481 705147 : tree_code code = gimple_assign_rhs_code (def_stmt);
482 705147 : tree ptr1 = NULL_TREE, ptr2 = NULL_TREE;
483 :
484 : /* Set to the number of arguments examined that should
485 : be added to ARGSLOC->NARGS to identify expressions
486 : only some but not all of whose operands refer to local
487 : addresses. */
488 705147 : unsigned nargs = 0;
489 705147 : if (code == COND_EXPR)
490 : {
491 0 : ptr1 = gimple_assign_rhs2 (def_stmt);
492 0 : ptr2 = gimple_assign_rhs3 (def_stmt);
493 0 : nargs = 2;
494 : }
495 : else if (code == MAX_EXPR || code == MIN_EXPR)
496 : {
497 258 : ptr1 = gimple_assign_rhs1 (def_stmt);
498 258 : ptr2 = gimple_assign_rhs2 (def_stmt);
499 258 : nargs = 2;
500 : }
501 : else if (code == ADDR_EXPR
502 : || code == NOP_EXPR
503 : || code == POINTER_PLUS_EXPR)
504 : /* Leave NARGS at zero and let the recursive call set it. */
505 273749 : ptr1 = gimple_assign_rhs1 (def_stmt);
506 :
507 : /* Avoid short-circuiting the logical OR result in case
508 : both operands refer to local variables, in which case
509 : both should be considered and identified in the warning. */
510 979154 : bool res1 = false, res2 = false;
511 274007 : if (ptr1)
512 274007 : res1 = is_addr_local (return_stmt, ptr1, plocmap, visited);
513 705147 : if (ptr2)
514 258 : res2 = is_addr_local (return_stmt, ptr2, plocmap, visited);
515 :
516 705147 : if (nargs)
517 258 : if (args_loc_t *argsloc = plocmap->get (return_stmt))
518 90 : argsloc->nargs += nargs;
519 :
520 705147 : return res1 || res2;
521 : }
522 : return false;
523 : }
524 :
525 724876 : if (code == GIMPLE_CALL
526 724876 : && gimple_call_builtin_p (def_stmt, BUILT_IN_NORMAL))
527 : {
528 : /* Handle alloca and friends that return pointers to automatic
529 : storage. */
530 16529 : tree fn = gimple_call_fndecl (def_stmt);
531 16529 : int code = DECL_FUNCTION_CODE (fn);
532 16529 : if (code == BUILT_IN_ALLOCA
533 16529 : || code == BUILT_IN_ALLOCA_WITH_ALIGN
534 14342 : || code == BUILT_IN_ALLOCA_WITH_ALIGN_AND_MAX)
535 : {
536 2187 : args_loc_t &argsloc = plocmap->get_or_insert (return_stmt);
537 2187 : argsloc.locvec.safe_push (gimple_location (def_stmt));
538 2187 : return true;
539 : }
540 :
541 14342 : if (gimple_call_num_args (def_stmt) < 1)
542 : return false;
543 :
544 : /* Recursively examine the first argument of calls to built-ins
545 : that return it. */
546 13491 : switch (code)
547 : {
548 1462 : case BUILT_IN_MEMCPY:
549 1462 : case BUILT_IN_MEMCPY_CHK:
550 1462 : case BUILT_IN_MEMPCPY:
551 1462 : case BUILT_IN_MEMPCPY_CHK:
552 1462 : case BUILT_IN_MEMMOVE:
553 1462 : case BUILT_IN_MEMMOVE_CHK:
554 1462 : case BUILT_IN_STPCPY:
555 1462 : case BUILT_IN_STPCPY_CHK:
556 1462 : case BUILT_IN_STPNCPY:
557 1462 : case BUILT_IN_STPNCPY_CHK:
558 1462 : case BUILT_IN_STRCAT:
559 1462 : case BUILT_IN_STRCAT_CHK:
560 1462 : case BUILT_IN_STRCHR:
561 1462 : case BUILT_IN_STRCPY:
562 1462 : case BUILT_IN_STRCPY_CHK:
563 1462 : case BUILT_IN_STRNCAT:
564 1462 : case BUILT_IN_STRNCAT_CHK:
565 1462 : case BUILT_IN_STRNCPY:
566 1462 : case BUILT_IN_STRNCPY_CHK:
567 1462 : case BUILT_IN_STRRCHR:
568 1462 : case BUILT_IN_STRSTR:
569 1462 : return is_addr_local (return_stmt,
570 : gimple_call_arg (def_stmt, 0),
571 1462 : plocmap, visited);
572 : default:
573 : return false;
574 : }
575 : }
576 :
577 708347 : if (code == GIMPLE_PHI && visited)
578 : {
579 32385 : gphi *phi_stmt = as_a <gphi *> (def_stmt);
580 32385 : if (visited->add (phi_stmt))
581 : return false;
582 :
583 21695 : unsigned count = 0;
584 21695 : unsigned nargs = gimple_phi_num_args (phi_stmt);
585 21695 : args_loc_t &argsloc = plocmap->get_or_insert (return_stmt);
586 : /* Bump up the number of operands examined by the number of
587 : operands of this PHI. */
588 21695 : argsloc.nargs += nargs;
589 86950 : for (unsigned i = 0; i < gimple_phi_num_args (phi_stmt); ++i)
590 : {
591 65255 : tree arg = gimple_phi_arg_def (phi_stmt, i);
592 65255 : if (is_addr_local (return_stmt, arg, plocmap, visited))
593 52 : ++count;
594 : }
595 21695 : return count != 0;
596 : }
597 : }
598 :
599 : return false;
600 : }
601 :
602 : /* Detect returning the address of a local variable in a PHI result LHS
603 : and argument ARG and PHI edge E in basic block BB. Add an entry for
604 : each use to LOCMAP, setting its NARGS member to the NARGS argument
605 : (the number of PHI operands) plus the number of arguments in binary
606 : expressions referenced by ARG. Call isolate_path for each returned
607 : address and set *ISOLATED to true if called.
608 : Return either DUPLICATE or the most recent result of isolate_path. */
609 :
610 : static basic_block
611 7793382 : handle_return_addr_local_phi_arg (basic_block bb, basic_block duplicate,
612 : tree lhs, tree arg, edge e, locmap_t &locmap,
613 : unsigned nargs, bool *isolated)
614 : {
615 : /* Use (gimple*)-1 as a temporary placeholder and replace it with
616 : the return statement below once it is known. Using a null doesn't
617 : work because it's used by the hash_map to mean "no-entry." Pass
618 : null instead of a visited_phis bitmap to avoid descending into
619 : PHIs since they are being processed by the caller. Those that
620 : remain will be checked again later. */
621 7793382 : if (!is_addr_local ((gimple*)-1, arg, &locmap, NULL))
622 : {
623 : /* Remove the placeholder regardless of success or failure. */
624 7756519 : locmap.remove ((gimple*)-1);
625 7756519 : return duplicate;
626 : }
627 :
628 36863 : const args_loc_t* const placeargsloc = locmap.get ((gimple*)-1);
629 36863 : const unsigned nlocs = placeargsloc->locvec.length ();
630 36863 : gcc_assert (nlocs);
631 :
632 : /* Add to the number of PHI arguments determined by the caller
633 : the number of operands of the expressions referenced by ARG.
634 : This lets the caller determine whether it's dealing with
635 : a "may return" or "definitely returns." */
636 36863 : nargs += placeargsloc->nargs;
637 :
638 : /* Set to true if any expressions referenced by ARG involve
639 : multiple addresses only some of which are those of locals. */
640 36863 : bool maybe = placeargsloc->nargs > placeargsloc->locvec.length ();
641 :
642 36863 : gimple *use_stmt;
643 36863 : imm_use_iterator iter;
644 :
645 : /* Look for uses of the PHI result LHS in return statements. */
646 178798 : FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
647 : {
648 141935 : greturn *return_stmt = dyn_cast <greturn *> (use_stmt);
649 141935 : if (!return_stmt)
650 141805 : continue;
651 :
652 130 : if (gimple_return_retval (return_stmt) != lhs
653 130 : || !dominated_by_p (CDI_DOMINATORS, gimple_bb (use_stmt), bb))
654 6 : continue;
655 :
656 : /* Add an entry for the return statement and the locations
657 : oof the PHI arguments obtained above to the map. */
658 124 : args_loc_t &argsloc = locmap.get_or_insert (use_stmt);
659 124 : argsloc.nargs = nargs;
660 124 : unsigned nelts = argsloc.locvec.length () + nlocs;
661 124 : argsloc.locvec.reserve (nelts);
662 124 : argsloc.locvec.splice (placeargsloc->locvec);
663 :
664 124 : if (!maybe
665 109 : && (flag_isolate_erroneous_paths_dereference
666 0 : || flag_isolate_erroneous_paths_attribute)
667 109 : && gimple_bb (use_stmt) == bb
668 233 : && (duplicate || can_duplicate_block_p (bb)))
669 : {
670 109 : duplicate = isolate_path (bb, duplicate, e,
671 : use_stmt, lhs, true);
672 :
673 : /* Let caller know the path has been isolated. */
674 109 : *isolated = true;
675 : }
676 36863 : }
677 :
678 36863 : locmap.remove ((gimple*)-1);
679 :
680 36863 : return duplicate;
681 : }
682 :
683 : /* Look for PHI nodes which feed statements in the same block where
684 : the value of the PHI node implies the statement is erroneous.
685 :
686 : For example, a NULL PHI arg value which then feeds a pointer
687 : dereference.
688 :
689 : When found isolate and optimize the path associated with the PHI
690 : argument feeding the erroneous statement. */
691 : static void
692 981472 : find_implicit_erroneous_behavior (void)
693 : {
694 981472 : locmap_t locmap;
695 :
696 981472 : basic_block bb;
697 :
698 10212263 : FOR_EACH_BB_FN (bb, cfun)
699 : {
700 9230791 : gphi_iterator si;
701 :
702 : /* Out of an abundance of caution, do not isolate paths to a
703 : block where the block has any abnormal outgoing edges.
704 :
705 : We might be able to relax this in the future. We have to detect
706 : when we have to split the block with the NULL dereference and
707 : the trap we insert. We have to preserve abnormal edges out
708 : of the isolated block which in turn means updating PHIs at
709 : the targets of those abnormal outgoing edges. */
710 9230791 : if (has_abnormal_or_eh_outgoing_edge_p (bb))
711 987639 : continue;
712 :
713 :
714 : /* If BB has an edge to itself, then duplication of BB below
715 : could result in reallocation of BB's PHI nodes. If that happens
716 : then the loop below over the PHIs would use the old PHI and
717 : thus invalid information. We don't have a good way to know
718 : if a PHI has been reallocated, so just avoid isolation in
719 : this case. */
720 8496181 : if (find_edge (bb, bb))
721 253029 : continue;
722 :
723 : /* First look for a PHI which sets a pointer to NULL and which
724 : is then dereferenced within BB. This is somewhat overly
725 : conservative, but probably catches most of the interesting
726 : cases. */
727 8243152 : basic_block duplicate = NULL;
728 11354589 : for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
729 : {
730 3111437 : gphi *phi = si.phi ();
731 3111437 : tree lhs = gimple_phi_result (phi);
732 :
733 : /* PHI produces a pointer result. See if any of the PHI's
734 : arguments are NULL.
735 :
736 : When we remove an edge, we want to reprocess the current
737 : index since the argument at that index will have been
738 : removed, hence the ugly way we update I for each iteration. */
739 3111437 : for (unsigned i = 0, next_i = 0;
740 10905932 : i < gimple_phi_num_args (phi); i = next_i)
741 : {
742 7794495 : tree arg = gimple_phi_arg_def (phi, i);
743 7794495 : edge e = gimple_phi_arg_edge (phi, i);
744 :
745 : /* Advance the argument index unless a path involving
746 : the current argument has been isolated. */
747 7794495 : next_i = i + 1;
748 :
749 7794495 : if (!integer_zerop (arg))
750 7177040 : continue;
751 :
752 617455 : location_t phi_arg_loc = gimple_phi_arg_location (phi, i);
753 :
754 617455 : imm_use_iterator iter;
755 617455 : gimple *use_stmt;
756 :
757 : /* We've got a NULL PHI argument. Now see if the
758 : PHI's result is dereferenced within BB. */
759 617455 : auto_vec <gimple *, 4> uses_in_bb;
760 2160257 : FOR_EACH_IMM_USE_STMT (use_stmt, iter, lhs)
761 : {
762 : /* We only care about uses in BB. Catching cases in
763 : in other blocks would require more complex path
764 : isolation code. */
765 1542802 : if (gimple_bb (use_stmt) != bb)
766 795229 : continue;
767 :
768 747573 : location_t loc = gimple_location (use_stmt)
769 747573 : ? gimple_location (use_stmt)
770 : : phi_arg_loc;
771 :
772 747573 : if (stmt_uses_name_in_undefined_way (use_stmt, lhs, loc))
773 : {
774 1374 : if (!can_duplicate_block_p (bb))
775 : break;
776 1374 : uses_in_bb.safe_push (use_stmt);
777 : }
778 617455 : }
779 1853739 : for (gimple *use_stmt : uses_in_bb)
780 : {
781 1374 : duplicate = isolate_path (bb, duplicate, e,
782 : use_stmt, lhs, false);
783 :
784 : /* When we remove an incoming edge, we need to
785 : reprocess the Ith element. */
786 1374 : next_i = i;
787 1374 : cfg_altered = true;
788 : }
789 617455 : }
790 : }
791 :
792 : /* Then look for a PHI which have addresses of locals that
793 : are then returned. */
794 8243152 : duplicate = NULL;
795 11354589 : for (si = gsi_start_phis (bb); !gsi_end_p (si); gsi_next (&si))
796 : {
797 3111437 : gphi *phi = si.phi ();
798 3111437 : tree lhs = gimple_phi_result (phi);
799 :
800 : /* Initial number of PHI arguments. The result may change
801 : from one iteration of the loop below to the next in
802 : response to changes to the CFG but only the initial
803 : value is stored below for use by diagnostics. */
804 3111437 : unsigned nargs = gimple_phi_num_args (phi);
805 :
806 : /* PHI produces a pointer result. See if any of the PHI's
807 : arguments are NULL.
808 :
809 : When we remove an edge, we want to reprocess the current
810 : index since the argument at that index will have been
811 : removed, hence the ugly way we update I for each iteration. */
812 3111437 : for (unsigned i = 0, next_i = 0;
813 10904819 : i < gimple_phi_num_args (phi); i = next_i)
814 : {
815 7793382 : tree arg = gimple_phi_arg_def (phi, i);
816 7793382 : edge e = gimple_phi_arg_edge (phi, i);
817 :
818 : /* Advance the argument index unless a path involving
819 : the current argument has been isolated. */
820 7793382 : next_i = i + 1;
821 7793382 : bool isolated = false;
822 7793382 : duplicate = handle_return_addr_local_phi_arg (bb, duplicate, lhs,
823 : arg, e, locmap,
824 : nargs, &isolated);
825 7793382 : if (isolated)
826 : {
827 109 : cfg_altered = true;
828 109 : next_i = i;
829 : }
830 : }
831 : }
832 :
833 : }
834 :
835 981472 : diag_returned_locals (false, locmap);
836 981472 : }
837 :
838 : /* Detect and diagnose returning the address of a local variable
839 : in RETURN_STMT in basic block BB. This only becomes undefined
840 : behavior if the result is used, so we do not insert a trap and
841 : only return NULL instead. */
842 :
843 : static void
844 956872 : warn_return_addr_local (basic_block bb, greturn *return_stmt)
845 : {
846 956872 : tree val = gimple_return_retval (return_stmt);
847 956872 : if (!val)
848 956793 : return;
849 :
850 547108 : locmap_t locmap;
851 547108 : hash_set<gphi *> visited_phis;
852 547108 : if (!is_addr_local (return_stmt, val, &locmap, &visited_phis))
853 : return;
854 :
855 : /* We only need it for this particular case. */
856 247 : calculate_dominance_info (CDI_POST_DOMINATORS);
857 :
858 247 : const args_loc_t *argsloc = locmap.get (return_stmt);
859 247 : gcc_assert (argsloc);
860 :
861 247 : bool maybe = argsloc->nargs > argsloc->locvec.length ();
862 247 : if (!maybe)
863 215 : maybe = !dominated_by_p (CDI_POST_DOMINATORS,
864 215 : single_succ (ENTRY_BLOCK_PTR_FOR_FN (cfun)), bb);
865 :
866 247 : diag_returned_locals (maybe, locmap);
867 :
868 : /* Bail if the statement isn't certain to return the address
869 : of a local (e.g., if it involves a conditional expression
870 : that wasn't transformed into a PHI or if it involves
871 : a MAX_EXPR or MIN_EXPR only one of whose operands is a local
872 : (even though such an expression isn't valid in C or has
873 : defined semantics in C++). */
874 247 : if (maybe)
875 : return;
876 :
877 : /* Do not modify code if the user only asked for warnings. */
878 79 : if (flag_isolate_erroneous_paths_dereference
879 0 : || flag_isolate_erroneous_paths_attribute)
880 : {
881 79 : tree zero = build_zero_cst (TREE_TYPE (val));
882 79 : gimple_return_set_retval (return_stmt, zero);
883 79 : update_stmt (return_stmt);
884 : }
885 547108 : }
886 :
887 : /* Look for statements which exhibit erroneous behavior. For example
888 : a NULL pointer dereference.
889 :
890 : When found, optimize the block containing the erroneous behavior. */
891 : static void
892 981472 : find_explicit_erroneous_behavior (void)
893 : {
894 981472 : basic_block bb;
895 981472 : auto_vec<gimple *> local_bb_split_points;
896 981472 : bb_split_points = &local_bb_split_points;
897 :
898 10213206 : FOR_EACH_BB_FN (bb, cfun)
899 : {
900 9231734 : gimple_stmt_iterator si;
901 :
902 : /* Out of an abundance of caution, do not isolate paths to a
903 : block where the block has any abnormal outgoing edges.
904 :
905 : We might be able to relax this in the future. We have to detect
906 : when we have to split the block with the NULL dereference and
907 : the trap we insert. We have to preserve abnormal edges out
908 : of the isolated block which in turn means updating PHIs at
909 : the targets of those abnormal outgoing edges. */
910 9231734 : if (has_abnormal_or_eh_outgoing_edge_p (bb))
911 734610 : continue;
912 :
913 : /* Now look at the statements in the block and see if any of
914 : them explicitly dereference a NULL pointer. This happens
915 : because of jump threading and constant propagation. */
916 96063508 : for (si = gsi_start_bb (bb); !gsi_end_p (si); gsi_next (&si))
917 : {
918 79070461 : gimple *stmt = gsi_stmt (si);
919 :
920 79070461 : if (stmt_uses_0_or_null_in_undefined_way (stmt))
921 : {
922 1201 : insert_trap (&si, null_pointer_node);
923 1201 : bb = gimple_bb (gsi_stmt (si));
924 :
925 : /* Ignore any more operands on this statement and
926 : continue the statement iterator (which should
927 : terminate its loop immediately. */
928 1201 : cfg_altered = true;
929 1201 : break;
930 : }
931 :
932 : /* Look for a return statement that returns the address
933 : of a local variable or the result of alloca. */
934 80026132 : if (greturn *return_stmt = dyn_cast <greturn *> (stmt))
935 956872 : warn_return_addr_local (bb, return_stmt);
936 : }
937 : }
938 :
939 981472 : free_dominance_info (CDI_POST_DOMINATORS);
940 :
941 : /* Perform delayed splitting of blocks. */
942 981475 : for (gimple *stmt : local_bb_split_points)
943 1 : split_block (gimple_bb (stmt), stmt);
944 :
945 981472 : bb_split_points = NULL;
946 981472 : }
947 :
948 : /* Search the function for statements which, if executed, would cause
949 : the program to fault such as a dereference of a NULL pointer.
950 :
951 : Such a program can't be valid if such a statement was to execute
952 : according to ISO standards.
953 :
954 : We detect explicit NULL pointer dereferences as well as those implied
955 : by a PHI argument having a NULL value which unconditionally flows into
956 : a dereference in the same block as the PHI.
957 :
958 : In the former case we replace the offending statement with an
959 : unconditional trap and eliminate the outgoing edges from the statement's
960 : basic block. This may expose secondary optimization opportunities.
961 :
962 : In the latter case, we isolate the path(s) with the NULL PHI
963 : feeding the dereference. We can then replace the offending statement
964 : and eliminate the outgoing edges in the duplicate. Again, this may
965 : expose secondary optimization opportunities.
966 :
967 : A warning for both cases may be advisable as well.
968 :
969 : Other statically detectable violations of the ISO standard could be
970 : handled in a similar way, such as out-of-bounds array indexing. */
971 :
972 : static unsigned int
973 981472 : gimple_ssa_isolate_erroneous_paths (void)
974 : {
975 981472 : initialize_original_copy_tables ();
976 :
977 : /* Search all the blocks for edges which, if traversed, will
978 : result in undefined behavior. */
979 981472 : cfg_altered = false;
980 :
981 : /* First handle cases where traversal of a particular edge
982 : triggers undefined behavior. These cases require creating
983 : duplicate blocks and thus new SSA_NAMEs.
984 :
985 : We want that process complete prior to the phase where we start
986 : removing edges from the CFG. Edge removal may ultimately result in
987 : removal of PHI nodes and thus releasing SSA_NAMEs back to the
988 : name manager.
989 :
990 : If the two processes run in parallel we could release an SSA_NAME
991 : back to the manager but we could still have dangling references
992 : to the released SSA_NAME in unreachable blocks.
993 : that any released names not have dangling references in the IL. */
994 981472 : find_implicit_erroneous_behavior ();
995 981472 : find_explicit_erroneous_behavior ();
996 :
997 981472 : free_original_copy_tables ();
998 :
999 : /* We scramble the CFG and loop structures a bit, clean up
1000 : appropriately. We really should incrementally update the
1001 : loop structures, in theory it shouldn't be that hard. */
1002 981472 : if (cfg_altered)
1003 : {
1004 1331 : free_dominance_info (CDI_DOMINATORS);
1005 1331 : loops_state_set (LOOPS_NEED_FIXUP);
1006 1331 : return TODO_cleanup_cfg | TODO_update_ssa;
1007 : }
1008 : return 0;
1009 : }
1010 :
1011 : namespace {
1012 : const pass_data pass_data_isolate_erroneous_paths =
1013 : {
1014 : GIMPLE_PASS, /* type */
1015 : "isolate-paths", /* name */
1016 : OPTGROUP_NONE, /* optinfo_flags */
1017 : TV_ISOLATE_ERRONEOUS_PATHS, /* tv_id */
1018 : ( PROP_cfg | PROP_ssa ), /* properties_required */
1019 : 0, /* properties_provided */
1020 : 0, /* properties_destroyed */
1021 : 0, /* todo_flags_start */
1022 : 0, /* todo_flags_finish */
1023 : };
1024 :
1025 : class pass_isolate_erroneous_paths : public gimple_opt_pass
1026 : {
1027 : public:
1028 294196 : pass_isolate_erroneous_paths (gcc::context *ctxt)
1029 588392 : : gimple_opt_pass (pass_data_isolate_erroneous_paths, ctxt)
1030 : {}
1031 :
1032 : /* opt_pass methods: */
1033 0 : opt_pass * clone () final override
1034 : {
1035 0 : return new pass_isolate_erroneous_paths (m_ctxt);
1036 : }
1037 1060389 : bool gate (function *) final override
1038 : {
1039 : /* If we do not have a suitable builtin function for the trap statement,
1040 : then do not perform the optimization. */
1041 1060389 : return (flag_isolate_erroneous_paths_dereference != 0
1042 78851 : || flag_isolate_erroneous_paths_attribute != 0
1043 1139238 : || warn_null_dereference);
1044 : }
1045 :
1046 981472 : unsigned int execute (function *) final override
1047 : {
1048 981472 : return gimple_ssa_isolate_erroneous_paths ();
1049 : }
1050 :
1051 : }; // class pass_isolate_erroneous_paths
1052 : }
1053 :
1054 : gimple_opt_pass *
1055 294196 : make_pass_isolate_erroneous_paths (gcc::context *ctxt)
1056 : {
1057 294196 : return new pass_isolate_erroneous_paths (ctxt);
1058 : }
|