This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] Fix PR41395


This tries to fix PR41395, an issue with get_ref_base_and_extent and
trailing arrays (again).

Bootstrap and regtest running on x86_64-unknown-linux-gnu (but without
re-enabling IPA-SRA).

Richard.

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.

Index: gcc/testsuite/gcc.c-torture/execute/pr41395-1.c
===================================================================
*** gcc/testsuite/gcc.c-torture/execute/pr41395-1.c	(revision 0)
--- gcc/testsuite/gcc.c-torture/execute/pr41395-1.c	(revision 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;
+ }
Index: gcc/testsuite/gcc.c-torture/execute/pr41395-2.c
===================================================================
*** gcc/testsuite/gcc.c-torture/execute/pr41395-2.c	(revision 0)
--- gcc/testsuite/gcc.c-torture/execute/pr41395-2.c	(revision 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;
+ }
Index: gcc/tree-dfa.c
===================================================================
*** gcc/tree-dfa.c	(revision 151967)
--- gcc/tree-dfa.c	(working copy)
*************** get_ref_base_and_extent (tree exp, HOST_
*** 752,758 ****
    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)
--- 752,757 ----
*************** get_ref_base_and_extent (tree exp, HOST_
*** 794,802 ****
  	    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))
--- 793,798 ----
*************** get_ref_base_and_extent (tree exp, HOST_
*** 849,854 ****
--- 845,884 ----
  	    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.  */
*************** get_ref_base_and_extent (tree exp, HOST_
*** 887,911 ****
         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]
       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.  */
  
    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;
  
    /* ???  Due to negative offsets in ARRAY_REF we can end up with
--- 917,934 ----
         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.  This needs to include possible trailing padding
!      that is there for alignment purposes.  */
  
    if (seen_variable_array_ref
!       && (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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]