summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>2009-09-22 14:58:05 +0000
committerrguenth <rguenth@138bc75d-0d04-0410-961f-82ee72b054a4>2009-09-22 14:58:05 +0000
commitafff72577d338d0202f923b9d0d94530c282b2a3 (patch)
tree7e6fe3b018d1707e31a2a61b9b18a4b0501d3846
parent4e8b9ae1bb4321f00513a58a470f16afba8cd136 (diff)
downloadgcc-afff72577d338d0202f923b9d0d94530c282b2a3.tar.gz
2009-09-22 Richard Guenther <rguenther@suse.de>
PR middle-end/41395 * tree-dfa.c (get_ref_base_and_extent): Handle trailing arrays really properly. * gcc.c-torture/execute/pr41395-1.c: New testcase. * gcc.c-torture/execute/pr41395-2.c: Likewise. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@151981 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog6
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr41395-1.c28
-rw-r--r--gcc/testsuite/gcc.c-torture/execute/pr41395-2.c35
-rw-r--r--gcc/tree-dfa.c59
5 files changed, 116 insertions, 18 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 115042b974f..25cc781399a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,9 @@
+2009-09-22 Richard Guenther <rguenther@suse.de>
+
+ PR middle-end/41395
+ * tree-dfa.c (get_ref_base_and_extent): Handle trailing
+ arrays really properly.
+
2009-09-22 Jakub Jelinek <jakub@redhat.com>
* config/rs6000/rs6000.c (bdesc_2arg): Fix CODE_FOR_vector_gt* codes
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 7fc7523ecca..981e8e3833a 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,9 @@
+2009-09-22 Richard Guenther <rguenther@suse.de>
+
+ PR middle-end/41395
+ * gcc.c-torture/execute/pr41395-1.c: New testcase.
+ * gcc.c-torture/execute/pr41395-2.c: Likewise.
+
2009-09-22 Jakub Jelinek <jakub@redhat.com>
* gcc.dg/20090922-1.c: New test.
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr41395-1.c b/gcc/testsuite/gcc.c-torture/execute/pr41395-1.c
new file mode 100644
index 00000000000..e4df0e5d187
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr41395-1.c
@@ -0,0 +1,28 @@
+struct VEC_char_base
+{
+ unsigned num;
+ unsigned alloc;
+ short vec[1];
+};
+
+short __attribute__((noinline))
+foo (struct VEC_char_base *p, int i)
+{
+ short *q;
+ p->vec[i] = 0;
+ q = &p->vec[8];
+ *q = 1;
+ return p->vec[i];
+}
+
+extern void abort (void);
+extern void *malloc (__SIZE_TYPE__);
+
+int
+main()
+{
+ struct VEC_char_base *p = malloc (sizeof (struct VEC_char_base) + 256);
+ if (foo (p, 8) != 1)
+ abort ();
+ return 0;
+}
diff --git a/gcc/testsuite/gcc.c-torture/execute/pr41395-2.c b/gcc/testsuite/gcc.c-torture/execute/pr41395-2.c
new file mode 100644
index 00000000000..c75e963613b
--- /dev/null
+++ b/gcc/testsuite/gcc.c-torture/execute/pr41395-2.c
@@ -0,0 +1,35 @@
+struct VEC_char_base
+{
+ unsigned num;
+ unsigned alloc;
+ union {
+ short vec[1];
+ struct {
+ int i;
+ int j;
+ int k;
+ } a;
+ } u;
+};
+
+short __attribute__((noinline))
+foo (struct VEC_char_base *p, int i)
+{
+ short *q;
+ p->u.vec[i] = 0;
+ q = &p->u.vec[16];
+ *q = 1;
+ return p->u.vec[i];
+}
+
+extern void abort (void);
+extern void *malloc (__SIZE_TYPE__);
+
+int
+main()
+{
+ struct VEC_char_base *p = malloc (sizeof (struct VEC_char_base) + 256);
+ if (foo (p, 16) != 1)
+ abort ();
+ return 0;
+}
diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
index e9a645ef7f2..3fd8477cf7e 100644
--- a/gcc/tree-dfa.c
+++ b/gcc/tree-dfa.c
@@ -752,7 +752,6 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset,
tree size_tree = NULL_TREE;
HOST_WIDE_INT bit_offset = 0;
bool seen_variable_array_ref = false;
- bool seen_union = false;
/* First get the final access size from just the outermost expression. */
if (TREE_CODE (exp) == COMPONENT_REF)
@@ -794,9 +793,6 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset,
tree field = TREE_OPERAND (exp, 1);
tree this_offset = component_ref_field_offset (exp);
- if (TREE_CODE (TREE_TYPE (TREE_OPERAND (exp, 0))) == UNION_TYPE)
- seen_union = true;
-
if (this_offset
&& TREE_CODE (this_offset) == INTEGER_CST
&& host_integerp (this_offset, 0))
@@ -849,6 +845,40 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset,
else
{
tree asize = TYPE_SIZE (TREE_TYPE (TREE_OPERAND (exp, 0)));
+ /* Get at the array size but include trailing padding if
+ the array is the last element of a struct or union. */
+ if (maxsize != -1
+ && TREE_CODE (TREE_OPERAND (exp, 0)) == COMPONENT_REF)
+ {
+ tree cref = TREE_OPERAND (exp, 0);
+ tree field = TREE_OPERAND (cref, 1);
+ tree stype = TREE_TYPE (TREE_OPERAND (cref, 0));
+ tree next = TREE_CHAIN (field);
+ while (next && TREE_CODE (next) != FIELD_DECL)
+ next = TREE_CHAIN (next);
+ if (!next
+ || TREE_CODE (stype) != RECORD_TYPE)
+ {
+ /* The size including padding is the size of
+ the whole structure minus the offset of the
+ array in it. */
+ tree field_offset = component_ref_field_offset (cref);
+ if (field_offset
+ && host_integerp (field_offset, 0)
+ && host_integerp (TYPE_SIZE_UNIT (stype), 0))
+ {
+ unsigned HOST_WIDE_INT as;
+ as = (((TREE_INT_CST_LOW (TYPE_SIZE_UNIT (stype))
+ - TREE_INT_CST_LOW (field_offset))
+ * BITS_PER_UNIT)
+ - TREE_INT_CST_LOW
+ (DECL_FIELD_BIT_OFFSET (field)));
+ asize = build_int_cstu (sizetype, as);
+ }
+ else
+ asize = NULL_TREE;
+ }
+ }
/* We need to adjust maxsize to the whole array bitsize.
But we can subtract any constant offset seen so far,
because that would get us outside of the array otherwise. */
@@ -887,25 +917,18 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset,
struct { int length; int a[1]; } x; x.a[d]
struct { struct { int a; int b; } a[1]; } x; x.a[d].a
struct { struct { int a[1]; } a[1]; } x; x.a[0][d], x.a[d][0]
+ struct { int len; union { int a[1]; struct X x; } u; } x; x.u.a[d]
where we do not know maxsize for variable index accesses to
the array. The simplest way to conservatively deal with this
is to punt in the case that offset + maxsize reaches the
- base type boundary.
-
- Unfortunately this is difficult to determine reliably when unions are
- involved and so we are conservative in such cases.
-
- FIXME: This approach may be too conservative, we probably want to at least
- check that the union is the last field/element at its level or even
- propagate the calculated offsets back up the access chain and check
- there. */
+ base type boundary. This needs to include possible trailing padding
+ that is there for alignment purposes. */
if (seen_variable_array_ref
- && (seen_union
- || (maxsize != -1
- && host_integerp (TYPE_SIZE (TREE_TYPE (exp)), 1)
- && bit_offset + maxsize
- == (signed) TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (exp))))))
+ && (maxsize != -1
+ && host_integerp (TYPE_SIZE (TREE_TYPE (exp)), 1)
+ && bit_offset + maxsize
+ == (signed) TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (exp)))))
maxsize = -1;
/* ??? Due to negative offsets in ARRAY_REF we can end up with