aboutsummaryrefslogtreecommitdiff
path: root/gcc/analyzer/region-model.cc
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2024-02-29 17:57:08 -0500
committerDavid Malcolm <dmalcolm@redhat.com>2024-02-29 17:57:08 -0500
commitc0d8a64e72324d1c2981da21a66394bf8f7a2889 (patch)
tree8cef0240a8a9b0234a8a4c547f83e573e44f4fce /gcc/analyzer/region-model.cc
parentcda3836161834c5f21f264885891fe4d0ce90da1 (diff)
downloadgcc-c0d8a64e72324d1c2981da21a66394bf8f7a2889.zip
gcc-c0d8a64e72324d1c2981da21a66394bf8f7a2889.tar.gz
gcc-c0d8a64e72324d1c2981da21a66394bf8f7a2889.tar.bz2
analyzer: fix ICE in call summarization [PR114159]
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 &". 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>
Diffstat (limited to 'gcc/analyzer/region-model.cc')
-rw-r--r--gcc/analyzer/region-model.cc42
1 files changed, 22 insertions, 20 deletions
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 6ab9174..33a4584 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -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);