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;
|
= event->m_eedge.m_src->get_state ().m_region_model;
|
||||||
tree callee_var = callee_model->get_representative_tree (sval);
|
tree callee_var = callee_model->get_representative_tree (sval);
|
||||||
callsite_expr expr;
|
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 (caller_var)
|
||||||
{
|
{
|
||||||
if (get_logger ())
|
if (get_logger ())
|
||||||
@ -2121,11 +2136,28 @@ diagnostic_manager::prune_for_sm_diagnostic (checker_path *path,
|
|||||||
if (sval)
|
if (sval)
|
||||||
{
|
{
|
||||||
return_event *event = (return_event *)base_event;
|
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;
|
callsite_expr expr;
|
||||||
|
|
||||||
const region_model *callee_model
|
tree callee_var;
|
||||||
= event->m_eedge.m_src->get_state ().m_region_model;
|
if (event->m_sedge)
|
||||||
tree callee_var = callee_model->get_representative_tree (sval);
|
{
|
||||||
|
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 (callee_var)
|
||||||
{
|
{
|
||||||
if (get_logger ())
|
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
|
Some example such calls are dynamically dispatched calls to virtual
|
||||||
functions or calls that happen via function pointer. */
|
functions or calls that happen via function pointer. */
|
||||||
|
|
||||||
void
|
bool
|
||||||
exploded_graph::create_dynamic_call (const gcall *call,
|
exploded_graph::maybe_create_dynamic_call (const gcall *call,
|
||||||
tree fn_decl,
|
tree fn_decl,
|
||||||
exploded_node *node,
|
exploded_node *node,
|
||||||
program_state next_state,
|
program_state next_state,
|
||||||
program_point &next_point,
|
program_point &next_point,
|
||||||
uncertainty_t *uncertainty,
|
uncertainty_t *uncertainty,
|
||||||
logger *logger)
|
logger *logger)
|
||||||
{
|
{
|
||||||
LOG_FUNC (logger);
|
LOG_FUNC (logger);
|
||||||
|
|
||||||
@ -3049,8 +3049,8 @@ exploded_graph::create_dynamic_call (const gcall *call,
|
|||||||
if (fun)
|
if (fun)
|
||||||
{
|
{
|
||||||
const supergraph &sg = this->get_supergraph ();
|
const supergraph &sg = this->get_supergraph ();
|
||||||
supernode * sn_entry = sg.get_node_for_function_entry (fun);
|
supernode *sn_entry = sg.get_node_for_function_entry (fun);
|
||||||
supernode * sn_exit = sg.get_node_for_function_exit (fun);
|
supernode *sn_exit = sg.get_node_for_function_exit (fun);
|
||||||
|
|
||||||
program_point new_point
|
program_point new_point
|
||||||
= program_point::before_supernode (sn_entry,
|
= program_point::before_supernode (sn_entry,
|
||||||
@ -3075,8 +3075,10 @@ exploded_graph::create_dynamic_call (const gcall *call,
|
|||||||
if (enode)
|
if (enode)
|
||||||
add_edge (node,enode, NULL,
|
add_edge (node,enode, NULL,
|
||||||
new dynamic_call_info_t (call));
|
new dynamic_call_info_t (call));
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* The core of exploded_graph::process_worklist (the main analysis loop),
|
/* 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());
|
point.get_stmt());
|
||||||
|
|
||||||
region_model *model = state.m_region_model;
|
region_model *model = state.m_region_model;
|
||||||
|
bool call_discovered = false;
|
||||||
|
|
||||||
if (tree fn_decl = model->get_fndecl_for_call(call,&ctxt))
|
if (tree fn_decl = model->get_fndecl_for_call(call,&ctxt))
|
||||||
create_dynamic_call (call,
|
call_discovered = maybe_create_dynamic_call (call,
|
||||||
fn_decl,
|
fn_decl,
|
||||||
node,
|
node,
|
||||||
next_state,
|
next_state,
|
||||||
next_point,
|
next_point,
|
||||||
&uncertainty,
|
&uncertainty,
|
||||||
logger);
|
logger);
|
||||||
else
|
if (!call_discovered)
|
||||||
{
|
{
|
||||||
/* An unknown function was called at this point, in such
|
/* An unknown function or a special function was called
|
||||||
case, don't terminate the analysis of the current
|
at this point, in such case, don't terminate the
|
||||||
function.
|
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
|
analysing the stmt itself, so the the function call
|
||||||
must have been handled by the anlyzer till now. */
|
must have been handled by the anlyzer till now. */
|
||||||
exploded_node *next
|
exploded_node *next
|
||||||
|
@ -816,13 +816,13 @@ public:
|
|||||||
bool maybe_process_run_of_before_supernode_enodes (exploded_node *node);
|
bool maybe_process_run_of_before_supernode_enodes (exploded_node *node);
|
||||||
void process_node (exploded_node *node);
|
void process_node (exploded_node *node);
|
||||||
|
|
||||||
void create_dynamic_call (const gcall *call,
|
bool maybe_create_dynamic_call (const gcall *call,
|
||||||
tree fn_decl,
|
tree fn_decl,
|
||||||
exploded_node *node,
|
exploded_node *node,
|
||||||
program_state next_state,
|
program_state next_state,
|
||||||
program_point &next_point,
|
program_point &next_point,
|
||||||
uncertainty_t *uncertainty,
|
uncertainty_t *uncertainty,
|
||||||
logger *logger);
|
logger *logger);
|
||||||
|
|
||||||
exploded_node *get_or_create_node (const program_point &point,
|
exploded_node *get_or_create_node (const program_point &point,
|
||||||
const program_state &state,
|
const program_state &state,
|
||||||
|
@ -3178,7 +3178,8 @@ region_model::maybe_update_for_edge (const superedge &edge,
|
|||||||
|
|
||||||
void
|
void
|
||||||
region_model::update_for_gcall (const gcall *call_stmt,
|
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
|
/* Build a vec of argument svalues, using the current top
|
||||||
frame for resolving tree expressions. */
|
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));
|
arg_svals.quick_push (get_rvalue (arg, ctxt));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Get the function * from the call. */
|
if(!callee)
|
||||||
tree fn_decl = get_fndecl_for_call (call_stmt,ctxt);
|
{
|
||||||
function *fun = DECL_STRUCT_FUNCTION (fn_decl);
|
/* Get the function * from the gcall. */
|
||||||
push_frame (fun, &arg_svals, ctxt);
|
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
|
/* 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)
|
region_model_context *ctxt)
|
||||||
{
|
{
|
||||||
const gcall *call_stmt = call_edge.get_call_stmt ();
|
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
|
/* Extract calling information from the return superedge and update the model
|
||||||
|
@ -609,7 +609,8 @@ class region_model
|
|||||||
rejected_constraint **out);
|
rejected_constraint **out);
|
||||||
|
|
||||||
void update_for_gcall (const gcall *call_stmt,
|
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,
|
void update_for_return_gcall (const gcall *call_stmt,
|
||||||
region_model_context *ctxt);
|
region_model_context *ctxt);
|
||||||
|
@ -6,9 +6,10 @@ typedef void (*fn_ptr_t) (void *);
|
|||||||
void
|
void
|
||||||
calls_free (void *victim)
|
calls_free (void *victim)
|
||||||
{
|
{
|
||||||
free (victim);
|
free (victim); /* { dg-warning "double-'free' of 'victim'" } */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
no_op (void *ptr)
|
no_op (void *ptr)
|
||||||
{
|
{
|
||||||
@ -25,7 +26,6 @@ void test_1 (void *ptr)
|
|||||||
fn_ptr (ptr);
|
fn_ptr (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
|
/* As above, but with an extra indirection to try to thwart
|
||||||
the optimizer. */
|
the optimizer. */
|
||||||
@ -41,4 +41,3 @@ void test_2 (void *ptr, fn_ptr_t *fn_ptr)
|
|||||||
(*fn_ptr) (ptr);
|
(*fn_ptr) (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))
|
static void __attribute__((noinline))
|
||||||
called_by_test_6a (void *ptr)
|
called_by_test_6a (void *ptr)
|
||||||
{
|
{
|
||||||
free (ptr); /* { dg-warning "double-'free'" "" { xfail *-*-* } } */
|
free (ptr); /* { dg-warning "double-'free'"} */
|
||||||
}
|
}
|
||||||
|
|
||||||
static deallocator_t __attribute__((noinline))
|
static deallocator_t __attribute__((noinline))
|
||||||
|
Loading…
Reference in New Issue
Block a user