@@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see
#include "analyzer/analyzer.h"
#include "tree-pretty-print.h"
#include "diagnostic-event-id.h"
+#include "tree-dfa.h"
#if ENABLE_ANALYZER
@@ -275,6 +276,14 @@ byte_offset_to_json (const byte_offset_t &offset)
return new json::string (pp_formatted_text (&pp));
}
+/* Workaround for lack of const-correctness of ssa_default_def. */
+
+tree
+get_ssa_default_def (const function &fun, tree var)
+{
+ return ssa_default_def (const_cast <function *> (&fun), var);
+}
+
} // namespace ana
/* Helper function for checkers. Is the CALL to the given function name,
@@ -433,6 +433,9 @@ compare_constants (tree lhs_const, enum tree_code op, tree rhs_const);
extern tree
get_string_cst_size (const_tree string_cst);
+extern tree
+get_ssa_default_def (const function &fun, tree var);
+
} // namespace ana
extern bool is_special_named_call_p (const gcall *call, const char *funcname,
@@ -143,6 +143,14 @@ call_info::call_info (const call_details &cd)
gcc_assert (m_fndecl);
}
+call_info::call_info (const call_details &cd,
+ const function &called_fn)
+: m_call_stmt (cd.get_call_stmt ()),
+ m_fndecl (called_fn.decl)
+{
+ gcc_assert (m_fndecl);
+}
+
/* class succeed_or_fail_call_info : public call_info. */
label_text
@@ -44,6 +44,7 @@ public:
protected:
call_info (const call_details &cd);
+ call_info (const call_details &cd, const function &called_fn);
private:
const gcall *m_call_stmt;
@@ -167,7 +167,7 @@ call_summary::dump (const extrinsic_state &ext_state, bool simple) const
arguments at the caller. */
call_summary_replay::call_summary_replay (const call_details &cd,
- function *called_fn,
+ const function &called_fn,
call_summary *summary,
const extrinsic_state &ext_state)
: m_cd (cd),
@@ -177,7 +177,7 @@ call_summary_replay::call_summary_replay (const call_details &cd,
region_model_manager *mgr = cd.get_manager ();
// populate params based on args
- tree fndecl = called_fn->decl;
+ tree fndecl = called_fn.decl;
/* Get a frame_region for use with respect to the summary.
This will be a top-level frame, since that's what's in
@@ -196,7 +196,7 @@ call_summary_replay::call_summary_replay (const call_details &cd,
break;
const svalue *caller_arg_sval = cd.get_arg_svalue (idx);
tree parm_lval = iter_parm;
- if (tree parm_default_ssa = ssa_default_def (called_fn, iter_parm))
+ if (tree parm_default_ssa = get_ssa_default_def (called_fn, iter_parm))
parm_lval = parm_default_ssa;
const region *summary_parm_reg
= summary_frame->get_region_for_local (mgr, parm_lval, cd.get_ctxt ());
@@ -68,7 +68,7 @@ class call_summary_replay
{
public:
call_summary_replay (const call_details &cd,
- function *called_fn,
+ const function &called_fn,
call_summary *m_summary,
const extrinsic_state &ext_state);
@@ -370,7 +370,7 @@ public:
label_text get_desc (bool can_colorize) const final override;
meaning get_meaning () const override;
- function *get_dest_function () const
+ const function *get_dest_function () const
{
return m_dst_state.get_current_function ();
}
@@ -1072,7 +1072,7 @@ point_and_state::validate (const extrinsic_state &ext_state) const
{
int index = iter_frame->get_index ();
gcc_assert (m_point.get_function_at_depth (index)
- == iter_frame->get_function ());
+ == &iter_frame->get_function ());
}
}
@@ -1496,14 +1496,17 @@ exploded_node::on_stmt (exploded_graph &eg,
per_function_data *called_fn_data
= eg.get_per_function_data (called_fn);
if (called_fn_data)
- return replay_call_summaries (eg,
- snode,
- as_a <const gcall *> (stmt),
- state,
- path_ctxt,
- called_fn,
- called_fn_data,
- &ctxt);
+ {
+ gcc_assert (called_fn);
+ return replay_call_summaries (eg,
+ snode,
+ as_a <const gcall *> (stmt),
+ state,
+ path_ctxt,
+ *called_fn,
+ *called_fn_data,
+ &ctxt);
+ }
}
bool unknown_side_effects = false;
@@ -1610,10 +1613,10 @@ class call_summary_edge_info : public call_info
{
public:
call_summary_edge_info (const call_details &cd,
- function *called_fn,
+ const function &called_fn,
call_summary *summary,
const extrinsic_state &ext_state)
- : call_info (cd),
+ : call_info (cd, called_fn),
m_called_fn (called_fn),
m_summary (summary),
m_ext_state (ext_state)
@@ -1648,7 +1651,7 @@ public:
}
private:
- function *m_called_fn;
+ const function &m_called_fn;
call_summary *m_summary;
const extrinsic_state &m_ext_state;
};
@@ -1662,18 +1665,15 @@ exploded_node::replay_call_summaries (exploded_graph &eg,
const gcall *call_stmt,
program_state *state,
path_context *path_ctxt,
- function *called_fn,
- per_function_data *called_fn_data,
+ const function &called_fn,
+ per_function_data &called_fn_data,
region_model_context *ctxt)
{
logger *logger = eg.get_logger ();
LOG_SCOPE (logger);
- gcc_assert (called_fn);
- gcc_assert (called_fn_data);
-
/* Each summary will call bifurcate on the PATH_CTXT. */
- for (auto summary : called_fn_data->m_summaries)
+ for (auto summary : called_fn_data.m_summaries)
replay_call_summary (eg, snode, call_stmt, state,
path_ctxt, called_fn, summary, ctxt);
path_ctxt->terminate_path ();
@@ -1691,7 +1691,7 @@ exploded_node::replay_call_summary (exploded_graph &eg,
const gcall *call_stmt,
program_state *old_state,
path_context *path_ctxt,
- function *called_fn,
+ const function &called_fn,
call_summary *summary,
region_model_context *ctxt)
{
@@ -1700,13 +1700,12 @@ exploded_node::replay_call_summary (exploded_graph &eg,
gcc_assert (snode);
gcc_assert (call_stmt);
gcc_assert (old_state);
- gcc_assert (called_fn);
gcc_assert (summary);
if (logger)
logger->log ("using %s as summary for call to %qE from %qE",
summary->get_desc ().get (),
- called_fn->decl,
+ called_fn.decl,
snode->get_function ()->decl);
const extrinsic_state &ext_state = eg.get_ext_state ();
const program_state &summary_end_state = summary->get_state ();
@@ -2784,16 +2783,17 @@ private:
Return the exploded_node for the entrypoint to the function. */
exploded_node *
-exploded_graph::add_function_entry (function *fun)
+exploded_graph::add_function_entry (const function &fun)
{
- gcc_assert (gimple_has_body_p (fun->decl));
+ gcc_assert (gimple_has_body_p (fun.decl));
/* Be idempotent. */
- if (m_functions_with_enodes.contains (fun))
+ function *key = const_cast<function *> (&fun);
+ if (m_functions_with_enodes.contains (key))
{
logger * const logger = get_logger ();
if (logger)
- logger->log ("entrypoint for %qE already exists", fun->decl);
+ logger->log ("entrypoint for %qE already exists", fun.decl);
return NULL;
}
@@ -2805,10 +2805,10 @@ exploded_graph::add_function_entry (function *fun)
std::unique_ptr<custom_edge_info> edge_info = NULL;
- if (lookup_attribute ("tainted_args", DECL_ATTRIBUTES (fun->decl)))
+ if (lookup_attribute ("tainted_args", DECL_ATTRIBUTES (fun.decl)))
{
- if (mark_params_as_tainted (&state, fun->decl, m_ext_state))
- edge_info = make_unique<tainted_args_function_info> (fun->decl);
+ if (mark_params_as_tainted (&state, fun.decl, m_ext_state))
+ edge_info = make_unique<tainted_args_function_info> (fun.decl);
}
if (!state.m_valid)
@@ -2820,7 +2820,7 @@ exploded_graph::add_function_entry (function *fun)
add_edge (m_origin, enode, NULL, false, std::move (edge_info));
- m_functions_with_enodes.add (fun);
+ m_functions_with_enodes.add (key);
return enode;
}
@@ -3108,7 +3108,7 @@ exploded_graph::get_per_function_data (function *fun) const
called via other functions. */
static bool
-toplevel_function_p (function *fun, logger *logger)
+toplevel_function_p (const function &fun, logger *logger)
{
/* Don't directly traverse into functions that have an "__analyzer_"
prefix. Doing so is useful for the analyzer test suite, allowing
@@ -3119,17 +3119,17 @@ toplevel_function_p (function *fun, logger *logger)
excess messages from the case of the first function being traversed
directly. */
#define ANALYZER_PREFIX "__analyzer_"
- if (!strncmp (IDENTIFIER_POINTER (DECL_NAME (fun->decl)), ANALYZER_PREFIX,
+ if (!strncmp (IDENTIFIER_POINTER (DECL_NAME (fun.decl)), ANALYZER_PREFIX,
strlen (ANALYZER_PREFIX)))
{
if (logger)
logger->log ("not traversing %qE (starts with %qs)",
- fun->decl, ANALYZER_PREFIX);
+ fun.decl, ANALYZER_PREFIX);
return false;
}
if (logger)
- logger->log ("traversing %qE (all checks passed)", fun->decl);
+ logger->log ("traversing %qE (all checks passed)", fun.decl);
return true;
}
@@ -3254,9 +3254,9 @@ add_tainted_args_callback (exploded_graph *eg, tree field, tree fndecl,
program_point point
= program_point::from_function_entry (*ext_state.get_model_manager (),
- eg->get_supergraph (), fun);
+ eg->get_supergraph (), *fun);
program_state state (ext_state);
- state.push_frame (ext_state, fun);
+ state.push_frame (ext_state, *fun);
if (!mark_params_as_tainted (&state, fndecl, ext_state))
return;
@@ -3330,9 +3330,10 @@ exploded_graph::build_initial_worklist ()
FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
{
function *fun = node->get_fun ();
- if (!toplevel_function_p (fun, logger))
+ gcc_assert (fun);
+ if (!toplevel_function_p (*fun, logger))
continue;
- exploded_node *enode = add_function_entry (fun);
+ exploded_node *enode = add_function_entry (*fun);
if (logger)
{
if (enode)
@@ -3838,8 +3839,8 @@ exploded_graph::maybe_create_dynamic_call (const gcall *call,
if (fun)
{
const supergraph &sg = this->get_supergraph ();
- supernode *sn_entry = sg.get_node_for_function_entry (fun);
- supernode *sn_exit = sg.get_node_for_function_exit (fun);
+ supernode *sn_entry = sg.get_node_for_function_entry (*fun);
+ supernode *sn_exit = sg.get_node_for_function_exit (*fun);
program_point new_point
= program_point::before_supernode (sn_entry,
@@ -4962,7 +4963,7 @@ maybe_update_for_edge (logger *logger,
== PK_BEFORE_SUPERNODE);
function *fun = eedge->m_dest->get_function ();
gcc_assert (fun);
- m_model.push_frame (fun, NULL, ctxt);
+ m_model.push_frame (*fun, NULL, ctxt);
if (logger)
logger->log (" pushing frame for %qD", fun->decl);
}
@@ -5582,7 +5583,7 @@ exploded_graph::on_escaped_function (tree fndecl)
if (!gimple_has_body_p (fndecl))
return;
- exploded_node *enode = add_function_entry (fun);
+ exploded_node *enode = add_function_entry (*fun);
if (logger)
{
if (enode)
@@ -285,15 +285,15 @@ class exploded_node : public dnode<eg_traits>
const gcall *call_stmt,
program_state *state,
path_context *path_ctxt,
- function *called_fn,
- per_function_data *called_fn_data,
+ const function &called_fn,
+ per_function_data &called_fn_data,
region_model_context *ctxt);
void replay_call_summary (exploded_graph &eg,
const supernode *snode,
const gcall *call_stmt,
program_state *state,
path_context *path_ctxt,
- function *called_fn,
+ const function &called_fn,
call_summary *summary,
region_model_context *ctxt);
@@ -810,7 +810,7 @@ public:
exploded_node *get_origin () const { return m_origin; }
- exploded_node *add_function_entry (function *fun);
+ exploded_node *add_function_entry (const function &fun);
void build_initial_worklist ();
void process_worklist ();
@@ -230,7 +230,7 @@ function_point::final_stmt_p () const
/* Create a function_point representing the entrypoint of function FUN. */
function_point
-function_point::from_function_entry (const supergraph &sg, function *fun)
+function_point::from_function_entry (const supergraph &sg, const function &fun)
{
return before_supernode (sg.get_node_for_function_entry (fun), NULL);
}
@@ -698,7 +698,7 @@ program_point::origin (const region_model_manager &mgr)
program_point
program_point::from_function_entry (const region_model_manager &mgr,
const supergraph &sg,
- function *fun)
+ const function &fun)
{
return program_point (function_point::from_function_entry (sg, fun),
mgr.get_empty_call_string ());
@@ -112,7 +112,7 @@ public:
/* Factory functions for making various kinds of program_point. */
static function_point from_function_entry (const supergraph &sg,
- function *fun);
+ const function &fun);
static function_point before_supernode (const supernode *supernode,
const superedge *from_edge);
@@ -252,7 +252,7 @@ public:
static program_point origin (const region_model_manager &mgr);
static program_point from_function_entry (const region_model_manager &mgr,
const supergraph &sg,
- function *fun);
+ const function &fun);
static program_point before_supernode (const supernode *supernode,
const superedge *from_edge,
@@ -1143,14 +1143,14 @@ program_state::to_json (const extrinsic_state &ext_state) const
void
program_state::push_frame (const extrinsic_state &ext_state ATTRIBUTE_UNUSED,
- function *fun)
+ const function &fun)
{
m_region_model->push_frame (fun, NULL, NULL);
}
/* Get the current function of this state. */
-function *
+const function *
program_state::get_current_function () const
{
return m_region_model->get_current_function ();
@@ -226,8 +226,8 @@ public:
json::object *to_json (const extrinsic_state &ext_state) const;
- void push_frame (const extrinsic_state &ext_state, function *fun);
- function * get_current_function () const;
+ void push_frame (const extrinsic_state &ext_state, const function &fun);
+ const function * get_current_function () const;
void push_call (exploded_graph &eg,
exploded_node *enode,
@@ -1676,7 +1676,7 @@ region_model_manager::get_cast_region (const region *original_region,
const frame_region *
region_model_manager::get_frame_region (const frame_region *calling_frame,
- function *fun)
+ const function &fun)
{
int index = calling_frame ? calling_frame->get_index () + 1 : 0;
@@ -131,7 +131,7 @@ public:
const region *get_cast_region (const region *original_region,
tree type);
const frame_region *get_frame_region (const frame_region *calling_frame,
- function *fun);
+ const function &fun);
const region *get_symbolic_region (const svalue *sval);
const string_region *get_region_for_string (tree string_cst);
const region *get_bit_range (const region *parent, tree type,
@@ -2619,7 +2619,7 @@ region_model::called_from_main_p () const
/* Determine if the oldest stack frame in this model is for "main". */
const frame_region *frame0 = get_frame_at_index (0);
gcc_assert (frame0);
- return id_equal (DECL_NAME (frame0->get_function ()->decl), "main");
+ return id_equal (DECL_NAME (frame0->get_function ().decl), "main");
}
/* Subroutine of region_model::get_store_value for when REG is (or is within)
@@ -5552,7 +5552,8 @@ region_model::update_for_gcall (const gcall *call_stmt,
callee = DECL_STRUCT_FUNCTION (fn_decl);
}
- push_frame (callee, &arg_svals, ctxt);
+ gcc_assert (callee);
+ push_frame (*callee, &arg_svals, ctxt);
}
/* Pop the top-most frame_region from the stack, and copy the return
@@ -5896,14 +5897,15 @@ region_model::on_top_level_param (tree param,
Return the frame_region for the new frame. */
const region *
-region_model::push_frame (function *fun, const vec<const svalue *> *arg_svals,
+region_model::push_frame (const function &fun,
+ const vec<const svalue *> *arg_svals,
region_model_context *ctxt)
{
m_current_frame = m_mgr->get_frame_region (m_current_frame, fun);
if (arg_svals)
{
/* Arguments supplied from a caller frame. */
- tree fndecl = fun->decl;
+ tree fndecl = fun.decl;
unsigned idx = 0;
for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm;
iter_parm = DECL_CHAIN (iter_parm), ++idx)
@@ -5914,7 +5916,7 @@ region_model::push_frame (function *fun, const vec<const svalue *> *arg_svals,
if (idx >= arg_svals->length ())
break;
tree parm_lval = iter_parm;
- if (tree parm_default_ssa = ssa_default_def (fun, iter_parm))
+ if (tree parm_default_ssa = get_ssa_default_def (fun, iter_parm))
parm_lval = parm_default_ssa;
const region *parm_reg = get_lvalue (parm_lval, ctxt);
const svalue *arg_sval = (*arg_svals)[idx];
@@ -5937,7 +5939,7 @@ region_model::push_frame (function *fun, const vec<const svalue *> *arg_svals,
/* Otherwise we have a top-level call within the analysis. The params
have defined but unknown initial values.
Anything they point to has escaped. */
- tree fndecl = fun->decl;
+ tree fndecl = fun.decl;
/* Handle "__attribute__((nonnull))". */
tree fntype = TREE_TYPE (fndecl);
@@ -5951,7 +5953,7 @@ region_model::push_frame (function *fun, const vec<const svalue *> *arg_svals,
? (bitmap_empty_p (nonnull_args)
|| bitmap_bit_p (nonnull_args, parm_idx))
: false);
- if (tree parm_default_ssa = ssa_default_def (fun, iter_parm))
+ if (tree parm_default_ssa = get_ssa_default_def (fun, iter_parm))
on_top_level_param (parm_default_ssa, non_null, ctxt);
else
on_top_level_param (iter_parm, non_null, ctxt);
@@ -5967,12 +5969,12 @@ region_model::push_frame (function *fun, const vec<const svalue *> *arg_svals,
/* Get the function of the top-most frame in this region_model's stack.
There must be such a frame. */
-function *
+const function *
region_model::get_current_function () const
{
const frame_region *frame = get_current_frame ();
gcc_assert (frame);
- return frame->get_function ();
+ return &frame->get_function ();
}
/* Pop the topmost frame_region from this region_model's stack;
@@ -6007,7 +6009,7 @@ region_model::pop_frame (tree result_lvalue,
ctxt->on_pop_frame (frame_reg);
/* Evaluate the result, within the callee frame. */
- tree fndecl = m_current_frame->get_function ()->decl;
+ tree fndecl = m_current_frame->get_function ().decl;
tree result = DECL_RESULT (fndecl);
const svalue *retval = NULL;
if (result
@@ -7966,7 +7968,7 @@ test_stack_frames ()
/* Push stack frame for "parent_fn". */
const region *parent_frame_reg
- = model.push_frame (DECL_STRUCT_FUNCTION (parent_fndecl),
+ = model.push_frame (*DECL_STRUCT_FUNCTION (parent_fndecl),
NULL, &ctxt);
ASSERT_EQ (model.get_current_frame (), parent_frame_reg);
ASSERT_TRUE (model.region_exists_p (parent_frame_reg));
@@ -7982,7 +7984,7 @@ test_stack_frames ()
/* Push stack frame for "child_fn". */
const region *child_frame_reg
- = model.push_frame (DECL_STRUCT_FUNCTION (child_fndecl), NULL, &ctxt);
+ = model.push_frame (*DECL_STRUCT_FUNCTION (child_fndecl), NULL, &ctxt);
ASSERT_EQ (model.get_current_frame (), child_frame_reg);
ASSERT_TRUE (model.region_exists_p (child_frame_reg));
const region *x_in_child_reg = model.get_lvalue (x, &ctxt);
@@ -8075,7 +8077,7 @@ test_get_representative_path_var ()
for (int depth = 0; depth < 5; depth++)
{
const region *frame_n_reg
- = model.push_frame (DECL_STRUCT_FUNCTION (fndecl), NULL, &ctxt);
+ = model.push_frame (*DECL_STRUCT_FUNCTION (fndecl), NULL, &ctxt);
const region *parm_n_reg = model.get_lvalue (path_var (n, depth), &ctxt);
parm_regs.safe_push (parm_n_reg);
@@ -8319,9 +8321,9 @@ test_state_merging ()
region_model model0 (&mgr);
region_model model1 (&mgr);
ASSERT_EQ (model0.get_stack_depth (), 0);
- model0.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, &ctxt);
+ model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, &ctxt);
ASSERT_EQ (model0.get_stack_depth (), 1);
- model1.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, &ctxt);
+ model1.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, &ctxt);
placeholder_svalue test_sval (mgr.alloc_symbol_id (),
integer_type_node, "test sval");
@@ -8413,7 +8415,7 @@ test_state_merging ()
/* Pointers: non-NULL and non-NULL: ptr to a local. */
{
region_model model0 (&mgr);
- model0.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
+ model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
model0.set_value (model0.get_lvalue (p, NULL),
model0.get_rvalue (addr_of_a, NULL), NULL);
@@ -8552,12 +8554,12 @@ test_state_merging ()
frame points to a local in a more recent stack frame. */
{
region_model model0 (&mgr);
- model0.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
+ model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
const region *q_in_first_frame = model0.get_lvalue (q, NULL);
/* Push a second frame. */
const region *reg_2nd_frame
- = model0.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
+ = model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
/* Have a pointer in the older frame point to a local in the
more recent frame. */
@@ -8584,7 +8586,7 @@ test_state_merging ()
/* Verify that we can merge a model in which a local points to a global. */
{
region_model model0 (&mgr);
- model0.push_frame (DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
+ model0.push_frame (*DECL_STRUCT_FUNCTION (test_fndecl), NULL, NULL);
model0.set_value (model0.get_lvalue (q, NULL),
model0.get_rvalue (addr_of_y, NULL), NULL);
@@ -9110,7 +9112,7 @@ test_alloca ()
/* Push stack frame. */
const region *frame_reg
- = model.push_frame (DECL_STRUCT_FUNCTION (fndecl),
+ = model.push_frame (*DECL_STRUCT_FUNCTION (fndecl),
NULL, &ctxt);
/* "p = alloca (n * 4);". */
const svalue *size_sval = model.get_rvalue (n_times_4, &ctxt);
@@ -347,10 +347,10 @@ class region_model
void update_for_return_gcall (const gcall *call_stmt,
region_model_context *ctxt);
- const region *push_frame (function *fun, const vec<const svalue *> *arg_sids,
+ const region *push_frame (const function &fun, const vec<const svalue *> *arg_sids,
region_model_context *ctxt);
const frame_region *get_current_frame () const { return m_current_frame; }
- function * get_current_function () const;
+ const function *get_current_function () const;
void pop_frame (tree result_lvalue,
const svalue **out_result,
region_model_context *ctxt,
@@ -1306,10 +1306,10 @@ void
frame_region::dump_to_pp (pretty_printer *pp, bool simple) const
{
if (simple)
- pp_printf (pp, "frame: %qs@%i", function_name (m_fun), get_stack_depth ());
+ pp_printf (pp, "frame: %qs@%i", function_name (&m_fun), get_stack_depth ());
else
pp_printf (pp, "frame_region(%qs, index: %i, depth: %i)",
- function_name (m_fun), m_index, get_stack_depth ());
+ function_name (&m_fun), m_index, get_stack_depth ());
}
const decl_region *
@@ -1334,14 +1334,14 @@ frame_region::get_region_for_local (region_model_manager *mgr,
/* Fall through. */
case PARM_DECL:
case RESULT_DECL:
- gcc_assert (DECL_CONTEXT (expr) == m_fun->decl);
+ gcc_assert (DECL_CONTEXT (expr) == m_fun.decl);
break;
case SSA_NAME:
{
if (tree var = SSA_NAME_VAR (expr))
{
if (DECL_P (var))
- gcc_assert (DECL_CONTEXT (var) == m_fun->decl);
+ gcc_assert (DECL_CONTEXT (var) == m_fun.decl);
}
else if (ctxt)
if (const extrinsic_state *ext_state = ctxt->get_ext_state ())
@@ -1351,7 +1351,7 @@ frame_region::get_region_for_local (region_model_manager *mgr,
const gimple *def_stmt = SSA_NAME_DEF_STMT (expr);
const supernode *snode
= sg->get_supernode_for_stmt (def_stmt);
- gcc_assert (snode->get_function () == m_fun);
+ gcc_assert (snode->get_function () == &m_fun);
}
}
break;
@@ -305,11 +305,10 @@ public:
/* A support class for uniquifying instances of frame_region. */
struct key_t
{
- key_t (const frame_region *calling_frame, function *fun)
- : m_calling_frame (calling_frame), m_fun (fun)
+ key_t (const frame_region *calling_frame, const function &fun)
+ : m_calling_frame (calling_frame), m_fun (&fun)
{
/* calling_frame can be NULL. */
- gcc_assert (fun);
}
hashval_t hash () const
@@ -322,7 +321,8 @@ public:
bool operator== (const key_t &other) const
{
- return (m_calling_frame == other.m_calling_frame && m_fun == other.m_fun);
+ return (m_calling_frame == other.m_calling_frame
+ && m_fun == other.m_fun);
}
void mark_deleted () { m_fun = reinterpret_cast<function *> (1); }
@@ -334,12 +334,12 @@ public:
bool is_empty () const { return m_fun == NULL; }
const frame_region *m_calling_frame;
- function *m_fun;
+ const function *m_fun;
};
frame_region (symbol::id_t id, const region *parent,
const frame_region *calling_frame,
- function *fun, int index)
+ const function &fun, int index)
: space_region (id, parent), m_calling_frame (calling_frame),
m_fun (fun), m_index (index)
{}
@@ -356,8 +356,8 @@ public:
/* Accessors. */
const frame_region *get_calling_frame () const { return m_calling_frame; }
- function *get_function () const { return m_fun; }
- tree get_fndecl () const { return get_function ()->decl; }
+ const function &get_function () const { return m_fun; }
+ tree get_fndecl () const { return get_function ().decl; }
int get_index () const { return m_index; }
int get_stack_depth () const { return m_index + 1; }
@@ -373,7 +373,7 @@ public:
private:
const frame_region *m_calling_frame;
- function *m_fun;
+ const function &m_fun;
int m_index;
/* The regions for the decls within this frame are managed by this
@@ -146,7 +146,8 @@ public:
if (change.is_global_p ()
&& change.m_new_state == m_sm.m_in_signal_handler)
{
- function *handler = change.m_event.get_dest_function ();
+ const function *handler = change.m_event.get_dest_function ();
+ gcc_assert (handler);
return change.formatted_print ("registering %qD as signal handler",
handler->decl);
}
@@ -193,7 +194,7 @@ signal_state_machine::signal_state_machine (logger *logger)
static void
update_model_for_signal_handler (region_model *model,
- function *handler_fun)
+ const function &handler_fun)
{
gcc_assert (model);
/* Purge all state within MODEL. */
@@ -222,7 +223,9 @@ public:
region_model_context *) const final override
{
gcc_assert (eedge);
- update_model_for_signal_handler (model, eedge->m_dest->get_function ());
+ gcc_assert (eedge->m_dest->get_function ());
+ update_model_for_signal_handler (model,
+ *eedge->m_dest->get_function ());
return true;
}
@@ -263,11 +266,11 @@ public:
program_point entering_handler
= program_point::from_function_entry (*ext_state.get_model_manager (),
eg->get_supergraph (),
- handler_fun);
+ *handler_fun);
program_state state_entering_handler (ext_state);
update_model_for_signal_handler (state_entering_handler.m_region_model,
- handler_fun);
+ *handler_fun);
state_entering_handler.m_checker_states[sm_idx]->set_global_state
(m_sm.m_in_signal_handler);
@@ -89,7 +89,7 @@ class gimple_op_visitor : public log_user
public:
gimple_op_visitor (state_purge_map *map,
const function_point &point,
- function *fun)
+ const function &fun)
: log_user (map->get_logger ()),
m_map (map),
m_point (point),
@@ -172,7 +172,7 @@ private:
state_purge_map *m_map;
const function_point &m_point;
- function *m_fun;
+ const function &m_fun;
};
static bool
@@ -214,6 +214,7 @@ state_purge_map::state_purge_map (const supergraph &sg,
FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
{
function *fun = node->get_fun ();
+ gcc_assert (fun);
if (logger)
log ("function: %s", function_name (fun));
tree name;
@@ -225,7 +226,7 @@ state_purge_map::state_purge_map (const supergraph &sg,
if (TREE_CODE (var) == VAR_DECL)
if (VAR_DECL_IS_VIRTUAL_OPERAND (var))
continue;
- m_ssa_map.put (name, new state_purge_per_ssa_name (*this, name, fun));
+ m_ssa_map.put (name, new state_purge_per_ssa_name (*this, name, *fun));
}
}
@@ -241,8 +242,10 @@ state_purge_map::state_purge_map (const supergraph &sg,
unsigned i;
FOR_EACH_VEC_ELT (snode->m_stmts, i, stmt)
{
+ function *fun = snode->get_function ();
+ gcc_assert (fun);
function_point point (function_point::before_stmt (snode, i));
- gimple_op_visitor v (this, point, snode->get_function ());
+ gimple_op_visitor v (this, point, *fun);
walk_stmt_load_store_addr_ops (stmt, &v,
my_load_cb, my_store_cb, my_addr_cb);
}
@@ -272,7 +275,7 @@ state_purge_map::~state_purge_map ()
if necessary. */
state_purge_per_decl &
-state_purge_map::get_or_create_data_for_decl (function *fun, tree decl)
+state_purge_map::get_or_create_data_for_decl (const function &fun, tree decl)
{
if (state_purge_per_decl **slot
= const_cast <decl_map_t&> (m_decl_map).get (decl))
@@ -295,14 +298,14 @@ state_purge_map::get_or_create_data_for_decl (function *fun, tree decl)
state_purge_per_ssa_name::state_purge_per_ssa_name (const state_purge_map &map,
tree name,
- function *fun)
+ const function &fun)
: state_purge_per_tree (fun), m_points_needing_name (), m_name (name)
{
LOG_FUNC (map.get_logger ());
if (map.get_logger ())
{
- map.log ("SSA name: %qE within %qD", name, fun->decl);
+ map.log ("SSA name: %qE within %qD", name, fun.decl);
/* Show def stmt. */
const gimple *def_stmt = SSA_NAME_DEF_STMT (name);
@@ -410,7 +413,7 @@ state_purge_per_ssa_name::state_purge_per_ssa_name (const state_purge_map &map,
if (map.get_logger ())
{
- map.log ("%qE in %qD is needed to process:", name, fun->decl);
+ map.log ("%qE in %qD is needed to process:", name, fun.decl);
/* Log m_points_needing_name, sorting it to avoid churn when comparing
dumps. */
auto_vec<function_point> points;
@@ -472,7 +475,7 @@ state_purge_per_ssa_name::add_to_worklist (const function_point &point,
logger->end_log_line ();
}
- gcc_assert (point.get_function () == get_function ());
+ gcc_assert (point.get_function () == &get_function ());
if (point.get_from_edge ())
gcc_assert (point.get_from_edge ()->get_kind () == SUPEREDGE_CFG_EDGE);
@@ -678,7 +681,7 @@ state_purge_per_ssa_name::process_point (const function_point &point,
state_purge_per_decl::state_purge_per_decl (const state_purge_map &map,
tree decl,
- function *fun)
+ const function &fun)
: state_purge_per_tree (fun),
m_decl (decl)
{
@@ -794,7 +797,7 @@ state_purge_per_decl::add_to_worklist (const function_point &point,
logger->end_log_line ();
}
- gcc_assert (point.get_function () == get_function ());
+ gcc_assert (point.get_function () == &get_function ());
if (point.get_from_edge ())
gcc_assert (point.get_from_edge ()->get_kind () == SUPEREDGE_CFG_EDGE);
@@ -1192,7 +1195,7 @@ state_purge_annotator::print_needed (graphviz_out *gv,
{
tree name = (*iter).first;
state_purge_per_ssa_name *per_name_data = (*iter).second;
- if (per_name_data->get_function () == point.get_function ())
+ if (&per_name_data->get_function () == point.get_function ())
{
if (per_name_data->needed_at_point_p (point))
needed.safe_push (name);
@@ -1206,7 +1209,7 @@ state_purge_annotator::print_needed (graphviz_out *gv,
{
tree decl = (*iter).first;
state_purge_per_decl *per_decl_data = (*iter).second;
- if (per_decl_data->get_function () == point.get_function ())
+ if (&per_decl_data->get_function () == point.get_function ())
{
if (per_decl_data->needed_at_point_p (point))
needed.safe_push (decl);
@@ -112,7 +112,8 @@ public:
return NULL;
}
- state_purge_per_decl &get_or_create_data_for_decl (function *fun, tree decl);
+ state_purge_per_decl &
+ get_or_create_data_for_decl (const function &fun, tree decl);
const supergraph &get_sg () const { return m_sg; }
@@ -135,19 +136,19 @@ private:
class state_purge_per_tree
{
public:
- function *get_function () const { return m_fun; }
- tree get_fndecl () const { return m_fun->decl; }
+ const function &get_function () const { return m_fun; }
+ tree get_fndecl () const { return m_fun.decl; }
protected:
typedef hash_set<function_point> point_set_t;
- state_purge_per_tree (function *fun)
+ state_purge_per_tree (const function &fun)
: m_fun (fun)
{
}
private:
- function *m_fun;
+ const function &m_fun;
};
/* The part of a state_purge_map relating to a specific SSA name.
@@ -162,7 +163,7 @@ class state_purge_per_ssa_name : public state_purge_per_tree
public:
state_purge_per_ssa_name (const state_purge_map &map,
tree name,
- function *fun);
+ const function &fun);
bool needed_at_point_p (const function_point &point) const;
@@ -194,7 +195,7 @@ class state_purge_per_decl : public state_purge_per_tree
public:
state_purge_per_decl (const state_purge_map &map,
tree decl,
- function *fun);
+ const function &fun);
bool needed_at_point_p (const function_point &point) const;
@@ -364,6 +364,7 @@ supergraph::dump_dot_to_pp (pretty_printer *pp,
FOR_EACH_FUNCTION_WITH_GIMPLE_BODY (node)
{
function *fun = node->get_fun ();
+ gcc_assert (fun);
const char *funcname = function_name (fun);
gv.println ("subgraph \"cluster_%s\" {",
funcname);
@@ -409,9 +410,9 @@ supergraph::dump_dot_to_pp (pretty_printer *pp,
/* Add an invisible edge from ENTRY to EXIT, to improve the graph layout. */
pp_string (pp, "\t");
- get_node_for_function_entry (fun)->dump_dot_id (pp);
+ get_node_for_function_entry (*fun)->dump_dot_id (pp);
pp_string (pp, ":s -> ");
- get_node_for_function_exit (fun)->dump_dot_id (pp);
+ get_node_for_function_exit (*fun)->dump_dot_id (pp);
pp_string (pp, ":n [style=\"invis\",constraint=true];\n");
/* Terminate per-function "subgraph" */
@@ -111,14 +111,14 @@ public:
supergraph (logger *logger);
~supergraph ();
- supernode *get_node_for_function_entry (function *fun) const
+ supernode *get_node_for_function_entry (const function &fun) const
{
- return get_node_for_block (ENTRY_BLOCK_PTR_FOR_FN (fun));
+ return get_node_for_block (ENTRY_BLOCK_PTR_FOR_FN (&fun));
}
- supernode *get_node_for_function_exit (function *fun) const
+ supernode *get_node_for_function_exit (const function &fun) const
{
- return get_node_for_block (EXIT_BLOCK_PTR_FOR_FN (fun));
+ return get_node_for_block (EXIT_BLOCK_PTR_FOR_FN (&fun));
}
supernode *get_node_for_block (basic_block bb) const
@@ -6391,7 +6391,7 @@ fndecl_name (tree fndecl)
/* Returns the name of function FN. */
const char *
-function_name (struct function *fn)
+function_name (const function *fn)
{
tree fndecl = (fn == NULL) ? NULL : fn->decl;
return fndecl_name (fndecl);
@@ -730,7 +730,7 @@ extern poly_int64 get_stack_dynamic_offset ();
/* Returns the name of the current function. */
extern const char *fndecl_name (tree);
-extern const char *function_name (struct function *);
+extern const char *function_name (const function *);
extern const char *current_function_name (void);
extern void used_types_insert (tree);
new file mode 100644
@@ -0,0 +1,20 @@
+/* Verify we don't ICE on this case with these options. */
+
+/* { dg-additional-options "-fanalyzer-call-summaries --param=analyzer-max-svalue-depth=0 -Wno-analyzer-symbol-too-complex" } */
+
+int foo_i;
+void bar() {}
+void foo() {
+ if (foo_i)
+ bar();
+ else
+ goto f1;
+ bar();
+f1:
+ bar();
+}
+int main() {
+ foo();
+ foo();
+ return 0;
+}
PR analyzer/114159 reports an ICE inside playback of call summaries for very low values of --param=analyzer-max-svalue-depth=VAL. Root cause is that call_summary_edge_info's ctor tries to evaluate the function ptr of a gimple call stmt and assumes it gets a function *, but with low values of --param=analyzer-max-svalue-depth=VAL we get back an UNKNOWN svalue, rather than a pointer to a specific function. Fix by adding a new call_info ctor that passes a specific const function & from the call_summary_edge_info, rather than trying to compute the function. In doing so, I noticed that the analyzer was using "function *" despite not modifying functions, and was sloppy about can-be-null versus must-be-non-null function pointers, so I "constified" the function, and converted the many places where the function must be non-null to be "const function &". Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. Successful run of analyzer integration tests on x86_64-pc-linux-gnu. Pushed to trunk as r14-9245-gc0d8a64e72324d. gcc/analyzer/ChangeLog: PR analyzer/114159 * analyzer.cc: Include "tree-dfa.h". (get_ssa_default_def): New decl. * analyzer.h (get_ssa_default_def): New. * call-info.cc (call_info::call_info): New ctor taking an explicit called_fn. * call-info.h (call_info::call_info): Likewise. * call-summary.cc (call_summary_replay::call_summary_replay): Convert param from function * to const function &. * call-summary.h (call_summary_replay::call_summary_replay): Likewise. * checker-event.h (state_change_event::get_dest_function): Constify return value. * engine.cc (point_and_state::validate): Update for conversion to const function &. (exploded_node::on_stmt): Likewise. (call_summary_edge_info::call_summary_edge_info): Likewise. Pass in called_fn to call_info ctor. (exploded_node::replay_call_summaries): Update for conversion to const function &. Convert per_function_data from * to &. (exploded_node::replay_call_summary): Update for conversion to const function &. (exploded_graph::add_function_entry): Likewise. (toplevel_function_p): Likewise. (add_tainted_args_callback): Likewise. (exploded_graph::build_initial_worklist): Likewise. (exploded_graph::maybe_create_dynamic_call): Likewise. (maybe_update_for_edge): Likewise. (exploded_graph::on_escaped_function): Likewise. * exploded-graph.h (exploded_node::replay_call_summaries): Likewise. (exploded_node::replay_call_summary): Likewise. (exploded_graph::add_function_entry): Likewise. * program-point.cc (function_point::from_function_entry): Likewise. (program_point::from_function_entry): Likewise. * program-point.h (function_point::from_function_entry): Likewise. (program_point::from_function_entry): Likewise. * program-state.cc (program_state::push_frame): Likewise. (program_state::get_current_function): Constify return type. * program-state.h (program_state::push_frame): Update for conversion to const function &. (program_state::get_current_function): Likewise. * region-model-manager.cc (region_model_manager::get_frame_region): Likewise. * region-model-manager.h (region_model_manager::get_frame_region): Likewise. * region-model.cc (region_model::called_from_main_p): Likewise. (region_model::update_for_gcall): Likewise. (region_model::push_frame): Likewise. (region_model::get_current_function): Constify return type. (region_model::pop_frame): Update for conversion to const function &. (selftest::test_stack_frames): Likewise. (selftest::test_get_representative_path_var): Likewise. (selftest::test_state_merging): Likewise. (selftest::test_alloca): Likewise. * region-model.h (region_model::push_frame): Likewise. (region_model::get_current_function): Likewise. * region.cc (frame_region::dump_to_pp): Likewise. (frame_region::get_region_for_local): Likewise. * region.h (class frame_region): Likewise. * sm-signal.cc (signal_unsafe_call::describe_state_change): Likewise. (update_model_for_signal_handler): Likewise. (signal_delivery_edge_info_t::update_model): Likewise. (register_signal_handler::impl_transition): Likewise. * state-purge.cc (class gimple_op_visitor): Likewise. (state_purge_map::state_purge_map): Likewise. (state_purge_map::get_or_create_data_for_decl): Likewise. (state_purge_per_ssa_name::state_purge_per_ssa_name): Likewise. (state_purge_per_ssa_name::add_to_worklist): Likewise. (state_purge_per_ssa_name::process_point): Likewise. (state_purge_per_decl::add_to_worklist): Likewise. (state_purge_annotator::print_needed): Likewise. * state-purge.h (state_purge_map::get_or_create_data_for_decl): Likewise. (class state_purge_per_tree): Likewise. (class state_purge_per_ssa_name): Likewise. (class state_purge_per_decl): Likewise. * supergraph.cc (supergraph::dump_dot_to_pp): Likewise. * supergraph.h (supergraph::get_node_for_function_entry): Likewise. (supergraph::get_node_for_function_exit): Likewise. gcc/ChangeLog: PR analyzer/114159 * function.cc (function_name): Make param const. * function.h (function_name): Likewise. gcc/testsuite/ChangeLog: PR analyzer/114159 * c-c++-common/analyzer/call-summaries-pr114159.c: New test. Signed-off-by: David Malcolm <dmalcolm@redhat.com> --- gcc/analyzer/analyzer.cc | 9 ++ gcc/analyzer/analyzer.h | 3 + gcc/analyzer/call-info.cc | 8 ++ gcc/analyzer/call-info.h | 1 + gcc/analyzer/call-summary.cc | 6 +- gcc/analyzer/call-summary.h | 2 +- gcc/analyzer/checker-event.h | 2 +- gcc/analyzer/engine.cc | 83 ++++++++++--------- gcc/analyzer/exploded-graph.h | 8 +- gcc/analyzer/program-point.cc | 4 +- gcc/analyzer/program-point.h | 4 +- gcc/analyzer/program-state.cc | 4 +- gcc/analyzer/program-state.h | 4 +- gcc/analyzer/region-model-manager.cc | 2 +- gcc/analyzer/region-model-manager.h | 2 +- gcc/analyzer/region-model.cc | 42 +++++----- gcc/analyzer/region-model.h | 4 +- gcc/analyzer/region.cc | 10 +-- gcc/analyzer/region.h | 18 ++-- gcc/analyzer/sm-signal.cc | 13 +-- gcc/analyzer/state-purge.cc | 29 ++++--- gcc/analyzer/state-purge.h | 15 ++-- gcc/analyzer/supergraph.cc | 5 +- gcc/analyzer/supergraph.h | 8 +- gcc/function.cc | 2 +- gcc/function.h | 2 +- .../analyzer/call-summaries-pr114159.c | 20 +++++ 27 files changed, 181 insertions(+), 129 deletions(-) create mode 100644 gcc/testsuite/c-c++-common/analyzer/call-summaries-pr114159.c