diff options
author | David Malcolm <dmalcolm@redhat.com> | 2024-02-29 17:57:08 -0500 |
---|---|---|
committer | David Malcolm <dmalcolm@redhat.com> | 2024-02-29 17:57:08 -0500 |
commit | c0d8a64e72324d1c2981da21a66394bf8f7a2889 (patch) | |
tree | 8cef0240a8a9b0234a8a4c547f83e573e44f4fce /gcc/analyzer/region-model.cc | |
parent | cda3836161834c5f21f264885891fe4d0ce90da1 (diff) | |
download | gcc-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.cc | 42 |
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); |