aboutsummaryrefslogtreecommitdiff
path: root/gcc/analyzer/engine.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/engine.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/engine.cc')
-rw-r--r--gcc/analyzer/engine.cc83
1 files changed, 42 insertions, 41 deletions
diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc
index 44ff20c..ad310b4 100644
--- a/gcc/analyzer/engine.cc
+++ b/gcc/analyzer/engine.cc
@@ -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)