From 538fe12ea76eb3575ebecf016819e5a7cefb7d5b Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Tue, 14 Apr 2020 14:51:03 -0400 Subject: [PATCH 034/179] FIXME: start adding array handling --- gcc/analyzer/region-model2.cc | 195 ++++++++++++++++++++++++++++++---- gcc/analyzer/region-model2.h | 91 ++++++++++------ 2 files changed, 236 insertions(+), 50 deletions(-) diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc index b08e3d679f2..b4de5a23bdd 100644 --- a/gcc/analyzer/region-model2.cc +++ b/gcc/analyzer/region-model2.cc @@ -697,9 +697,9 @@ region2::kind_to_str (enum kind kind) /* FIXME. */ int -region2::cmp_indices (const region2 *reg1, const region2 *reg2) +region2::cmp_ids (const region2 *reg1, const region2 *reg2) { - return (long)reg1->get_idx () - (long)reg2->get_idx (); + return (long)reg1->get_id () - (long)reg2->get_id (); } /* class region2. */ @@ -817,6 +817,14 @@ region2::operator== (const region2 &other) const = (const field_region2 &)other; return this_sub.compare_fields (other_sub); } + case RK_ELEMENT: + { + const element_region2 &this_sub + = (const element_region2 &)*this; + const element_region2 &other_sub + = (const element_region2 &)other; + return this_sub.compare_fields (other_sub); + } } } @@ -832,6 +840,7 @@ region2::get_base_region () const { //case RK_element_region: case RK_FIELD: + case RK_ELEMENT: iter = iter->get_parent_region (); continue; default: @@ -1327,8 +1336,8 @@ region2::get_view (tree type, region_model2 *model) const /* region2's ctor. */ -region2::region2 (unsigned idx, region2 *parent, tree type) -: m_idx (idx), m_parent (parent), m_type (type) +region2::region2 (unsigned id, region2 *parent, tree type) +: m_id (id), m_parent (parent), m_type (type) { gcc_assert (type == NULL_TREE || TYPE_P (type)); } @@ -1339,6 +1348,8 @@ region2::region2 (unsigned idx, region2 *parent, tree type) void region2::add_to_hash (inchash::hash &hstate) const { + /* We deliberatly omit the id, to avoid different IDs preventing + consolidation. */ hstate.add_ptr (m_parent); hstate.add_ptr (m_type); } @@ -1373,7 +1384,7 @@ region2::cmp_ptrs (const void *p1, const void *p2) const region2 * const *reg1 = (const region2 * const *)p1; const region2 * const *reg2 = (const region2 * const *)p2; - return cmp_indices (*reg1, *reg2); + return cmp_ids (*reg1, *reg2); } /* Determine if a pointer to this region2 must be non-NULL. @@ -2266,8 +2277,8 @@ heap_region2::compare_fields (const heap_region2 &) const /* root_region2's default ctor. */ -root_region2::root_region2 (unsigned idx) -: region2 (idx, NULL, NULL_TREE) +root_region2::root_region2 (unsigned id) +: region2 (id, NULL, NULL_TREE) { } @@ -2756,6 +2767,43 @@ field_region2::dump_to_pp (pretty_printer *pp, bool simple) const } } +/* class element_region2 : public region2. */ + +bool +element_region2::compare_fields (const element_region2 &other) const +{ + return m_index == other.m_index; +} + +void +element_region2::dump_to_pp (pretty_printer *pp, bool simple) const +{ + if (simple) + { + get_parent_region ()->dump_to_pp (pp, simple); + pp_string (pp, "["); + m_index->dump_to_pp (pp, simple); + pp_string (pp, "]"); + } + else + { + pp_string (pp, "element_region2("); + get_parent_region ()->dump_to_pp (pp, simple); + pp_string (pp, ", "); + print_quoted_type (pp, get_type ()); + pp_string (pp, ", "); + m_index->dump_to_pp (pp, simple); + pp_printf (pp, ")"); + } +} + +void +element_region2::add_to_hash (inchash::hash &hstate) const +{ + region2::add_to_hash (hstate); + hstate.add_ptr (m_index); +} + /* class binding_key. */ /* FIXME. */ @@ -2773,7 +2821,7 @@ binding_key::cmp_ptrs (const void *p1, const void *p2) int binding_key::cmp (const binding_key *k1, const binding_key *k2) { - if (int reg_cmp = region2::cmp_indices (k1->m_region, k2->m_region)) + if (int reg_cmp = region2::cmp_ids (k1->m_region, k2->m_region)) return reg_cmp; enum kind kind1 = k1->get_kind (); @@ -2837,12 +2885,24 @@ binding_cluster::bind (region_model2_manager *mgr, m_map.put (binding, val); } +svalue2 * +binding_cluster::get_binding (region_model2_manager *mgr, region2 *reg) const +{ + // FIXME: what if symbolic vs concrete? + const binding_key *binding + = mgr->get_concrete_binding (reg, binding_key::BK_direct, 0); + svalue2 **slot = const_cast (m_map).get (binding); + if (slot) + return *slot; + return NULL; +} + /* class region_model2_manager. */ region_model2_manager::region_model2_manager () -: m_next_region_idx (0), - m_root_region (alloc_region_idx ()), - m_globals_region (alloc_region_idx (), &m_root_region), +: m_next_region_id (0), + m_root_region (alloc_region_id ()), + m_globals_region (alloc_region_id (), &m_root_region), m_globals_map () { // TODO @@ -2878,7 +2938,7 @@ region_model2_manager::get_region_for_global (tree expr, if (slot) return *slot; decl_region2 *reg - = new decl_region2 (alloc_region_idx (), &m_globals_region, expr); + = new decl_region2 (alloc_region_id (), &m_globals_region, expr); m_globals_map.put (expr, reg); return reg; } @@ -2887,11 +2947,23 @@ region2 * region_model2_manager::get_field_region (region2 *parent, tree field, region_model2_context *ctxt) { - // FIXME: should only alloc_region_idx if consolidation fails - region2 *field_reg = new field_region2 (alloc_region_idx (), parent, field); + // FIXME: should only alloc_region_id if consolidation fails + region2 *field_reg = new field_region2 (alloc_region_id (), parent, field); return const_cast (m_fields.consolidate (field_reg)); } +region2 * +region_model2_manager::get_element_region (region2 *parent, + tree element_type, + svalue2 *index, + region_model2_context *ctxt) +{ + // FIXME: should only alloc_region_id if consolidation fails + region2 *element_reg + = new element_region2 (alloc_region_id (), parent, element_type, index); + return const_cast (m_elements.consolidate (element_reg)); +} + const concrete_binding * region_model2_manager::get_concrete_binding (region2 *region, enum binding_key::kind kind, @@ -4303,7 +4375,6 @@ region_model2::get_lvalue_1 (region_model2_manager *mgr, path_var pv, dump_location_t ()); #endif -#if 0 case ARRAY_REF: { tree array = TREE_OPERAND (expr, 0); @@ -4314,8 +4385,12 @@ region_model2::get_lvalue_1 (region_model2_manager *mgr, path_var pv, gcc_assert (TREE_OPERAND (expr, 3) == NULL_TREE); #endif - region2 *array_reg = get_lvalue (array, ctxt); - svalue2 *index_sval = get_rvalue (index, ctxt); + region2 *array_reg = get_lvalue (mgr, array, ctxt); + svalue2 *index_sval = get_rvalue (mgr, index, ctxt); + return mgr->get_element_region (array_reg, + TREE_TYPE (TREE_TYPE (array)), + index_sval, ctxt); +#if 0 region2 *base_array_reg = get_region2 (array_reg); array_region2 *array_reg = base_array_reg->dyn_cast_array_region2 (); if (!array_reg) @@ -4329,9 +4404,11 @@ region_model2::get_lvalue_1 (region_model2_manager *mgr, path_var pv, dump_location_t ()); } return array_reg->get_element (this, array_reg, index_sval, ctxt); +#endif } break; +#if 0 case BIT_FIELD_REF: { /* For now, create a view, as if a cast, ignoring the bit positions. */ @@ -4530,12 +4607,13 @@ region_model2::get_rvalue_1 (region_model2_manager *mgr, path_var pv, } break; +#endif case ARRAY_REF: { - region2 *element_reg = get_lvalue (pv, ctxt); - return get_region2 (element_reg)->get_value (*this, true, ctxt); + region2 *element_reg = get_lvalue (mgr, pv, ctxt); + return get_store_value (mgr, element_reg); } -#endif + case INTEGER_CST: case REAL_CST: case STRING_CST: @@ -4582,6 +4660,23 @@ region_model2::get_rvalue (region_model2_manager *mgr, tree expr, return get_rvalue (mgr, path_var (expr, get_stack_depth () - 1), ctxt); } +/* FIXME. */ + +svalue2 * +region_model2::get_store_value (region_model2_manager *mgr, region2 *reg) +{ + const region2 *base_reg = reg->get_base_region (); + binding_cluster **cluster_slot = m_cluster_map.get (base_reg); + if (cluster_slot) + { + if (svalue2 *result = (*cluster_slot)->get_binding (mgr, reg)) + return result; + } + + /* Otherwise, no bound value. */ + gcc_unreachable (); // TODO +} + /* Return an svalue2 *for a pointer to RID of type PTR_TYPE, reusing existing pointer values if one is available. */ #if 0 @@ -6855,6 +6950,8 @@ test_dump_2 () model.set_value (&mgr, c_x, int_17, NULL); model.set_value (&mgr, c_y, int_m3, NULL); + // TODO: test get_value + /* FIXME: fails due to lack of sorting! ...but time to implement a[0] = ; a[1] = ; a[i] = ; and a more sophisticated region binding/cluster implementation. */ @@ -8061,6 +8158,63 @@ test_malloc_constraints () } #endif +static void +test_array () +{ + /* "int arr[10];" */ + tree tlen = size_int (10); + tree arr_type + = build_array_type (integer_type_node, build_index_type (tlen)); + tree arr = build_global_decl ("arr", arr_type); + + /* "int i;" */ + tree i = build_global_decl ("i", integer_type_node); + + tree int_0 = build_int_cst (integer_type_node, 0); + tree int_1 = build_int_cst (integer_type_node, 1); + + tree arr_0 = build4 (ARRAY_REF, integer_type_node, + arr, int_0, NULL_TREE, NULL_TREE); + tree arr_1 = build4 (ARRAY_REF, integer_type_node, + arr, int_1, NULL_TREE, NULL_TREE); + tree arr_i = build4 (ARRAY_REF, integer_type_node, + arr, i, NULL_TREE, NULL_TREE); + + tree int_17 = build_int_cst (integer_type_node, 17); + tree int_m3 = build_int_cst (integer_type_node, -3); + + region_model2_manager mgr; + region_model2 model; + /* "arr[0] = 17;". */ + model.set_value (&mgr, arr_0, int_17, NULL); + /* "arr[1] = -3;". */ + model.set_value (&mgr, arr_1, int_m3, NULL); + + ASSERT_EQ (model.get_rvalue (&mgr, arr_0, NULL), + model.get_rvalue (&mgr, int_17, NULL)); + ASSERT_EQ (model.get_rvalue (&mgr, arr_1, NULL), + model.get_rvalue (&mgr, int_m3, NULL)); + +#if 0 + /* "arr[i] = i;" - this should remove the earlier bindings. */ + model.set_value (&mgr, arr_i, i, NULL); + // TODO: get_value for other bindings + // TODO: assert that there is now no binding for the other indices +#endif + + /* Simplified dump. */ +#if 0 + ASSERT_DUMP_EQ (model, true, + "base region: {c} has cluster: {" + "binding key: {region: c.x, kind: direct, offset: 0}," + " value: {17}," + " binding key: {region: c.y, kind: direct, offset: 0}," + " value: {-3}" + "}"); +#endif + +} + /* Run all of the selftests within this file. */ void @@ -8089,6 +8243,7 @@ analyzer_region_model2_cc_tests () test_constraint_merging (); test_malloc_constraints (); #endif + test_array (); } } // namespace selftest diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h index 18b9bfde7e5..66db7d71aa7 100644 --- a/gcc/analyzer/region-model2.h +++ b/gcc/analyzer/region-model2.h @@ -510,7 +510,8 @@ public: root_region (RK_ROOT) label_region (RK_FUNCTION) symbolic_region (RK_SYMBOLIC) - field_region (RK_FIELD). */ + field_region (RK_FIELD) + element_region (RK_ELEMENT). */ /* Abstract base class representing a chunk of memory. @@ -541,7 +542,8 @@ public: RK_ROOT, //RK_SYMBOLIC, RK_DECL, - RK_FIELD + RK_FIELD, + RK_ELEMENT }; static const char *kind_to_str (enum kind); @@ -554,8 +556,8 @@ public: virtual region2 *clone () const = 0; #endif - unsigned get_idx () const { return m_idx; } - static int cmp_indices (const region2 *reg1, const region2 *reg2); + unsigned get_id () const { return m_id; } + static int cmp_ids (const region2 *reg1, const region2 *reg2); virtual enum kind get_kind () const = 0; virtual map_region2 *dyn_cast_map_region2 () { return NULL; } @@ -616,7 +618,7 @@ public: static int cmp_ptrs (const void *, const void *); protected: - region2 (unsigned idx, region2 *parent, tree type); + region2 (unsigned id, region2 *parent, tree type); virtual void add_to_hash (inchash::hash &hstate) const; #if 0 @@ -631,7 +633,7 @@ public: void deactivate_view (region_model2 &model, region_id this_view_rid); #endif - unsigned m_idx; // purely for deterministic sorting at this stage, for dumps + unsigned m_id; // purely for deterministic sorting at this stage, for dumps region2 *m_parent; tree m_type; }; @@ -658,8 +660,8 @@ public: typedef ordered_hash_map map_t; typedef map_t::iterator iterator_t; - map_region2 (unsigned idx, region2 *parent, tree type) - : region2 (idx, parent, type) + map_region2 (unsigned id, region2 *parent, tree type) + : region2 (id, parent, type) {} map_region2 (const map_region2 &other); @@ -740,8 +742,8 @@ class scope_region2 : public map_region2 public: protected: - scope_region2 (unsigned idx, region2 *parent) - : map_region2 (idx, parent, NULL_TREE) + scope_region2 (unsigned id, region2 *parent) + : map_region2 (id, parent, NULL_TREE) {} bool compare_fields (const scope_region2 &other) const; @@ -753,8 +755,8 @@ class scope_region2 : public map_region2 class frame_region2 : public scope_region2 { public: - frame_region2 (unsigned idx, region2 *parent, function *fun, int depth) - : scope_region2 (idx, parent), m_fun (fun), m_depth (depth) + frame_region2 (unsigned id, region2 *parent, function *fun, int depth) + : scope_region2 (id, parent), m_fun (fun), m_depth (depth) {} /* region2 vfuncs. */ @@ -799,8 +801,8 @@ namespace ana { class globals_region2 : public scope_region2 { public: - globals_region2 (unsigned idx, region2 *parent) - : scope_region2 (idx, parent) + globals_region2 (unsigned id, region2 *parent) + : scope_region2 (id, parent) {} /* region2 vfuncs. */ @@ -834,8 +836,8 @@ namespace ana { class code_region2 : public map_region2 { public: - code_region2 (unsigned idx, region2 *parent) - : map_region2 (idx, parent, NULL_TREE) + code_region2 (unsigned id, region2 *parent) + : map_region2 (id, parent, NULL_TREE) {} /* region2 vfuncs. */ @@ -872,8 +874,8 @@ namespace ana { class function_region2 : public map_region2 { public: - function_region2 (unsigned idx, region2 *parent, tree type) - : map_region2 (idx, parent, type) + function_region2 (unsigned id, region2 *parent, tree type) + : map_region2 (id, parent, type) { gcc_assert (FUNC_OR_METHOD_TYPE_P (type)); } @@ -1029,7 +1031,7 @@ namespace ana { class root_region2 : public region2 { public: - root_region2 (unsigned idx); + root_region2 (unsigned id); bool compare_fields (const root_region2 &other) const; @@ -1116,7 +1118,7 @@ namespace ana { class symbolic_region2 : public region2 { public: - symbolic_region2 (unsigned idx, region2 *parent, tree type, bool possibly_null) + symbolic_region2 (unsigned id, region2 *parent, tree type, bool possibly_null) : region2 (parent, type), m_possibly_null (possibly_null) {} @@ -1150,8 +1152,8 @@ public: class decl_region2 : public region2 { public: - decl_region2 (unsigned idx, region2 *parent, tree decl) - : region2 (idx, parent, TREE_TYPE (decl)), m_decl (decl) + decl_region2 (unsigned id, region2 *parent, tree decl) + : region2 (id, parent, TREE_TYPE (decl)), m_decl (decl) {} #if 0 @@ -1176,14 +1178,10 @@ private: class field_region2 : public region2 { public: - field_region2 (unsigned idx, region2 *parent, tree field) - : region2 (idx, parent, TREE_TYPE (field)), m_field (field) + field_region2 (unsigned id, region2 *parent, tree field) + : region2 (id, parent, TREE_TYPE (field)), m_field (field) {} -#if 0 - region2 *clone () const FINAL OVERRIDE; -#endif - bool compare_fields (const field_region2 &other) const; enum region2::kind get_kind () const FINAL OVERRIDE { return RK_FIELD; } @@ -1197,6 +1195,31 @@ private: tree m_field; }; +/* An element within an array. */ + +class element_region2 : public region2 +{ +public: + element_region2 (unsigned id, region2 *parent, tree element_type, + svalue2 *index) + : region2 (id, parent, element_type), m_index (index) + {} + + bool compare_fields (const element_region2 &other) const; + + enum region2::kind get_kind () const FINAL OVERRIDE { return RK_ELEMENT; } + + void dump_to_pp (pretty_printer *pp, bool simple) const FINAL OVERRIDE; + + svalue2 *get_index () const { return m_index; } + +protected: + void add_to_hash (inchash::hash &hstate) const OVERRIDE; + +private: + svalue2 *m_index; +}; + /* A binding within a store. */ class binding_key @@ -1334,6 +1357,8 @@ public: const region2 *, const svalue2 *) const; #endif + svalue2 *get_binding (region_model2_manager *mgr, region2 *reg) const; + private: map_t m_map; }; @@ -1355,6 +1380,10 @@ public: region_model2_context *ctxt); region2 *get_field_region (region2 *parent, tree field, region_model2_context *ctxt); + region2 *get_element_region (region2 *parent, + tree element_type, + svalue2 *index, + region_model2_context *ctxt); const concrete_binding * get_concrete_binding (region2 *region, @@ -1366,10 +1395,10 @@ public: enum binding_key::kind kind, region2 *concrete_offset_region); - unsigned alloc_region_idx () { return m_next_region_idx++; } + unsigned alloc_region_id () { return m_next_region_id++; } private: - unsigned m_next_region_idx; + unsigned m_next_region_id; root_region2 m_root_region; typedef hash_map constants_map_t; @@ -1386,6 +1415,7 @@ private: typedef hash_map fields_map_t; fields_map_t m_fields_map; #endif + uniq_manager m_elements; uniq_manager m_concrete_binding_key_mgr; uniq_manager m_symbolic_binding_key_mgr; @@ -1599,6 +1629,7 @@ class region_model2 region_model2_context *ctxt); svalue2 *get_rvalue_1 (region_model2_manager *mgr, path_var pv, region_model2_context *ctxt); + svalue2 *get_store_value (region_model2_manager *mgr, region2 *reg); #if 0 void copy_struct_region2 (region2_id dst_rid, struct_region2 *dst_reg, -- 2.21.0