diff options
-rw-r--r-- | gcc/analyzer/store.cc | 12 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/analyzer/symbolic-12.c | 106 |
2 files changed, 118 insertions, 0 deletions
diff --git a/gcc/analyzer/store.cc b/gcc/analyzer/store.cc index 35f66a4b6fc..f5f8fe061f5 100644 --- a/gcc/analyzer/store.cc +++ b/gcc/analyzer/store.cc @@ -1519,6 +1519,18 @@ binding_cluster::get_any_binding (store_manager *mgr, = get_binding_recursive (mgr, reg)) return direct_sval; + /* If we had a write to a cluster of unknown size, we might + have a self-binding of the whole base region with an svalue, + where the base region is symbolic. + Handle such cases by returning sub_svalue instances. */ + if (const svalue *cluster_sval = maybe_get_simple_value (mgr)) + { + /* Extract child svalue from parent svalue. */ + region_model_manager *rmm_mgr = mgr->get_svalue_manager (); + return rmm_mgr->get_or_create_sub_svalue (reg->get_type (), + cluster_sval, reg); + } + /* If this cluster has been touched by a symbolic write, then the content of any subregion not currently specifically bound is "UNKNOWN". */ if (m_touched) diff --git a/gcc/testsuite/gcc.dg/analyzer/symbolic-12.c b/gcc/testsuite/gcc.dg/analyzer/symbolic-12.c new file mode 100644 index 00000000000..d7c50de9f27 --- /dev/null +++ b/gcc/testsuite/gcc.dg/analyzer/symbolic-12.c @@ -0,0 +1,106 @@ +#include "analyzer-decls.h" + +void external_fn(void); + +struct st_1 +{ + char *name; + unsigned size; +}; + +void test_1a (void *p, unsigned next_off) +{ + struct st_1 *r = p; + + external_fn(); + + if (next_off >= r->size) + return; + + if (next_off >= r->size) + /* We should have already returned if this is the case. */ + __analyzer_dump_path (); /* { dg-bogus "path" } */ +} + +void test_1b (void *p, unsigned next_off) +{ + struct st_1 *r = p; + + if (next_off >= r->size) + return; + + if (next_off >= r->size) + /* We should have already returned if this is the case. */ + __analyzer_dump_path (); /* { dg-bogus "path" } */ +} + +void test_1c (struct st_1 *r, unsigned next_off) +{ + if (next_off >= r->size) + return; + + if (next_off >= r->size) + /* We should have already returned if this is the case. */ + __analyzer_dump_path (); /* { dg-bogus "path" } */ +} + +void test_1d (struct st_1 *r, unsigned next_off) +{ + external_fn(); + + if (next_off >= r->size) + return; + + if (next_off >= r->size) + /* We should have already returned if this is the case. */ + __analyzer_dump_path (); /* { dg-bogus "path" } */ +} + +void test_1e (void *p, unsigned next_off) +{ + struct st_1 *r = p; + + while (1) + { + external_fn(); + + if (next_off >= r->size) + return; + + __analyzer_dump_path (); /* { dg-message "path" } */ + } +} + +struct st_2 +{ + char *name; + unsigned arr[10]; +}; + +void test_2a (void *p, unsigned next_off) +{ + struct st_2 *r = p; + + external_fn(); + + if (next_off >= r->arr[5]) + return; + + if (next_off >= r->arr[5]) + /* We should have already returned if this is the case. */ + __analyzer_dump_path (); /* { dg-bogus "path" } */ +} + +void test_2b (void *p, unsigned next_off, int idx) +{ + struct st_2 *r = p; + + external_fn(); + + if (next_off >= r->arr[idx]) + return; + + if (next_off >= r->arr[idx]) + /* We should have already returned if this is the case. */ + __analyzer_dump_path (); /* { dg-bogus "path" } */ +} |