From 9bd57c71a3e6f9632515c88f813d31fdd5105e3e Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Mon, 27 Apr 2020 16:27:35 -0400 Subject: [PATCH 079/179] FIXME: treat regions pointer to by initial values of pointer parms as escaped --- gcc/analyzer/region-model2.cc | 42 +++++++++++++++++-- gcc/analyzer/region-model2.h | 1 + gcc/analyzer/store2.cc | 7 +++- gcc/testsuite/gcc.dg/analyzer/unknown-fns-2.c | 30 +++++++++++++ 4 files changed, 76 insertions(+), 4 deletions(-) diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc index f3d406d0788..f1a5f82ec2d 100644 --- a/gcc/analyzer/region-model2.cc +++ b/gcc/analyzer/region-model2.cc @@ -6266,6 +6266,27 @@ region_model2::get_stack_region2 *() const } #endif +/* For use with push_frame when handling a top-level call within the analysis. + PARAM has a defined but unknown initial value. + Anything it points to has escaped, since the calling context "knows" + the pointer, and thus calls to unknown functions could read/write into + the region. */ + +void +region_model2::on_top_level_param (tree param, + region_model2_context *ctxt) +{ + if (POINTER_TYPE_P (TREE_TYPE (param))) + { + region2 *param_reg = get_lvalue (param, ctxt); + svalue2 *init_ptr_sval + = m_mgr->get_or_create_initial_value (param_reg); + region2 *pointee_reg = m_mgr->get_symbolic_region (init_ptr_sval); + m_store.on_escape_to_unknown_fncall (m_mgr->get_store2_manager (), + pointee_reg); + } +} + // FIXME: /* Create a new frame_region2 for a call to FUN and push it onto the stack. @@ -6278,7 +6299,7 @@ region_model2::get_stack_region2 *() const region2 * region_model2::push_frame (function *fun, vec *arg_svals, - region_model2_context */*ctxt*/) + region_model2_context *ctxt) { m_current_frame = m_mgr->get_frame_region (m_current_frame, fun); if (arg_svals) @@ -6315,8 +6336,23 @@ region_model2::push_frame (function *fun, vec *arg_svals, #endif } } - /* Otherwise we have a top-level call within the analysis. The params - have defined but unknown initial values. */ + else + { + /* Otherwise we have a top-level call within the analysis. The params + have defined but unknown initial values. + Anything they point to has escaped. */ + tree fndecl = fun->decl; + for (tree iter_parm = DECL_ARGUMENTS (fndecl); iter_parm; + iter_parm = DECL_CHAIN (iter_parm)) + { + on_top_level_param (iter_parm, ctxt); + /* TODO: also do it for default SSA name (sharing the same unknown + value). */ + tree parm_default_ssa = ssa_default_def (fun, iter_parm); + if (parm_default_ssa) + on_top_level_param (parm_default_ssa, ctxt); + } + } return m_current_frame; } diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h index 05e550cdb39..e4fc3395cf9 100644 --- a/gcc/analyzer/region-model2.h +++ b/gcc/analyzer/region-model2.h @@ -1942,6 +1942,7 @@ class region_model2 auto_vec *rep_path_vars, bool *is_first); #endif + void on_top_level_param (tree param, region_model2_context *ctxt); void record_dynamic_extents (region2 *reg, svalue2 *size_in_bytes); diff --git a/gcc/analyzer/store2.cc b/gcc/analyzer/store2.cc index b6b51fe8898..807df24becf 100644 --- a/gcc/analyzer/store2.cc +++ b/gcc/analyzer/store2.cc @@ -568,7 +568,12 @@ store2::on_escape_to_unknown_fncall (store2_manager *mgr, if (binding_cluster2 **cluster_slot = m_cluster_map.get (base_reg)) (*cluster_slot)->on_escape_to_unknown_fncall (mgr); - // TODO + else + { + binding_cluster2 *cluster = new binding_cluster2 (); + m_cluster_map.put (base_reg, cluster); + cluster->on_escape_to_unknown_fncall (mgr); + } /* FIXME: but don't bother marking every global as escaped; instead, clear these. */ } diff --git a/gcc/testsuite/gcc.dg/analyzer/unknown-fns-2.c b/gcc/testsuite/gcc.dg/analyzer/unknown-fns-2.c index 42d6009d4db..fd99127e3ec 100644 --- a/gcc/testsuite/gcc.dg/analyzer/unknown-fns-2.c +++ b/gcc/testsuite/gcc.dg/analyzer/unknown-fns-2.c @@ -89,3 +89,33 @@ void test_3 (void) unknown_fn (NULL); __analyzer_eval (i == 17); /* { dg-warning "UNKNOWN" } */ } + +struct used_by_test_4 +{ + int *int_ptr; +}; + +void test_4 (struct used_by_test_4 *st4_ptr) +{ + /* Something unknown called "test_4", and hence *st4_ptr has + effectively already escaped. */ + + int i = 42; + __analyzer_eval (i == 42); /* { dg-warning "TRUE" } */ + + unknown_fn (NULL); + __analyzer_eval (i == 42); /* { dg-warning "TRUE" } */ + + /* Given that *st4_ptr has effectively already escaped, calling + an unknown fn should invalidate our knowledge of i". */ + st4_ptr->int_ptr = &i; + unknown_fn (NULL); + __analyzer_eval (i == 42); /* { dg-warning "UNKNOWN" } */ + + /* ...and "&i" should now be treated as having escaped. */ + i = 17; + __analyzer_eval (i == 17); /* { dg-warning "TRUE" } */ + st4_ptr->int_ptr = NULL; + unknown_fn (NULL); + __analyzer_eval (i == 17); /* { dg-warning "UNKNOWN" } */ +} -- 2.21.0