@@ -782,15 +782,22 @@ region_model_manager::maybe_fold_sub_svalue (tree type,
/* Handle getting individual chars from a STRING_CST. */
if (tree cst = parent_svalue->maybe_get_constant ())
if (TREE_CODE (cst) == STRING_CST)
- if (const element_region *element_reg
- = subregion->dyn_cast_element_region ())
- {
- const svalue *idx_sval = element_reg->get_index ();
- if (tree cst_idx = idx_sval->maybe_get_constant ())
+ {
+ /* If we have a concrete 1-byte access within the parent region... */
+ byte_range subregion_bytes (0, 0);
+ if (subregion->get_relative_concrete_byte_range (&subregion_bytes)
+ && subregion_bytes.m_size_in_bytes == 1)
+ {
+ /* ...then attempt to get that char from the STRING_CST. */
+ HOST_WIDE_INT hwi_start_byte
+ = subregion_bytes.m_start_byte_offset.to_shwi ();
+ tree cst_idx
+ = build_int_cst_type (size_type_node, hwi_start_byte);
if (const svalue *char_sval
= maybe_get_char_from_string_cst (cst, cst_idx))
return get_or_create_cast (type, char_sval);
- }
+ }
+ }
if (const initial_svalue *init_sval
= parent_svalue->dyn_cast_initial_svalue ())
@@ -539,6 +539,34 @@ region::get_relative_concrete_offset (bit_offset_t *) const
return false;
}
+/* Attempt to get the position and size of this region expressed as a
+ concrete range of bytes relative to its parent.
+ If successful, return true and write to *OUT.
+ Otherwise return false. */
+
+bool
+region::get_relative_concrete_byte_range (byte_range *out) const
+{
+ /* We must have a concrete offset relative to the parent. */
+ bit_offset_t rel_bit_offset;
+ if (!get_relative_concrete_offset (&rel_bit_offset))
+ return false;
+ /* ...which must be a whole number of bytes. */
+ if (rel_bit_offset % BITS_PER_UNIT != 0)
+ return false;
+ byte_offset_t start_byte_offset = rel_bit_offset / BITS_PER_UNIT;
+
+ /* We must have a concrete size, which must be a whole number
+ of bytes. */
+ byte_size_t num_bytes;
+ if (!get_byte_size (&num_bytes))
+ return false;
+
+ /* Success. */
+ *out = byte_range (start_byte_offset, num_bytes);
+ return true;
+}
+
/* Dump a description of this region to stderr. */
DEBUG_FUNCTION void
@@ -182,6 +182,12 @@ public:
Otherwise return false. */
virtual bool get_relative_concrete_offset (bit_offset_t *out) const;
+ /* Attempt to get the position and size of this region expressed as a
+ concrete range of bytes relative to its parent.
+ If successful, return true and write to *OUT.
+ Otherwise return false. */
+ bool get_relative_concrete_byte_range (byte_range *out) const;
+
void
get_subregions_for_binding (region_model_manager *mgr,
bit_offset_t start_bit_offset,
@@ -13,6 +13,14 @@ struct s2
char arr[4];
};
+struct s3
+{
+ struct inner {
+ char a;
+ char b;
+ } arr[2];
+};
+
void test_1 ()
{
struct s1 x = {'A', 'B', 'C', 'D'};
@@ -24,10 +32,16 @@ void test_1 ()
__analyzer_eval (((struct s2 *)&x)->arr[1] == 'B'); /* { dg-warning "TRUE" } */
__analyzer_eval (((struct s2 *)&x)->arr[2] == 'C'); /* { dg-warning "TRUE" } */
__analyzer_eval (((struct s2 *)&x)->arr[3] == 'D'); /* { dg-warning "TRUE" } */
+ struct s3 *p3 = (struct s3 *)&x;
+ __analyzer_eval (p3->arr[0].a == 'A'); /* { dg-warning "TRUE" } */
+ __analyzer_eval (p3->arr[0].b == 'B'); /* { dg-warning "TRUE" } */
+ __analyzer_eval (p3->arr[1].a == 'C'); /* { dg-warning "TRUE" } */
+ __analyzer_eval (p3->arr[1].b == 'D'); /* { dg-warning "TRUE" } */
((struct s2 *)&x)->arr[1] = '#';
__analyzer_eval (((struct s2 *)&x)->arr[1] == '#'); /* { dg-warning "TRUE" } */
__analyzer_eval (x.b == '#'); /* { dg-warning "TRUE" } */
+ __analyzer_eval (p3->arr[0].b == '#'); /* { dg-warning "TRUE" } */
}
void test_2 ()
@@ -38,12 +52,27 @@ void test_2 ()
__analyzer_eval (x.arr[2] == 'C'); /* { dg-warning "TRUE" } */
__analyzer_eval (x.arr[3] == 'D'); /* { dg-warning "TRUE" } */
struct s1 *p = (struct s1 *)&x;
- __analyzer_eval (p->a == 'A'); /* { dg-warning "TRUE" "true" { xfail *-*-* } } */
- /* { dg-bogus "UNKNOWN" "unknown" { xfail *-*-* } .-1 } */
- __analyzer_eval (p->b == 'B'); /* { dg-warning "TRUE" "true" { xfail *-*-* } } */
- /* { dg-bogus "UNKNOWN" "unknown" { xfail *-*-* } .-1 } */
- __analyzer_eval (p->c == 'C'); /* { dg-warning "TRUE" "true" { xfail *-*-* } } */
- /* { dg-bogus "UNKNOWN" "unknown" { xfail *-*-* } .-1 } */
- __analyzer_eval (p->d == 'D'); /* { dg-warning "TRUE" "true" { xfail *-*-* } } */
- /* { dg-bogus "UNKNOWN" "unknown" { xfail *-*-* } .-1 } */
+ __analyzer_eval (p->a == 'A'); /* { dg-warning "TRUE" } */
+ __analyzer_eval (p->b == 'B'); /* { dg-warning "TRUE" } */
+ __analyzer_eval (p->c == 'C'); /* { dg-warning "TRUE" } */
+ __analyzer_eval (p->d == 'D'); /* { dg-warning "TRUE" } */
+}
+
+void test_3 ()
+{
+ struct s3 x = {'A', 'B', 'C', 'D'};
+ __analyzer_eval (x.arr[0].a == 'A'); /* { dg-warning "TRUE" } */
+ __analyzer_eval (x.arr[0].b == 'B'); /* { dg-warning "TRUE" } */
+ __analyzer_eval (x.arr[1].a == 'C'); /* { dg-warning "TRUE" } */
+ __analyzer_eval (x.arr[1].b == 'D'); /* { dg-warning "TRUE" } */
+ struct s1 *p1 = (struct s1 *)&x;
+ __analyzer_eval (p1->a == 'A'); /* { dg-warning "TRUE" } */
+ __analyzer_eval (p1->b == 'B'); /* { dg-warning "TRUE" } */
+ __analyzer_eval (p1->c == 'C'); /* { dg-warning "TRUE" } */
+ __analyzer_eval (p1->d == 'D'); /* { dg-warning "TRUE" } */
+ struct s2 *p2 = (struct s2 *)&x;
+ __analyzer_eval (p2->arr[0] == 'A'); /* { dg-warning "TRUE" } */
+ __analyzer_eval (p2->arr[1] == 'B'); /* { dg-warning "TRUE" } */
+ __analyzer_eval (p2->arr[2] == 'C'); /* { dg-warning "TRUE" } */
+ __analyzer_eval (p2->arr[3] == 'D'); /* { dg-warning "TRUE" } */
}
Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu. Pushed to trunk as r12-7184-g2ac7b19f1e9219f46ccf55f25d8acb3e02e9a2d4. gcc/analyzer/ChangeLog: PR analyzer/98797 * region-model-manager.cc (region_model_manager::maybe_fold_sub_svalue): Generalize getting individual chars of a STRING_CST from element_region to any subregion which is a concrete access of a single byte from its parent region. * region.cc (region::get_relative_concrete_byte_range): New. * region.h (region::get_relative_concrete_byte_range): New decl. gcc/testsuite/ChangeLog: PR analyzer/98797 * gcc.dg/analyzer/casts-1.c: Mark xfails as fixed; add further test coverage for casts of string literals. Signed-off-by: David Malcolm <dmalcolm@redhat.com> --- gcc/analyzer/region-model-manager.cc | 19 +++++++---- gcc/analyzer/region.cc | 28 +++++++++++++++ gcc/analyzer/region.h | 6 ++++ gcc/testsuite/gcc.dg/analyzer/casts-1.c | 45 ++++++++++++++++++++----- 4 files changed, 84 insertions(+), 14 deletions(-)