From f0b934bd93be75c3b86adc8cc9c3842ab8b41574 Mon Sep 17 00:00:00 2001 From: David Malcolm Date: Thu, 9 Jul 2020 11:27:10 -0400 Subject: [PATCH 294/315] FIXME: add m_called_unknown_fn, fixing unknown-fns.c:test_2 --- gcc/analyzer/region-model2.cc | 14 ++++++++++++++ gcc/analyzer/region-model2.h | 8 +++++++- gcc/analyzer/store2.cc | 17 ++++++++++++++++- gcc/analyzer/store2.h | 10 ++++++++++ 4 files changed, 47 insertions(+), 2 deletions(-) diff --git a/gcc/analyzer/region-model2.cc b/gcc/analyzer/region-model2.cc index 47682e31cac..f6be72983f0 100644 --- a/gcc/analyzer/region-model2.cc +++ b/gcc/analyzer/region-model2.cc @@ -5794,6 +5794,18 @@ region_model2::get_store_value (const region2 *reg) return m_mgr->get_or_create_cast (reg->get_type (), char_sval); } + /* Otherwise we implicitly have the initial value of the region. */ + + /* Special-case: to avoid having to explicitly update all previously + untracked globals when calling an unknown fn, we instead change + the default here so we implicitly have an unknown value for such + regions. */ + // FIXME: what about symbolic writes also? + if (m_store.called_unknown_fn_p ()) + if (reg->get_base_region ()->get_parent_region ()->get_kind () + == region2::RK_GLOBALS) + return m_mgr->get_or_create_unknown_svalue2 (reg->get_type ()); + /* FIXME: not if touched by symbolic value; handled in binding_cluster2::get_any_binding. */ return m_mgr->get_or_create_initial_value (reg); @@ -8247,11 +8259,13 @@ test_dump () ASSERT_DUMP_EQ (model, false, "stack depth: 0\n" + "m_called_unknown_fn: FALSE\n" "constraint_manager2:\n" " equiv classes:\n" " constraints:\n"); ASSERT_DUMP_EQ (model, true, "stack depth: 0\n" + "m_called_unknown_fn: FALSE\n" "constraint_manager2:\n" " equiv classes:\n" " constraints:\n"); diff --git a/gcc/analyzer/region-model2.h b/gcc/analyzer/region-model2.h index fd5e3f66262..8abf888d7f5 100644 --- a/gcc/analyzer/region-model2.h +++ b/gcc/analyzer/region-model2.h @@ -505,7 +505,13 @@ template <> struct default_hash_traits namespace ana { /* Concrete subclass of svalue2 representing the initial value of a - specific region */ + specific region. + + FIXME: trying this approach: + This represents the initial value at the start of the analysis path, + as opposed to the first time the region is accessed during the path. + Hence as soon as we have a call to an unknown function, all previously + unmodelled globals become implicitly "unknown" rathen than "initial". */ class initial_svalue2 : public svalue2 { diff --git a/gcc/analyzer/store2.cc b/gcc/analyzer/store2.cc index 75128e4bdc8..bbbbd71bc0b 100644 --- a/gcc/analyzer/store2.cc +++ b/gcc/analyzer/store2.cc @@ -1001,12 +1001,14 @@ store2_manager::get_symbolic_binding (const region2 *reg, /* FIXME. */ store2::store2 () +: m_called_unknown_fn (false) { } /* store2's copy ctor. */ store2::store2 (const store2 &other) +: m_called_unknown_fn (other.m_called_unknown_fn) { /* Deep copy. TODO: replace with functional approach using immutable_map. */ for (cluster_map_t::iterator iter = other.m_cluster_map.begin (); @@ -1043,6 +1045,8 @@ store2::operator= (const store2 &other) delete (*iter).second; m_cluster_map.empty (); + m_called_unknown_fn = other.m_called_unknown_fn; + /* Deep copy. TODO: replace with functional approach using immutable_map. */ for (cluster_map_t::iterator iter = other.m_cluster_map.begin (); iter != other.m_cluster_map.end (); @@ -1062,6 +1066,9 @@ store2::operator= (const store2 &other) bool store2::operator== (const store2 &other) const { + if (m_called_unknown_fn != other.m_called_unknown_fn) + return false; + if (m_cluster_map.elements () != other.m_cluster_map.elements ()) return false; @@ -1205,6 +1212,10 @@ store2::dump_to_pp (pretty_printer *pp, bool simple, bool multiline, if (!multiline) pp_string (pp, "}"); } + pp_printf (pp, "m_called_unknown_fn: %s", + m_called_unknown_fn ? "TRUE" : "FALSE"); + if (multiline) + pp_newline (pp); } /* Dump a multiline representation of this store2 to stderr. */ @@ -1597,7 +1608,9 @@ store2::mark_as_escaped (const region2 *base_reg) binding_cluster2 *cluster = get_or_create_cluster (base_reg); cluster->mark_as_escaped (); /* FIXME: but don't bother marking every global as escaped; instead, - clear these on unknown fncalls. */ + m_called_unknown_fn is set on these when on unknown fncalls, + changeing the implicit value on globals from "initial" + to "unknown". */ } /* Handle an unknown fncall by updating any clusters that have escaped @@ -1606,6 +1619,8 @@ store2::mark_as_escaped (const region2 *base_reg) void store2::on_unknown_fncall () { + m_called_unknown_fn = true; + for (cluster_map_t::iterator iter = m_cluster_map.begin (); iter != m_cluster_map.end (); ++iter) (*iter).second->on_unknown_fncall (); diff --git a/gcc/analyzer/store2.h b/gcc/analyzer/store2.h index f1dcb6cc74a..bf27df97d59 100644 --- a/gcc/analyzer/store2.h +++ b/gcc/analyzer/store2.h @@ -473,6 +473,8 @@ public: const svalue2 *get_default_binding (store2_manager *mgr, const region2 *reg); const svalue2 *get_any_binding (store2_manager *mgr, const region2 *reg); + bool called_unknown_fn_p () const { return m_called_unknown_fn; } + void set_value (store2_manager *mgr, const region2 *lhs_reg, const svalue2 *rhs_sval, enum binding_kind kind); void clobber_region (store2_manager *mgr, const region2 *reg); @@ -525,6 +527,14 @@ private: void remove_overlapping_bindings (store2_manager *mgr, const region2 *reg); cluster_map_t m_cluster_map; // TODO: deep copy of this! + + /* If this is true, then unknown code has been called, and so + any global variable that isn't currently modelled by the store + has unknown state, rather than being in an "initial state". + This is to avoid having to mark (and thus explicitly track) + every global when an unknown function is called; instead, they + can be tracked implicitly. */ + bool m_called_unknown_fn; }; class store2_manager -- 2.26.2