From e92d0ff6b5e6d4b95c04fc3e326d40efeb136086 Mon Sep 17 00:00:00 2001 From: Ankur Saini Date: Thu, 19 Aug 2021 19:54:56 +0530 Subject: [PATCH] analyzer: Fix PR analyzer/101980 2021-08-19 Ankur Saini gcc/analyzer/ChangeLog: PR analyzer/101980 * diagnostic-manager.cc (diagnostic_manager::prune_for_sm_diagnostic): Use caller_model only when the supergraph_edge doesn't exixt. (diagnostic_manager::prune_for_sm_diagnostic): 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. --- gcc/analyzer/diagnostic-manager.cc | 40 +++++++++++++++++-- gcc/analyzer/engine.cc | 49 +++++++++++++----------- gcc/analyzer/exploded-graph.h | 14 +++---- gcc/analyzer/region-model.cc | 17 +++++--- gcc/analyzer/region-model.h | 3 +- gcc/testsuite/gcc.dg/analyzer/function-ptr-2.c | 5 +-- gcc/testsuite/gcc.dg/analyzer/malloc-callbacks.c | 2 +- 7 files changed, 85 insertions(+), 45 deletions(-) diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc index 06e7510..89b5d1e 100644 --- a/gcc/analyzer/diagnostic-manager.cc +++ b/gcc/analyzer/diagnostic-manager.cc @@ -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 ()) diff --git a/gcc/analyzer/engine.cc b/gcc/analyzer/engine.cc index 461de9c..e66ca4e 100644 --- a/gcc/analyzer/engine.cc +++ b/gcc/analyzer/engine.cc @@ -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 diff --git a/gcc/analyzer/exploded-graph.h b/gcc/analyzer/exploded-graph.h index 192a4b3..6890e84 100644 --- a/gcc/analyzer/exploded-graph.h +++ b/gcc/analyzer/exploded-graph.h @@ -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, diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc index 822e893..9870007 100644 --- a/gcc/analyzer/region-model.cc +++ b/gcc/analyzer/region-model.cc @@ -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 diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h index e40264e..a734f9f 100644 --- a/gcc/analyzer/region-model.h +++ b/gcc/analyzer/region-model.h @@ -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); diff --git a/gcc/testsuite/gcc.dg/analyzer/function-ptr-2.c b/gcc/testsuite/gcc.dg/analyzer/function-ptr-2.c index 411b1b3..fd25e3b 100644 --- a/gcc/testsuite/gcc.dg/analyzer/function-ptr-2.c +++ b/gcc/testsuite/gcc.dg/analyzer/function-ptr-2.c @@ -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. diff --git a/gcc/testsuite/gcc.dg/analyzer/malloc-callbacks.c b/gcc/testsuite/gcc.dg/analyzer/malloc-callbacks.c index 901ca5c..53c75fd 100644 --- a/gcc/testsuite/gcc.dg/analyzer/malloc-callbacks.c +++ b/gcc/testsuite/gcc.dg/analyzer/malloc-callbacks.c @@ -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)) -- 2.7.4