GCC Middle and Back End API Reference
gimple-ssa-isolate-paths.cc File Reference
#include "config.h"
#include "system.h"
#include "coretypes.h"
#include "backend.h"
#include "tree.h"
#include "gimple.h"
#include "cfghooks.h"
#include "tree-pass.h"
#include "ssa.h"
#include "diagnostic-core.h"
#include "fold-const.h"
#include "gimple-iterator.h"
#include "gimple-walk.h"
#include "tree-ssa.h"
#include "cfgloop.h"
#include "tree-cfg.h"
#include "cfganal.h"
#include "intl.h"
Include dependency graph for gimple-ssa-isolate-paths.cc:

Data Structures

class  args_loc_t
 

Typedefs

typedef hash_map< gimple *, args_loc_tlocmap_t
 

Functions

static bool check_loadstore (gimple *stmt, tree op, tree, void *data)
 
static void insert_trap (gimple_stmt_iterator *si_p, tree op)
 
ATTRIBUTE_RETURNS_NONNULL basic_block isolate_path (basic_block bb, basic_block duplicate, edge e, gimple *stmt, tree op, bool ret_zero)
 
static bool is_divmod_with_given_divisor (gimple *stmt, tree divisor)
 
bool stmt_uses_name_in_undefined_way (gimple *use_stmt, tree name, location_t loc)
 
bool stmt_uses_0_or_null_in_undefined_way (gimple *stmt)
 
static void diag_returned_locals (bool maybe, const locmap_t &locmap)
 
static bool is_addr_local (gimple *return_stmt, tree exp, locmap_t *plocmap, hash_set< gphi * > *visited)
 
static basic_block handle_return_addr_local_phi_arg (basic_block bb, basic_block duplicate, tree lhs, tree arg, edge e, locmap_t &locmap, unsigned nargs, bool *isolated)
 
static void find_implicit_erroneous_behavior (void)
 
static void warn_return_addr_local (basic_block bb, greturn *return_stmt)
 
static void find_explicit_erroneous_behavior (void)
 
static unsigned int gimple_ssa_isolate_erroneous_paths (void)
 
gimple_opt_passmake_pass_isolate_erroneous_paths (gcc::context *ctxt)
 

Variables

static bool cfg_altered
 

Typedef Documentation

◆ locmap_t

A mapping from a return statement to the locations of local variables
whose addresses it may return.   

Function Documentation

◆ check_loadstore()

static bool check_loadstore ( gimple * stmt,
tree op,
tree ,
void * data )
static
Callback for walk_stmt_load_store_ops.

Return TRUE if OP will dereference the tree stored in DATA, FALSE
otherwise.

This routine only makes a superficial check for a dereference.  Thus,
it must only be used if it is safe to return a false negative.   

References ggc_alloc(), operand_equal_p(), TREE_CODE, TREE_OPERAND, TREE_SIDE_EFFECTS, TREE_THIS_VOLATILE, and update_stmt().

Referenced by insert_trap().

◆ diag_returned_locals()

static void diag_returned_locals ( bool maybe,
const locmap_t & locmap )
static
Given the LOCMAP mapping, issue diagnostics about returning addresses
of local variables.  When MAYBE is set, all diagnostics will be of
the "may return" kind.  Otherwise each will be determined based on
the equality of the corresponding NARGS and LOCVEC.LENGTH () values.   

References cfun, G_, ggc_alloc(), gimple_location(), i, inform(), UNKNOWN_LOCATION, and warning_at().

Referenced by find_implicit_erroneous_behavior(), and warn_return_addr_local().

◆ find_explicit_erroneous_behavior()

static void find_explicit_erroneous_behavior ( void )
static
Look for statements which exhibit erroneous behavior.  For example
a NULL pointer dereference.

When found, optimize the block containing the erroneous behavior.   

References cfg_altered, cfun, FOR_EACH_BB_FN, ggc_alloc(), gimple_bb(), gsi_end_p(), gsi_next(), gsi_start_bb(), gsi_stmt(), has_abnormal_or_eh_outgoing_edge_p(), insert_trap(), null_pointer_node, si, stmt_uses_0_or_null_in_undefined_way(), and warn_return_addr_local().

Referenced by gimple_ssa_isolate_erroneous_paths().

◆ find_implicit_erroneous_behavior()

static void find_implicit_erroneous_behavior ( void )
static
Look for PHI nodes which feed statements in the same block where
the value of the PHI node implies the statement is erroneous.

For example, a NULL PHI arg value which then feeds a pointer
dereference.

When found isolate and optimize the path associated with the PHI
argument feeding the erroneous statement.   

