aboutsummaryrefslogtreecommitdiff
path: root/gcc/analyzer
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/analyzer')
-rw-r--r--gcc/analyzer/region-model.cc82
-rw-r--r--gcc/analyzer/region-model.h6
-rw-r--r--gcc/analyzer/region.cc57
-rw-r--r--gcc/analyzer/store.cc12
-rw-r--r--gcc/analyzer/store.h2
5 files changed, 130 insertions, 29 deletions
diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index c3d9ca7..5b08e48 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -1204,6 +1204,76 @@ region_model::get_rvalue (tree expr, region_model_context *ctxt)
return get_rvalue (path_var (expr, get_stack_depth () - 1), ctxt);
}
+/* Return true if this model is on a path with "main" as the entrypoint
+ (as opposed to one in which we're merely analyzing a subset of the
+ path through the code). */
+
+bool
+region_model::called_from_main_p () const
+{
+ if (!m_current_frame)
+ return false;
+ /* Determine if the oldest stack frame in this model is for "main". */
+ const frame_region *frame0 = get_frame_at_index (0);
+ gcc_assert (frame0);
+ return id_equal (DECL_NAME (frame0->get_function ()->decl), "main");
+}
+
+/* Subroutine of region_model::get_store_value for when REG is (or is within)
+ a global variable that hasn't been touched since the start of this path
+ (or was implicitly touched due to a call to an unknown function). */
+
+const svalue *
+region_model::get_initial_value_for_global (const region *reg) const
+{
+ /* Get the decl that REG is for (or is within). */
+ const decl_region *base_reg
+ = reg->get_base_region ()->dyn_cast_decl_region ();
+ gcc_assert (base_reg);
+ tree decl = base_reg->get_decl ();
+
+ /* Special-case: to avoid having to explicitly update all previously
+ untracked globals when calling an unknown fn, they implicitly have
+ an unknown value if an unknown call has occurred, unless this is
+ static to-this-TU and hasn't escaped. Globals that have escaped
+ are explicitly tracked, so we shouldn't hit this case for them. */
+ if (m_store.called_unknown_fn_p () && TREE_PUBLIC (decl))
+ return m_mgr->get_or_create_unknown_svalue (reg->get_type ());
+
+ /* If we are on a path from the entrypoint from "main" and we have a
+ global decl defined in this TU that hasn't been touched yet, then
+ the initial value of REG can be taken from the initialization value
+ of the decl. */
+ if (called_from_main_p () && !DECL_EXTERNAL (decl))
+ {
+ /* Get the initializer value for base_reg. */
+ const svalue *base_reg_init
+ = base_reg->get_svalue_for_initializer (m_mgr);
+ gcc_assert (base_reg_init);
+ if (reg == base_reg)
+ return base_reg_init;
+ else
+ {
+ /* Get the value for REG within base_reg_init. */
+ binding_cluster c (base_reg);
+ c.bind (m_mgr->get_store_manager (), base_reg, base_reg_init,
+ BK_direct);
+ const svalue *sval
+ = c.get_any_binding (m_mgr->get_store_manager (), reg);
+ if (sval)
+ {
+ if (reg->get_type ())
+ sval = m_mgr->get_or_create_cast (reg->get_type (),
+ sval);
+ return sval;
+ }
+ }
+ }
+
+ /* Otherwise, return INIT_VAL(REG). */
+ return m_mgr->get_or_create_initial_value (reg);
+}
+
/* Get a value for REG, looking it up in the store, or otherwise falling
back to "initial" or "unknown" values. */
@@ -1256,14 +1326,10 @@ region_model::get_store_value (const region *reg) const
would have returned UNKNOWN, and we would already have returned
that above). */
- /* 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. */
- if (m_store.called_unknown_fn_p ())
- if (reg->get_base_region ()->get_parent_region ()->get_kind ()
- == RK_GLOBALS)
- return m_mgr->get_or_create_unknown_svalue (reg->get_type ());
+ /* Handle globals. */
+ if (reg->get_base_region ()->get_parent_region ()->get_kind ()
+ == RK_GLOBALS)
+ return get_initial_value_for_global (reg);
return m_mgr->get_or_create_initial_value (reg);
}
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index 3d044bf..79d739e 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -1870,6 +1870,9 @@ public:
int get_stack_depth () const;
const svalue *maybe_get_constant_value (region_model_manager *mgr) const;
+ const svalue *get_svalue_for_constructor (tree ctor,
+ region_model_manager *mgr) const;
+ const svalue *get_svalue_for_initializer (region_model_manager *mgr) const;
private:
tree m_decl;
@@ -2701,6 +2704,9 @@ class region_model
void record_dynamic_extents (const region *reg,
const svalue *size_in_bytes);
+ bool called_from_main_p () const;
+ const svalue *get_initial_value_for_global (const region *reg) const;
+
/* Storing this here to avoid passing it around everywhere. */
region_model_manager *const m_mgr;
diff --git a/gcc/analyzer/region.cc b/gcc/analyzer/region.cc
index 770e2cb..c3dc8cd 100644
--- a/gcc/analyzer/region.cc
+++ b/gcc/analyzer/region.cc
@@ -886,20 +886,53 @@ decl_region::maybe_get_constant_value (region_model_manager *mgr) const
&& DECL_IN_CONSTANT_POOL (m_decl)
&& DECL_INITIAL (m_decl)
&& TREE_CODE (DECL_INITIAL (m_decl)) == CONSTRUCTOR)
- {
- tree ctor = DECL_INITIAL (m_decl);
- gcc_assert (!TREE_CLOBBER_P (ctor));
+ return get_svalue_for_constructor (DECL_INITIAL (m_decl), mgr);
+ return NULL;
+}
- /* Create a binding map, applying ctor to it, using this
- decl_region as the base region when building child regions
- for offset calculations. */
- binding_map map;
- map.apply_ctor_to_region (this, ctor, mgr);
+/* Get an svalue for CTOR, a CONSTRUCTOR for this region's decl. */
- /* Return a compound svalue for the map we built. */
- return mgr->get_or_create_compound_svalue (get_type (), map);
- }
- return NULL;
+const svalue *
+decl_region::get_svalue_for_constructor (tree ctor,
+ region_model_manager *mgr) const
+{
+ gcc_assert (!TREE_CLOBBER_P (ctor));
+
+ /* Create a binding map, applying ctor to it, using this
+ decl_region as the base region when building child regions
+ for offset calculations. */
+ binding_map map;
+ map.apply_ctor_to_region (this, ctor, mgr);
+
+ /* Return a compound svalue for the map we built. */
+ return mgr->get_or_create_compound_svalue (get_type (), map);
+}
+
+/* For use on decl_regions for global variables.
+
+ Get an svalue for the initial value of this region at entry to
+ "main" (either based on DECL_INITIAL, or implicit initialization to
+ zero. */
+
+const svalue *
+decl_region::get_svalue_for_initializer (region_model_manager *mgr) const
+{
+ tree init = DECL_INITIAL (m_decl);
+ if (!init)
+ {
+ /* Implicit initialization to zero; use a compound_svalue for it. */
+ binding_cluster c (this);
+ c.zero_fill_region (mgr->get_store_manager (), this);
+ return mgr->get_or_create_compound_svalue (TREE_TYPE (m_decl),
+ c.get_map ());
+ }
+
+ if (TREE_CODE (init) == CONSTRUCTOR)
+ return get_svalue_for_constructor (init, mgr);
+
+ /* Reuse the get_rvalue logic from region_model. */
+ region_model m (mgr);
+ return m.get_rvalue (path_var (init, 0), NULL);
}
/* class field_region : public region. */
diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc
index 5af86d0..d854f4e 100644
--- a/gcc/analyzer/store.cc
+++ b/gcc/analyzer/store.cc
@@ -396,15 +396,9 @@ get_subregion_within_ctor (const region *parent_reg, tree index,
static const svalue *
get_svalue_for_ctor_val (tree val, region_model_manager *mgr)
{
- if (TREE_CODE (val) == ADDR_EXPR)
- {
- gcc_assert (TREE_CODE (TREE_OPERAND (val, 0)) == STRING_CST);
- const string_region *str_reg
- = mgr->get_region_for_string (TREE_OPERAND (val, 0));
- return mgr->get_ptr_svalue (TREE_TYPE (val), str_reg);
- }
- gcc_assert (CONSTANT_CLASS_P (val));
- return mgr->get_or_create_constant_svalue (val);
+ /* Reuse the get_rvalue logic from region_model. */
+ region_model m (mgr);
+ return m.get_rvalue (path_var (val, 0), NULL);
}
/* Bind values from CONSTRUCTOR to this map, relative to
diff --git a/gcc/analyzer/store.h b/gcc/analyzer/store.h
index 16bad03..bc9dc2e 100644
--- a/gcc/analyzer/store.h
+++ b/gcc/analyzer/store.h
@@ -451,6 +451,8 @@ public:
iterator_t begin () const { return m_map.begin (); }
iterator_t end () const { return m_map.end (); }
+ const binding_map &get_map () const { return m_map; }
+
private:
const svalue *get_any_value (const binding_key *key) const;
void get_overlapping_bindings (store_manager *mgr, const region *reg,