analyzer: Fix PR analyzer/101980
2021-08-19 Ankur Saini <arsenic@sourceware.org> gcc/analyzer/ChangeLog: PR analyzer/101980 * diagnostic-manager.cc (diagnostic_manager::prune_for_sm_diagnostic)<case EK_CALL_EDGE>: Use caller_model only when the supergraph_edge doesn't exixt. (diagnostic_manager::prune_for_sm_diagnostic)<case EK_RETURN_EDGE>: Likewise. * engine.cc (exploded_graph::create_dynamic_call): Rename to... (exploded_graph::maybe_create_dynamic_call): ...this, return call creation status. (exploded_graph::process_node): Handle calls which were not dynamically discovered. * exploded-graph.h (exploded_graph::create_dynamic_call): Rename to... (exploded_graph::maybe_create_dynamic_call): ...this. * region-model.cc (region_model::update_for_gcall): New param, use it to push call to frame. (region_model::update_for_call_superedge): Pass callee function to update_for_gcall. * region-model.h (region_model::update_for_gcall): New param. gcc/testsuite/ChangeLog: PR analyzer/101980 * gcc.dg/analyzer/function-ptr-2.c : Add issue for double 'free'. * gcc.dg/analyzer/malloc-callbacks.c : Fix xfail testcase.
This commit is contained in:
parent
7c9e164583
commit
e92d0ff6b5
@ -2099,7 +2099,22 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
|
||||
= event->m_eedge.m_src->get_state ().m_region_model;
|
||||
tree callee_var = callee_model->get_representative_tree (sval);
|
||||
callsite_expr expr;
|
||||
tree caller_var = caller_model->get_representative_tree (sval);
|
||||
|
||||
tree caller_var;
|
||||
if(event->m_sedge)
|
||||
{
|
||||
const callgraph_superedge& cg_superedge
|
||||
= event->get_callgraph_superedge ();
|
||||
if (cg_superedge.m_cedge)
|
||||
caller_var
|
||||
= cg_superedge.map_expr_from_callee_to_caller (callee_var,
|
||||
&expr);
|
||||
else
|
||||
callee_var = callee_model->get_representative_tree (sval);
|
||||
}
|
||||
else
|
||||
caller_var = caller_model->get_representative_tree (sval);
|
||||
|
||||
if (caller_var)
|
||||
{
|
||||
if (get_logger ())
|
||||
@ -2121,11 +2136,28 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
|
||||
if (sval)
|
||||
{
|
||||
return_event *event = (return_event *)base_event;
|
||||
const region_model *caller_model
|
||||
= event->m_eedge.m_dest->get_state ().m_region_model;
|
||||
tree caller_var = caller_model->get_representative_tree (sval);
|
||||
const region_model *callee_model
|
||||
= event->m_eedge.m_src->get_state ().m_region_model;
|
||||
callsite_expr expr;
|
||||
|
||||
const region_model *callee_model
|
||||
= event->m_eedge.m_src->get_state ().m_region_model;
|
||||
tree callee_var = callee_model->get_representative_tree (sval);
|
||||
tree callee_var;
|
||||
if (event->m_sedge)
|
||||
{
|
||||
const callgraph_superedge& cg_superedge
|
||||
= event->get_callgraph_superedge ();
|
||||
if (cg_superedge.m_cedge)
|
||||
callee_var
|
||||
= cg_superedge.map_expr_from_caller_to_callee (caller_var,
|
||||
&expr);
|
||||
else
|
||||
callee_var = callee_model->get_representative_tree (sval);
|
||||
}
|
||||
else
|
||||
callee_var = callee_model->get_representative_tree (sval);
|
||||
|
||||
if (callee_var)
|
||||
{
|
||||
if (get_logger ())
|
||||
|
@ -3033,14 +3033,14 @@ state_change_requires_new_enode_p (const program_state &old_state,
|
||||
Some example such calls are dynamically dispatched calls to virtual
|
||||
functions or calls that happen via function pointer. */
|
||||
|
||||
void
|
||||
exploded_graph::create_dynamic_call (const gcall *call,
|
||||
tree fn_decl,
|
||||
exploded_node *node,
|
||||
program_state next_state,
|
||||
program_point &next_point,
|
||||
uncertainty_t *uncertainty,
|
||||
logger *logger)
|
||||
bool
|
||||
exploded_graph::maybe_create_dynamic_call (const gcall *call,
|
||||
tree fn_decl,
|
||||
exploded_node *node,
|
||||
program_state next_state,
|
||||
program_point &next_point,
|
||||
uncertainty_t *uncertainty,
|
||||
logger *logger)
|
||||
{
|
||||
LOG_FUNC (logger);
|
||||
|
||||
@ -3049,8 +3049,8 @@ exploded_graph::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,
|
||||
@ -3075,8 +3075,10 @@ exploded_graph::create_dynamic_call (const gcall *call,
|
||||
if (enode)
|
||||
add_edge (node,enode, NULL,
|
||||
new dynamic_call_info_t (call));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/* The core of exploded_graph::process_worklist (the main analysis loop),
|
||||
@ -3338,22 +3340,23 @@ exploded_graph::process_node (exploded_node *node)
|
||||
point.get_stmt());
|
||||
|
||||
region_model *model = state.m_region_model;
|
||||
bool call_discovered = false;
|
||||
|
||||
if (tree fn_decl = model->get_fndecl_for_call(call,&ctxt))
|
||||
create_dynamic_call (call,
|
||||
fn_decl,
|
||||
node,
|
||||
next_state,
|
||||
next_point,
|
||||
&uncertainty,
|
||||
logger);
|
||||
else
|
||||
call_discovered = maybe_create_dynamic_call (call,
|
||||
fn_decl,
|
||||
node,
|
||||
next_state,
|
||||
next_point,
|
||||
&uncertainty,
|
||||
logger);
|
||||
if (!call_discovered)
|
||||
{
|
||||
/* An unknown function was called at this point, in such
|
||||
case, don't terminate the analysis of the current
|
||||
function.
|
||||
/* An unknown function or a special function was called
|
||||
at this point, in such case, don't terminate the
|
||||
analysis of the current function.
|
||||
|
||||
The analyzer handles calls to unknown functions while
|
||||
The analyzer handles calls to such functions while
|
||||
analysing the stmt itself, so the the function call
|
||||
must have been handled by the anlyzer till now. */
|
||||
exploded_node *next
|
||||
|
@ -816,13 +816,13 @@ public:
|
||||
bool maybe_process_run_of_before_supernode_enodes (exploded_node *node);
|
||||
void process_node (exploded_node *node);
|
||||
|
||||
void create_dynamic_call (const gcall *call,
|
||||
tree fn_decl,
|
||||
exploded_node *node,
|
||||
program_state next_state,
|
||||
program_point &next_point,
|
||||
uncertainty_t *uncertainty,
|
||||
logger *logger);
|
||||
bool maybe_create_dynamic_call (const gcall *call,
|
||||
tree fn_decl,
|
||||
exploded_node *node,
|
||||
program_state next_state,
|
||||
program_point &next_point,
|
||||
uncertainty_t *uncertainty,
|
||||
logger *logger);
|
||||
|
||||
exploded_node *get_or_create_node (const program_point &point,
|
||||
const program_state &state,
|
||||
|
@ -3178,7 +3178,8 @@ region_model::maybe_update_for_edge (const superedge &edge,
|
||||
|
||||
void
|
||||
region_model::update_for_gcall (const gcall *call_stmt,
|
||||
region_model_context *ctxt)
|
||||
region_model_context *ctxt,
|
||||
function *callee)
|
||||
{
|
||||
/* Build a vec of argument svalues, using the current top
|
||||
frame for resolving tree expressions. */
|
||||
@ -3190,10 +3191,14 @@ region_model::update_for_gcall (const gcall *call_stmt,
|
||||
arg_svals.quick_push (get_rvalue (arg, ctxt));
|
||||
}
|
||||
|
||||
/* Get the function * from the call. */
|
||||
tree fn_decl = get_fndecl_for_call (call_stmt,ctxt);
|
||||
function *fun = DECL_STRUCT_FUNCTION (fn_decl);
|
||||
push_frame (fun, &arg_svals, ctxt);
|
||||
if(!callee)
|
||||
{
|
||||
/* Get the function * from the gcall. */
|
||||
tree fn_decl = get_fndecl_for_call (call_stmt,ctxt);
|
||||
callee = DECL_STRUCT_FUNCTION (fn_decl);
|
||||
}
|
||||
|
||||
push_frame (callee, &arg_svals, ctxt);
|
||||
}
|
||||
|
||||
/* Pop the top-most frame_region from the stack, and copy the return
|
||||
@ -3228,7 +3233,7 @@ region_model::update_for_call_superedge (const call_superedge &call_edge,
|
||||
region_model_context *ctxt)
|
||||
{
|
||||
const gcall *call_stmt = call_edge.get_call_stmt ();
|
||||
update_for_gcall (call_stmt,ctxt);
|
||||
update_for_gcall (call_stmt, ctxt, call_edge.get_callee_function ());
|
||||
}
|
||||
|
||||
/* Extract calling information from the return superedge and update the model
|
||||
|
@ -609,7 +609,8 @@ class region_model
|
||||
rejected_constraint **out);
|
||||
|
||||
void update_for_gcall (const gcall *call_stmt,
|
||||
region_model_context *ctxt);
|
||||
region_model_context *ctxt,
|
||||
function *callee = NULL);
|
||||
|
||||
void update_for_return_gcall (const gcall *call_stmt,
|
||||
region_model_context *ctxt);
|
||||
|
@ -6,9 +6,10 @@ typedef void (*fn_ptr_t) (void *);
|
||||
void
|
||||
calls_free (void *victim)
|
||||
{
|
||||
free (victim);
|
||||
free (victim); /* { dg-warning "double-'free' of 'victim'" } */
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
no_op (void *ptr)
|
||||
{
|
||||
@ -25,7 +26,6 @@ void test_1 (void *ptr)
|
||||
fn_ptr (ptr);
|
||||
fn_ptr (ptr);
|
||||
}
|
||||
// TODO: issue a double-'free' warning at 2nd call to fn_ptr.
|
||||
|
||||
/* As above, but with an extra indirection to try to thwart
|
||||
the optimizer. */
|
||||
@ -41,4 +41,3 @@ void test_2 (void *ptr, fn_ptr_t *fn_ptr)
|
||||
(*fn_ptr) (ptr);
|
||||
(*fn_ptr) (ptr);
|
||||
}
|
||||
// TODO: issue a double-'free' warning at 2nd call to fn_ptr.
|
||||
|
@ -69,7 +69,7 @@ int *test_5 (void)
|
||||
static void __attribute__((noinline))
|
||||
called_by_test_6a (void *ptr)
|
||||
{
|
||||
free (ptr); /* { dg-warning "double-'free'" "" { xfail *-*-* } } */
|
||||
free (ptr); /* { dg-warning "double-'free'"} */
|
||||
}
|
||||
|
||||
static deallocator_t __attribute__((noinline))
|
||||
|
Loading…
Reference in New Issue
Block a user