summaryrefslogtreecommitdiff
path: root/gcc/analyzer
diff options
context:
space:
mode:
authorDavid Malcolm <dmalcolm@redhat.com>2021-07-22 22:36:05 -0400
committerDavid Malcolm <dmalcolm@redhat.com>2021-07-22 22:36:05 -0400
commit60933a148ab33c82915b40690b3ced6abc32a1bf (patch)
tree04b6d29d7e1fe885237be0172dd4314fd15deb3f /gcc/analyzer
parent3382846558e02044598556e66e5ea1cb3115429d (diff)
downloadgcc-60933a148ab33c82915b40690b3ced6abc32a1bf.tar.gz
analyzer: fix feasibility false +ve with overly complex svalues
gcc/analyzer/ChangeLog: * diagnostic-manager.cc (class auto_disable_complexity_checks): New. (epath_finder::explore_feasible_paths): Use it to disable complexity checks whilst processing the worklist. * region-model-manager.cc (region_model_manager::region_model_manager): Initialize m_check_complexity. (region_model_manager::reject_if_too_complex): Bail if m_check_complexity is false. * region-model.h (region_model_manager::enable_complexity_check): New. (region_model_manager::disable_complexity_check): New. (region_model_manager::m_check_complexity): New. gcc/testsuite/ChangeLog: * gcc.dg/analyzer/feasibility-3.c: New test. Signed-off-by: David Malcolm <dmalcolm@redhat.com>
Diffstat (limited to 'gcc/analyzer')
-rw-r--r--gcc/analyzer/diagnostic-manager.cc47
-rw-r--r--gcc/analyzer/region-model-manager.cc4
-rw-r--r--gcc/analyzer/region-model.h5
3 files changed, 49 insertions, 7 deletions
diff --git a/gcc/analyzer/diagnostic-manager.cc b/gcc/analyzer/diagnostic-manager.cc
index 631fef6ad78..ef3df324365 100644
--- a/gcc/analyzer/diagnostic-manager.cc
+++ b/gcc/analyzer/diagnostic-manager.cc
@@ -292,6 +292,34 @@ private:
const shortest_paths<eg_traits, exploded_path> &m_sep;
};
+/* When we're building the exploded graph we want to simplify
+ overly-complicated symbolic values down to "UNKNOWN" to try to avoid
+ state explosions and unbounded chains of exploration.
+
+ However, when we're building the feasibility graph for a diagnostic
+ (actually a tree), we don't want UNKNOWN values, as conditions on them
+ are also unknown: we don't want to have a contradiction such as a path
+ where (VAL != 0) and then (VAL == 0) along the same path.
+
+ Hence this is an RAII class for temporarily disabling complexity-checking
+ in the region_model_manager, for use within
+ epath_finder::explore_feasible_paths. */
+
+class auto_disable_complexity_checks
+{
+public:
+ auto_disable_complexity_checks (region_model_manager *mgr) : m_mgr (mgr)
+ {
+ m_mgr->disable_complexity_check ();
+ }
+ ~auto_disable_complexity_checks ()
+ {
+ m_mgr->enable_complexity_check ();
+ }
+private:
+ region_model_manager *m_mgr;
+};
+
/* Attempt to find the shortest feasible path from the origin to
TARGET_ENODE by iteratively building a feasible_graph, in which
every path to a feasible_node is feasible by construction.
@@ -344,6 +372,8 @@ epath_finder::explore_feasible_paths (const exploded_node *target_enode,
logger *logger = get_logger ();
LOG_SCOPE (logger);
+ region_model_manager *mgr = m_eg.get_engine ()->get_model_manager ();
+
/* Determine the shortest path to TARGET_ENODE from each node in
the exploded graph. */
shortest_paths<eg_traits, exploded_path> sep
@@ -363,8 +393,7 @@ epath_finder::explore_feasible_paths (const exploded_node *target_enode,
/* Populate the worklist with the origin node. */
{
- feasibility_state init_state (m_eg.get_engine ()->get_model_manager (),
- m_eg.get_supergraph ());
+ feasibility_state init_state (mgr, m_eg.get_supergraph ());
feasible_node *origin = fg.add_node (m_eg.get_origin (), init_state, 0);
worklist.add_node (origin);
}
@@ -376,11 +405,15 @@ epath_finder::explore_feasible_paths (const exploded_node *target_enode,
/* Set this if we find a feasible path to TARGET_ENODE. */
exploded_path *best_path = NULL;
- while (process_worklist_item (&worklist, tg, &fg, target_enode, diag_idx,
- &best_path))
- {
- /* Empty; the work is done within process_worklist_item. */
- }
+ {
+ auto_disable_complexity_checks sentinel (mgr);
+
+ while (process_worklist_item (&worklist, tg, &fg, target_enode, diag_idx,
+ &best_path))
+ {
+ /* Empty; the work is done within process_worklist_item. */
+ }
+ }
if (logger)
{
diff --git a/gcc/analyzer/region-model-manager.cc b/gcc/analyzer/region-model-manager.cc
index fccb93ea5d1..14c57d8e0d8 100644
--- a/gcc/analyzer/region-model-manager.cc
+++ b/gcc/analyzer/region-model-manager.cc
@@ -71,6 +71,7 @@ region_model_manager::region_model_manager ()
m_stack_region (alloc_region_id (), &m_root_region),
m_heap_region (alloc_region_id (), &m_root_region),
m_unknown_NULL (NULL),
+ m_check_complexity (true),
m_max_complexity (0, 0),
m_code_region (alloc_region_id (), &m_root_region),
m_fndecls_map (), m_labels_map (),
@@ -160,6 +161,9 @@ region_model_manager::too_complex_p (const complexity &c) const
bool
region_model_manager::reject_if_too_complex (svalue *sval)
{
+ if (!m_check_complexity)
+ return false;
+
const complexity &c = sval->get_complexity ();
if (!too_complex_p (c))
{
diff --git a/gcc/analyzer/region-model.h b/gcc/analyzer/region-model.h
index cc39929db26..1c7a3865346 100644
--- a/gcc/analyzer/region-model.h
+++ b/gcc/analyzer/region-model.h
@@ -323,6 +323,9 @@ public:
void log_stats (logger *logger, bool show_objs) const;
+ void enable_complexity_check (void) { m_check_complexity = true; }
+ void disable_complexity_check (void) { m_check_complexity = false; }
+
private:
bool too_complex_p (const complexity &c) const;
bool reject_if_too_complex (svalue *sval);
@@ -407,6 +410,8 @@ private:
conjured_svalue *> conjured_values_map_t;
conjured_values_map_t m_conjured_values_map;
+ bool m_check_complexity;
+
/* Maximum complexity of svalues that weren't rejected. */
complexity m_max_complexity;