summaryrefslogtreecommitdiff
path: root/gcc/analyzer/store.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/analyzer/store.cc')
-rw-r--r--gcc/analyzer/store.cc112
1 files changed, 91 insertions, 21 deletions
diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc
index 0014633c335..35f66a4b6fc 100644
--- a/gcc/analyzer/store.cc
+++ b/gcc/analyzer/store.cc
@@ -997,27 +997,61 @@ binding_map::get_overlapping_bindings (const binding_key *key,
value: {BITS_WITHIN(bytes 4-7, inner_val: INIT_VAL((*INIT_VAL(p_33(D))).arr))}
If UNCERTAINTY is non-NULL, use it to record any svalues that
- were removed, as being maybe-bound. */
+ were removed, as being maybe-bound.
+
+ If ALWAYS_OVERLAP, then assume that DROP_KEY can overlap anything
+ in the map, due to one or both of the underlying clusters being
+ symbolic (but not the same symbolic region). Hence even if DROP_KEY is a
+ concrete binding it could actually be referring to the same memory as
+ distinct concrete bindings in the map. Remove all bindings, but
+ register any svalues with *UNCERTAINTY. */
void
binding_map::remove_overlapping_bindings (store_manager *mgr,
const binding_key *drop_key,
- uncertainty_t *uncertainty)
+ uncertainty_t *uncertainty,
+ bool always_overlap)
{
+ /* Get the bindings of interest within this map. */
auto_vec<const binding_key *> bindings;
- get_overlapping_bindings (drop_key, &bindings);
+ if (always_overlap)
+ for (auto iter : *this)
+ bindings.safe_push (iter.first); /* Add all bindings. */
+ else
+ /* Just add overlapping bindings. */
+ get_overlapping_bindings (drop_key, &bindings);
unsigned i;
const binding_key *iter_binding;
FOR_EACH_VEC_ELT (bindings, i, iter_binding)
{
+ /* Record any svalues that were removed to *UNCERTAINTY as being
+ maybe-bound, provided at least some part of the binding is symbolic.
+
+ Specifically, if at least one of the bindings is symbolic, or we
+ have ALWAYS_OVERLAP for the case where we have possibly aliasing
+ regions, then we don't know that the svalue has been overwritten,
+ and should record that to *UNCERTAINTY.
+
+ However, if we have concrete keys accessing within the same symbolic
+ region, then we *know* that the symbolic region has been overwritten,
+ so we don't record it to *UNCERTAINTY, as this could be a genuine
+ leak. */
const svalue *old_sval = get (iter_binding);
- if (uncertainty)
+ if (uncertainty
+ && (drop_key->symbolic_p ()
+ || iter_binding->symbolic_p ()
+ || always_overlap))
uncertainty->on_maybe_bound_sval (old_sval);
/* Begin by removing the old binding. */
m_map.remove (iter_binding);
+ /* Don't attempt to handle prefixes/suffixes for the
+ "always_overlap" case; everything's being removed. */
+ if (always_overlap)
+ continue;
+
/* Now potentially add the prefix and suffix. */
if (const concrete_binding *drop_ckey
= drop_key->dyn_cast_concrete_binding ())
@@ -1335,22 +1369,30 @@ binding_cluster::zero_fill_region (store_manager *mgr, const region *reg)
fill_region (mgr, reg, zero_sval);
}
-/* Mark REG within this cluster as being unknown.
+/* Mark REG_TO_BIND within this cluster as being unknown.
+
+ Remove any bindings overlapping REG_FOR_OVERLAP.
If UNCERTAINTY is non-NULL, use it to record any svalues that
- had bindings to them removed, as being maybe-bound. */
+ had bindings to them removed, as being maybe-bound.
+
+ REG_TO_BIND and REG_FOR_OVERLAP are the same for
+ store::mark_region_as_unknown, but are different in
+ store::set_value's alias handling, for handling the case where
+ we have a write to a symbolic REG_FOR_OVERLAP. */
void
binding_cluster::mark_region_as_unknown (store_manager *mgr,
- const region *reg,
+ const region *reg_to_bind,
+ const region *reg_for_overlap,
uncertainty_t *uncertainty)
{
- remove_overlapping_bindings (mgr, reg, uncertainty);
+ remove_overlapping_bindings (mgr, reg_for_overlap, uncertainty);
/* Add a default binding to "unknown". */
region_model_manager *sval_mgr = mgr->get_svalue_manager ();
const svalue *sval
- = sval_mgr->get_or_create_unknown_svalue (reg->get_type ());
- bind (mgr, reg, sval);
+ = sval_mgr->get_or_create_unknown_svalue (reg_to_bind->get_type ());
+ bind (mgr, reg_to_bind, sval);
}
/* Purge state involving SVAL. */
@@ -1595,7 +1637,7 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,
it overlaps with offset_concrete_key. */
default_map.remove_overlapping_bindings (mgr,
offset_concrete_key,
- NULL);
+ NULL, false);
}
else if (bound_range.contains_p (reg_range, &subrange))
{
@@ -1629,7 +1671,7 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,
it overlaps with overlap_concrete_key. */
default_map.remove_overlapping_bindings (mgr,
overlap_concrete_key,
- NULL);
+ NULL, false);
}
}
else
@@ -1652,7 +1694,13 @@ binding_cluster::maybe_get_compound_binding (store_manager *mgr,
}
/* Remove, truncate, and/or split any bindings within this map that
- overlap REG.
+ could overlap REG.
+
+ If REG's base region or this cluster is symbolic and they're different
+ base regions, then remove everything in this cluster's map, on the
+ grounds that REG could be referring to the same memory as anything
+ in the map.
+
If UNCERTAINTY is non-NULL, use it to record any svalues that
were removed, as being maybe-bound. */
@@ -1663,7 +1711,19 @@ binding_cluster::remove_overlapping_bindings (store_manager *mgr,
{
const binding_key *reg_binding = binding_key::make (mgr, reg);
- m_map.remove_overlapping_bindings (mgr, reg_binding, uncertainty);
+ const region *cluster_base_reg = get_base_region ();
+ const region *other_base_reg = reg->get_base_region ();
+ /* If at least one of the base regions involved is symbolic, and they're
+ not the same base region, then consider everything in the map as
+ potentially overlapping with reg_binding (even if it's a concrete
+ binding and things in the map are concrete - they could be referring
+ to the same memory when the symbolic base regions are taken into
+ account). */
+ bool always_overlap = (cluster_base_reg != other_base_reg
+ && (cluster_base_reg->get_kind () == RK_SYMBOLIC
+ || other_base_reg->get_kind () == RK_SYMBOLIC));
+ m_map.remove_overlapping_bindings (mgr, reg_binding, uncertainty,
+ always_overlap);
}
/* Attempt to merge CLUSTER_A and CLUSTER_B into OUT_CLUSTER, using
@@ -2368,7 +2428,7 @@ store::set_value (store_manager *mgr, const region *lhs_reg,
logger *logger = mgr->get_logger ();
LOG_SCOPE (logger);
- remove_overlapping_bindings (mgr, lhs_reg);
+ remove_overlapping_bindings (mgr, lhs_reg, uncertainty);
rhs_sval = simplify_for_binding (rhs_sval);
@@ -2438,8 +2498,14 @@ store::set_value (store_manager *mgr, const region *lhs_reg,
lhs_reg->dump_to_pp (pp, true);
logger->end_log_line ();
}
- iter_cluster->mark_region_as_unknown (mgr, iter_base_reg,
- uncertainty);
+ /* Mark all of iter_cluster's iter_base_reg as unknown,
+ using LHS_REG when considering overlaps, to handle
+ symbolic vs concrete issues. */
+ iter_cluster->mark_region_as_unknown
+ (mgr,
+ iter_base_reg, /* reg_to_bind */
+ lhs_reg, /* reg_for_overlap */
+ uncertainty);
break;
case tristate::TS_TRUE:
@@ -2603,7 +2669,7 @@ store::mark_region_as_unknown (store_manager *mgr, const region *reg,
|| !base_reg->tracked_p ())
return;
binding_cluster *cluster = get_or_create_cluster (base_reg);
- cluster->mark_region_as_unknown (mgr, reg, uncertainty);
+ cluster->mark_region_as_unknown (mgr, reg, reg, uncertainty);
}
/* Purge state involving SVAL. */
@@ -2826,10 +2892,14 @@ store::get_representative_path_vars (const region_model *model,
}
/* Remove all bindings overlapping REG within this store, removing
- any clusters that become redundant. */
+ any clusters that become redundant.
+
+ If UNCERTAINTY is non-NULL, use it to record any svalues that
+ were removed, as being maybe-bound. */
void
-store::remove_overlapping_bindings (store_manager *mgr, const region *reg)
+store::remove_overlapping_bindings (store_manager *mgr, const region *reg,
+ uncertainty_t *uncertainty)
{
const region *base_reg = reg->get_base_region ();
if (binding_cluster **cluster_slot = m_cluster_map.get (base_reg))
@@ -2842,7 +2912,7 @@ store::remove_overlapping_bindings (store_manager *mgr, const region *reg)
delete cluster;
return;
}
- cluster->remove_overlapping_bindings (mgr, reg, NULL);
+ cluster->remove_overlapping_bindings (mgr, reg, uncertainty);
}
}