mirror of
git://gcc.gnu.org/git/gcc.git
synced 2025-04-06 02:20:34 +08:00
analyzer: use ultimate alias target at calls (PR 93288)
PR analyzer/93288 reports an ICE in a C++ testcase when calling a constructor. The issue is that when building the supergraph, we encounter the cgraph edge to "__ct_comp ", the DECL_COMPLETE_CONSTRUCTOR_P, and this node's DECL_STRUCT_FUNCTION has a NULL CFG, which the analyzer reads through, leading to the ICE. This patch reworks function and fndecl lookup at calls throughout the analyzer so that it looks for the ultimate_alias_target of the callee. In the case above, this means using the "__ct_base " for the ctor, which has a CFG, fixing the ICE. Getting this right allows for some simple C++ cases involving ctors to work, so the patch also adds some test coverage for that. gcc/analyzer/ChangeLog: PR analyzer/93288 * analysis-plan.cc (analysis_plan::use_summary_p): Look through the ultimate_alias_target when getting the called function. * engine.cc (exploded_node::on_stmt): Rename second "ctxt" to "sm_ctxt". Use the region_model's get_fndecl_for_call rather than gimple_call_fndecl. * region-model.cc (region_model::get_fndecl_for_call): Use ultimate_alias_target on fndecl. * supergraph.cc (get_ultimate_function_for_cgraph_edge): New function. (supergraph_call_edge): Use it when rejecting edges without functions. (supergraph::supergraph): Use it to get the function for the cgraph_edge when building interprocedural superedges. (callgraph_superedge::get_callee_function): Use it. * supergraph.h (supergraph::get_num_snodes): Make param const. (supergraph::function_to_num_snodes_t): Make first type param const. gcc/testsuite/ChangeLog: PR analyzer/93288 * g++.dg/analyzer/malloc.C: Add test coverage for a double-free called in a constructor. * g++.dg/analyzer/pr93288.C: New test.
This commit is contained in:
parent
d9e067f98b
commit
91f993b7e3
@ -1,3 +1,24 @@
|
||||
2020-02-11 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
PR analyzer/93288
|
||||
* analysis-plan.cc (analysis_plan::use_summary_p): Look through
|
||||
the ultimate_alias_target when getting the called function.
|
||||
* engine.cc (exploded_node::on_stmt): Rename second "ctxt" to
|
||||
"sm_ctxt". Use the region_model's get_fndecl_for_call rather than
|
||||
gimple_call_fndecl.
|
||||
* region-model.cc (region_model::get_fndecl_for_call): Use
|
||||
ultimate_alias_target on fndecl.
|
||||
* supergraph.cc (get_ultimate_function_for_cgraph_edge): New
|
||||
function.
|
||||
(supergraph_call_edge): Use it when rejecting edges without
|
||||
functions.
|
||||
(supergraph::supergraph): Use it to get the function for the
|
||||
cgraph_edge when building interprocedural superedges.
|
||||
(callgraph_superedge::get_callee_function): Use it.
|
||||
* supergraph.h (supergraph::get_num_snodes): Make param const.
|
||||
(supergraph::function_to_num_snodes_t): Make first type param
|
||||
const.
|
||||
|
||||
2020-02-11 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
PR analyzer/93374
|
||||
|
@ -120,7 +120,11 @@ analysis_plan::use_summary_p (const cgraph_edge *edge) const
|
||||
|
||||
/* Require the callee to be sufficiently complex to be worth
|
||||
summarizing. */
|
||||
if ((int)m_sg.get_num_snodes (callee->get_fun ())
|
||||
const function *fun
|
||||
= const_cast <cgraph_node *> (callee)->ultimate_alias_target ()->get_fun ();
|
||||
/* TODO(stage1): can ultimate_alias_target be made const? */
|
||||
|
||||
if ((int)m_sg.get_num_snodes (fun)
|
||||
< param_analyzer_min_snodes_for_call_summary)
|
||||
return false;
|
||||
|
||||
|
@ -1044,19 +1044,19 @@ exploded_node::on_stmt (exploded_graph &eg,
|
||||
const sm_state_map *old_smap
|
||||
= old_state.m_checker_states[sm_idx];
|
||||
sm_state_map *new_smap = state->m_checker_states[sm_idx];
|
||||
impl_sm_context ctxt (eg, sm_idx, sm, this, &old_state, state,
|
||||
change,
|
||||
old_smap, new_smap);
|
||||
impl_sm_context sm_ctxt (eg, sm_idx, sm, this, &old_state, state,
|
||||
change,
|
||||
old_smap, new_smap);
|
||||
/* Allow the state_machine to handle the stmt. */
|
||||
if (sm.on_stmt (&ctxt, snode, stmt))
|
||||
if (sm.on_stmt (&sm_ctxt, snode, stmt))
|
||||
unknown_side_effects = false;
|
||||
else
|
||||
{
|
||||
/* For those stmts that were not handled by the state machine. */
|
||||
if (const gcall *call = dyn_cast <const gcall *> (stmt))
|
||||
{
|
||||
tree callee_fndecl = gimple_call_fndecl (call);
|
||||
// TODO: maybe we can be smarter about handling function pointers?
|
||||
tree callee_fndecl
|
||||
= state->m_region_model->get_fndecl_for_call (call, &ctxt);
|
||||
|
||||
if (!fndecl_has_gimple_body_p (callee_fndecl))
|
||||
new_smap->purge_for_unknown_fncall (eg, sm, call, callee_fndecl,
|
||||
|
@ -6676,7 +6676,10 @@ region_model::get_fndecl_for_call (const gcall *call,
|
||||
if (code)
|
||||
{
|
||||
tree fn_decl = code->get_tree_for_child_region (fn_rid);
|
||||
return fn_decl;
|
||||
const cgraph_node *ultimate_node
|
||||
= cgraph_node::get (fn_decl)->ultimate_alias_target ();
|
||||
if (ultimate_node)
|
||||
return ultimate_node->decl;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -56,6 +56,18 @@ along with GCC; see the file COPYING3. If not see
|
||||
|
||||
namespace ana {
|
||||
|
||||
/* Get the function of the ultimate alias target being called at EDGE,
|
||||
if any. */
|
||||
|
||||
static function *
|
||||
get_ultimate_function_for_cgraph_edge (cgraph_edge *edge)
|
||||
{
|
||||
cgraph_node *ultimate_node = edge->callee->ultimate_alias_target ();
|
||||
if (!ultimate_node)
|
||||
return NULL;
|
||||
return ultimate_node->get_fun ();
|
||||
}
|
||||
|
||||
/* Get the cgraph_edge, but only if there's an underlying function body. */
|
||||
|
||||
cgraph_edge *
|
||||
@ -69,7 +81,7 @@ supergraph_call_edge (function *fun, gimple *stmt)
|
||||
return NULL;
|
||||
if (!edge->callee)
|
||||
return NULL; /* e.g. for a function pointer. */
|
||||
if (!edge->callee->get_fun ())
|
||||
if (!get_ultimate_function_for_cgraph_edge (edge))
|
||||
return NULL;
|
||||
return edge;
|
||||
}
|
||||
@ -178,8 +190,10 @@ supergraph::supergraph (logger *logger)
|
||||
{
|
||||
cgraph_edge *edge = (*iter).first;
|
||||
supernode *caller_prev_supernode = (*iter).second;
|
||||
basic_block callee_cfg_block
|
||||
= ENTRY_BLOCK_PTR_FOR_FN (edge->callee->get_fun ());
|
||||
function* callee_fn = get_ultimate_function_for_cgraph_edge (edge);
|
||||
if (!callee_fn || !callee_fn->cfg)
|
||||
continue;
|
||||
basic_block callee_cfg_block = ENTRY_BLOCK_PTR_FOR_FN (callee_fn);
|
||||
supernode *callee_supernode
|
||||
= *m_bb_to_initial_node.get (callee_cfg_block);
|
||||
call_superedge *sedge
|
||||
@ -199,8 +213,10 @@ supergraph::supergraph (logger *logger)
|
||||
{
|
||||
cgraph_edge *edge = (*iter).first;
|
||||
supernode *caller_next_supernode = (*iter).second;
|
||||
basic_block callee_cfg_block
|
||||
= EXIT_BLOCK_PTR_FOR_FN (edge->callee->get_fun ());
|
||||
function* callee_fn = get_ultimate_function_for_cgraph_edge (edge);
|
||||
if (!callee_fn || !callee_fn->cfg)
|
||||
continue;
|
||||
basic_block callee_cfg_block = EXIT_BLOCK_PTR_FOR_FN (callee_fn);
|
||||
supernode *callee_supernode
|
||||
= *m_bb_to_initial_node.get (callee_cfg_block);
|
||||
return_superedge *sedge
|
||||
@ -840,7 +856,7 @@ callgraph_superedge::dump_label_to_pp (pretty_printer *pp,
|
||||
function *
|
||||
callgraph_superedge::get_callee_function () const
|
||||
{
|
||||
return m_cedge->callee->get_fun ();
|
||||
return get_ultimate_function_for_cgraph_edge (m_cedge);
|
||||
}
|
||||
|
||||
/* Get the calling function at this interprocedural call/return edge. */
|
||||
|
@ -156,7 +156,7 @@ public:
|
||||
return m_nodes[idx];
|
||||
}
|
||||
|
||||
unsigned get_num_snodes (function *fun) const
|
||||
unsigned get_num_snodes (const function *fun) const
|
||||
{
|
||||
function_to_num_snodes_t &map
|
||||
= const_cast <function_to_num_snodes_t &>(m_function_to_num_snodes);
|
||||
@ -201,7 +201,7 @@ private:
|
||||
typedef ordered_hash_map<gimple *, supernode *> stmt_to_node_t;
|
||||
stmt_to_node_t m_stmt_to_node_t;
|
||||
|
||||
typedef hash_map<function *, unsigned> function_to_num_snodes_t;
|
||||
typedef hash_map<const function *, unsigned> function_to_num_snodes_t;
|
||||
function_to_num_snodes_t m_function_to_num_snodes;
|
||||
};
|
||||
|
||||
|
@ -1,3 +1,10 @@
|
||||
2020-02-11 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
PR analyzer/93288
|
||||
* g++.dg/analyzer/malloc.C: Add test coverage for a double-free
|
||||
called in a constructor.
|
||||
* g++.dg/analyzer/pr93288.C: New test.
|
||||
|
||||
2020-02-11 David Malcolm <dmalcolm@redhat.com>
|
||||
|
||||
PR analyzer/93212
|
||||
|
@ -7,3 +7,19 @@ void test_1 (void *ptr)
|
||||
free (ptr);
|
||||
free (ptr); /* { dg-warning "double-'free' of 'ptr'" } */
|
||||
}
|
||||
|
||||
/* Test of double-free in ctor. */
|
||||
|
||||
struct s2
|
||||
{
|
||||
s2 (void *v)
|
||||
{
|
||||
free (v); // { dg-warning "double-'free' of 'v'" }
|
||||
}
|
||||
};
|
||||
|
||||
void test_2 (void *ptr)
|
||||
{
|
||||
free (ptr); // { dg-message "first 'free' here" }
|
||||
s2 a (ptr); // { dg-message "passing freed pointer 'ptr' in call to 's2::s2' from 'test_2'" }
|
||||
}
|
||||
|
8
gcc/testsuite/g++.dg/analyzer/pr93288.C
Normal file
8
gcc/testsuite/g++.dg/analyzer/pr93288.C
Normal file
@ -0,0 +1,8 @@
|
||||
// { dg-do compile }
|
||||
|
||||
struct a {
|
||||
a();
|
||||
};
|
||||
class foo {
|
||||
a b;
|
||||
} c;
|
Loading…
x
Reference in New Issue
Block a user