References can_duplicate_block_p(), cfg_altered, cfun, diag_returned_locals(), find_edge(), FOR_EACH_BB_FN, FOR_EACH_IMM_USE_STMT, ggc_alloc(), gimple_bb(), gimple_location(), gimple_phi_arg_def(), gimple_phi_arg_edge(), gimple_phi_arg_location(), gimple_phi_num_args(), gimple_phi_result(), gsi_end_p(), gsi_next(), gsi_start_phis(), handle_return_addr_local_phi_arg(), has_abnormal_or_eh_outgoing_edge_p(), i, integer_zerop(), isolate_path(), NULL, si, and stmt_uses_name_in_undefined_way().

Referenced by gimple_ssa_isolate_erroneous_paths().

◆ gimple_ssa_isolate_erroneous_paths()

static unsigned int gimple_ssa_isolate_erroneous_paths ( void )
static
Search the function for statements which, if executed, would cause
the program to fault such as a dereference of a NULL pointer.

Such a program can't be valid if such a statement was to execute
according to ISO standards.

We detect explicit NULL pointer dereferences as well as those implied
by a PHI argument having a NULL value which unconditionally flows into
a dereference in the same block as the PHI.

In the former case we replace the offending statement with an
unconditional trap and eliminate the outgoing edges from the statement's
basic block.  This may expose secondary optimization opportunities.

In the latter case, we isolate the path(s) with the NULL PHI
feeding the dereference.  We can then replace the offending statement
and eliminate the outgoing edges in the duplicate.  Again, this may
expose secondary optimization opportunities.

A warning for both cases may be advisable as well.

Other statically detectable violations of the ISO standard could be
handled in a similar way, such as out-of-bounds array indexing.   

References CDI_DOMINATORS, CDI_POST_DOMINATORS, cfg_altered, find_explicit_erroneous_behavior(), find_implicit_erroneous_behavior(), free_dominance_info(), free_original_copy_tables(), initialize_original_copy_tables(), LOOPS_NEED_FIXUP, loops_state_set(), TODO_cleanup_cfg, and TODO_update_ssa.

◆ handle_return_addr_local_phi_arg()

static basic_block handle_return_addr_local_phi_arg ( basic_block bb,
basic_block duplicate,
tree lhs,
tree arg,
edge e,
locmap_t & locmap,
unsigned nargs,
bool * isolated )
static
Detect returning the address of a local variable in a PHI result LHS
and argument ARG and PHI edge E in basic block BB.  Add an entry for
each use to LOCMAP, setting its NARGS member to the NARGS argument
(the number of PHI operands) plus the number of arguments in binary
expressions refereced by ARG.  Call isolate_path for each returned
address and set *ISOLATED to true if called.
Return either DUPLICATE or the most recent result of isolate_path.   

References can_duplicate_block_p(), FOR_EACH_IMM_USE_STMT, gcc_assert, ggc_alloc(), gimple_bb(), gimple_return_retval(), is_addr_local(), isolate_path(), and NULL.

Referenced by find_implicit_erroneous_behavior().

◆ insert_trap()

◆ is_addr_local()

static bool is_addr_local ( gimple * return_stmt,
tree exp,
locmap_t * plocmap,
hash_set< gphi * > * visited )
static
Return true if EXPR is an expression of pointer type that refers
to the address of one or more variables with automatic storage
duration.  If so, add an entry to *PLOCMAP and insert into
PLOCMAP->LOCVEC the locations of the corresponding local variables
whose address is returned by the RETURN_STMT (which may be set to
(gimple*)-1 as a placeholder for such a statement).  VISITED is
a bitmap of PHI nodes already visited by recursive calls.  When
null, PHI expressions are not considered.   

References BUILT_IN_NORMAL, count, DECL_FUNCTION_CODE(), DECL_SOURCE_LOCATION, exp(), get_base_address(), ggc_alloc(), gimple_assign_lhs(), gimple_assign_rhs1(), gimple_assign_rhs2(), gimple_assign_rhs3(), gimple_assign_rhs_code(), gimple_call_arg(), gimple_call_builtin_p(), gimple_call_fndecl(), gimple_call_num_args(), gimple_location(), gimple_phi_arg_def(), gimple_phi_num_args(), i, is_addr_local(), is_gimple_assign(), is_global_var(), NULL_TREE, POINTER_TYPE_P, SSA_NAME_DEF_STMT, TREE_CODE, TREE_OPERAND, TREE_TYPE, VAR_P, and visited.

Referenced by handle_return_addr_local_phi_arg(), is_addr_local(), and warn_return_addr_local().

◆ is_divmod_with_given_divisor()

static bool is_divmod_with_given_divisor ( gimple * stmt,
tree divisor )
static
Return TRUE if STMT is a div/mod operation using DIVISOR as the divisor.
FALSE otherwise.   

References ggc_alloc(), gimple_assign_rhs2(), gimple_assign_rhs_code(), is_gimple_assign(), and operand_equal_p().

Referenced by stmt_uses_0_or_null_in_undefined_way(), and stmt_uses_name_in_undefined_way().

◆ isolate_path()

ATTRIBUTE_RETURNS_NONNULL basic_block isolate_path ( basic_block bb,
basic_block duplicate,
edge e,
gimple * stmt,
tree op,
bool ret_zero )
BB when reached via incoming edge E will exhibit undefined behavior
at STMT.  Isolate and optimize the path which exhibits undefined
behavior.

Isolation is simple.  Duplicate BB and redirect E to BB'.

Optimization is simple as well.  Replace STMT in BB' with an
unconditional trap and remove all outgoing edges from BB'.

If RET_ZERO, do not trap, only return NULL.

DUPLICATE is a pre-existing duplicate, use it as BB' if it exists.

Return BB' (which may be equal to DUPLICATE).   

References build_zero_cst(), basic_block_def::count, count, duplicate_block(), ei_safe_edge(), ei_start, flush_pending_stmts(), force_edge_cold(), gcc_assert, ggc_alloc(), gimple_return_retval(), gimple_return_set_retval(), gsi_end_p(), gsi_next(), gsi_next_nondebug(), gsi_start_bb(), gsi_start_nondebug_after_labels_bb(), gsi_stmt(), insert_trap(), NULL, redirect_edge_and_branch(), remove_edge(), si, stmt_can_terminate_bb_p(), basic_block_def::succs, TREE_TYPE, update_stmt(), and profile_count::zero().

Referenced by find_implicit_erroneous_behavior(), and handle_return_addr_local_phi_arg().

◆ make_pass_isolate_erroneous_paths()

gimple_opt_pass * make_pass_isolate_erroneous_paths ( gcc::context * ctxt)

References ggc_alloc().

◆ stmt_uses_0_or_null_in_undefined_way()

bool stmt_uses_0_or_null_in_undefined_way ( gimple * stmt)
Return TRUE if USE_STMT uses 0 or NULL in a context which results in
undefined behavior, FALSE otherwise.

These cases are explicit in the IL.   

References cfun, ggc_alloc(), gimple_location(), infer_nonnull_range_by_attribute(), infer_nonnull_range_by_dereference(), integer_zero_node, is_divmod_with_given_divisor(), null_pointer_node, and warning_at().

Referenced by find_explicit_erroneous_behavior().

◆ stmt_uses_name_in_undefined_way()

bool stmt_uses_name_in_undefined_way ( gimple * use_stmt,
tree name,
location_t loc )
NAME is an SSA_NAME that we have already determined has the value 0 or NULL.

Return TRUE if USE_STMT uses NAME in a way where a 0 or NULL value results
in undefined behavior, FALSE otherwise

LOC is used for issuing diagnostics.  This case represents potential
undefined behavior exposed by path splitting and that's reflected in
the diagnostic.   

References cfun, ggc_alloc(), infer_nonnull_range_by_attribute(), infer_nonnull_range_by_dereference(), is_divmod_with_given_divisor(), POINTER_TYPE_P, TREE_TYPE, and warning_at().

Referenced by find_implicit_erroneous_behavior().

◆ warn_return_addr_local()

static void warn_return_addr_local ( basic_block bb,
greturn * return_stmt )
static
Detect and diagnose returning the address of a local variable
in RETURN_STMT in basic block BB.  This only becomes undefined
behavior if the result is used, so we do not insert a trap and
only return NULL instead.   

References build_zero_cst(), calculate_dominance_info(), CDI_POST_DOMINATORS, cfun, diag_returned_locals(), dominated_by_p(), ENTRY_BLOCK_PTR_FOR_FN, gcc_assert, ggc_alloc(), gimple_return_retval(), gimple_return_set_retval(), is_addr_local(), single_succ(), TREE_TYPE, and update_stmt().

Referenced by find_explicit_erroneous_behavior().

Variable Documentation

◆ cfg_altered

bool cfg_altered
static
Detect paths through the CFG which can never be executed in a conforming
   program and isolate them.

   Copyright (C) 2013-2024 Free Software Foundation, Inc.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING3.  If not see
<http://www.gnu.org/licenses/>.   

Referenced by find_explicit_erroneous_behavior(), find_implicit_erroneous_behavior(), gimple_ssa_isolate_erroneous_paths(), and dom_opt_dom_walker::optimize_stmt().