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] __builtin_object_size improvements


Hi!

__builtin_object_size doesn't handle ADDR_EXPRs which INDIRECT_REF base
address, e.g. for simple
struct A { char a[10]; char b[10]; char c[10]; };
struct A *p = malloc (sizeof (*p));
__builtin_object_size (&p->b, 0)
currently returns -1UL, while it can easily find out that there are
20 bytes after &p->b[0].  For
__builtin_object_size (&q->b, 1)
(i.e. the variant used for -D_FORTIFY_SOURCE=2 by strcpy etc., but not memcpy)
even if __builtin_object_size (q, 1) is -1UL, we can still find an upper
limit, 10, because for -D_FORTIFY_SOURCE=2 strcpy etc. isn't allowed to
copy accross field boundaries.
The patch below implements both of these, with the exception that if
the field is at the end of the structure and base is INDIRECT_REF,
__bos (x, 1) behaves like __bos (x, 0), because there is tons of code out
there that uses arrays at the end of a structure instead of flexible array
members and I wouldn't like to break code like:
struct A { int i; char c[1]; };
struct A *p = malloc (sizeof (*p) + strlen ("abcde"));
strcpy (p->c, "abcde");

Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?

2009-06-04  Jakub Jelinek  <jakub@redhat.com>

	* tree-object-size.c (addr_object_size): Add OSI argument.
	Handle also INDIRECT_REF with SSA_NAME inside of it as base address.
	(compute_builtin_object_size, expr_object_size): Adjust callers.
	(plus_stmt_object_size): Call addr_object_size instead of
	compute_builtin_object_size.

	* gcc.dg/builtin-object-size-2.c (test1): Adjust expected results.
	* gcc.dg/builtin-object-size-4.c (test1): Adjust expected results.
	* gcc.dg/builtin-object-size-6.c: New test.

--- gcc/tree-object-size.c.jj	2009-05-13 08:42:59.000000000 +0200
+++ gcc/tree-object-size.c	2009-06-04 18:47:03.000000000 +0200
@@ -43,7 +43,8 @@ struct object_size_info
 static unsigned HOST_WIDE_INT unknown[4] = { -1, -1, 0, 0 };
 
 static tree compute_object_offset (const_tree, const_tree);
-static unsigned HOST_WIDE_INT addr_object_size (const_tree, int);
+static unsigned HOST_WIDE_INT addr_object_size (struct object_size_info *,
+						const_tree, int);
 static unsigned HOST_WIDE_INT alloc_object_size (const_gimple, int);
 static tree pass_through_call (const_gimple);
 static void collect_object_sizes_for (struct object_size_info *, tree);
@@ -152,9 +153,10 @@ compute_object_offset (const_tree expr, 
    If unknown, return unknown[object_size_type].  */
 
 static unsigned HOST_WIDE_INT
-addr_object_size (const_tree ptr, int object_size_type)
+addr_object_size (struct object_size_info *osi, const_tree ptr,
+		  int object_size_type)
 {
-  tree pt_var;
+  tree pt_var, pt_var_size = NULL_TREE, var_size, bytes;
 
   gcc_assert (TREE_CODE (ptr) == ADDR_EXPR);
 
@@ -163,58 +165,157 @@ addr_object_size (const_tree ptr, int ob
     pt_var = get_base_address (pt_var);
 
   if (pt_var
-      && (SSA_VAR_P (pt_var) || TREE_CODE (pt_var) == STRING_CST)
-      && TYPE_SIZE_UNIT (TREE_TYPE (pt_var))
-      && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)), 1)
-      && (unsigned HOST_WIDE_INT)
-	 tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)), 1) < offset_limit)
+      && TREE_CODE (pt_var) == INDIRECT_REF
+      && TREE_CODE (TREE_OPERAND (pt_var, 0)) == SSA_NAME
+      && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (pt_var, 0))))
+    {
+      unsigned HOST_WIDE_INT sz;
+
+      if (!osi)
+	sz = compute_builtin_object_size (TREE_OPERAND (pt_var, 0),
+					  object_size_type);
+      else
+	{
+	  tree var = TREE_OPERAND (pt_var, 0);
+	  if (osi->pass == 0)
+	    collect_object_sizes_for (osi, var);
+	  if (bitmap_bit_p (computed[object_size_type],
+			    SSA_NAME_VERSION (var)))
+	    sz = object_sizes[object_size_type][SSA_NAME_VERSION (var)];
+	  else
+	    sz = unknown[object_size_type];
+	}
+
+      if (sz != unknown[object_size_type] && sz < offset_limit)
+	pt_var_size = size_int (sz);
+    }
+  else if (pt_var
+	   && (SSA_VAR_P (pt_var) || TREE_CODE (pt_var) == STRING_CST)
+	   && TYPE_SIZE_UNIT (TREE_TYPE (pt_var))
+	   && host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)), 1)
+	   && (unsigned HOST_WIDE_INT)
+	      tree_low_cst (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)), 1)
+	      < offset_limit)
+    pt_var_size = TYPE_SIZE_UNIT (TREE_TYPE (pt_var));
+  else
+    return unknown[object_size_type];
+
+  if (pt_var != TREE_OPERAND (ptr, 0))
     {
-      tree bytes;
+      tree var;
 
-      if (pt_var != TREE_OPERAND (ptr, 0))
+      if (object_size_type & 1)
 	{
-	  tree var;
+	  var = TREE_OPERAND (ptr, 0);
 
-	  if (object_size_type & 1)
+	  while (var != pt_var
+		 && TREE_CODE (var) != BIT_FIELD_REF
+		 && TREE_CODE (var) != COMPONENT_REF
+		 && TREE_CODE (var) != ARRAY_REF
+		 && TREE_CODE (var) != ARRAY_RANGE_REF
+		 && TREE_CODE (var) != REALPART_EXPR
+		 && TREE_CODE (var) != IMAGPART_EXPR)
+	    var = TREE_OPERAND (var, 0);
+	  if (var != pt_var && TREE_CODE (var) == ARRAY_REF)
+	      var = TREE_OPERAND (var, 0);
+	  if (! TYPE_SIZE_UNIT (TREE_TYPE (var))
+	      || ! host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (var)), 1)
+	      || (pt_var_size
+		  && tree_int_cst_lt (pt_var_size,
+				      TYPE_SIZE_UNIT (TREE_TYPE (var)))))
+	    var = pt_var;
+	  else if (var != pt_var && TREE_CODE (pt_var) == INDIRECT_REF)
 	    {
-	      var = TREE_OPERAND (ptr, 0);
-
-	      while (var != pt_var
-		      && TREE_CODE (var) != BIT_FIELD_REF
-		      && TREE_CODE (var) != COMPONENT_REF
-		      && TREE_CODE (var) != ARRAY_REF
-		      && TREE_CODE (var) != ARRAY_RANGE_REF
-		      && TREE_CODE (var) != REALPART_EXPR
-		      && TREE_CODE (var) != IMAGPART_EXPR)
-		var = TREE_OPERAND (var, 0);
-	      if (var != pt_var && TREE_CODE (var) == ARRAY_REF)
-		var = TREE_OPERAND (var, 0);
-	      if (! TYPE_SIZE_UNIT (TREE_TYPE (var))
-		  || ! host_integerp (TYPE_SIZE_UNIT (TREE_TYPE (var)), 1)
-		  || tree_int_cst_lt (TYPE_SIZE_UNIT (TREE_TYPE (pt_var)),
-				      TYPE_SIZE_UNIT (TREE_TYPE (var))))
+	      tree v = var;
+	      /* For &X->fld, compute object size only if fld isn't the last
+		 field, as struct { int i; char c[1]; } is often used instead
+		 of flexible array member.  */
+	      while (v && v != pt_var)
+		switch (TREE_CODE (v))
+		  {
+		  case ARRAY_REF:
+		    if (TYPE_SIZE_UNIT (TREE_TYPE (TREE_OPERAND (v, 0)))
+			&& TREE_CODE (TREE_OPERAND (v, 1)) == INTEGER_CST)
+		      {
+			tree domain
+			  = TYPE_DOMAIN (TREE_TYPE (TREE_OPERAND (v, 0)));
+			if (domain
+			    && TYPE_MAX_VALUE (domain)
+			    && TREE_CODE (TYPE_MAX_VALUE (domain))
+			       == INTEGER_CST
+			    && tree_int_cst_lt (TREE_OPERAND (v, 1),
+						TYPE_MAX_VALUE (domain)))
+			  {
+			    v = NULL_TREE;
+			    break;
+			  }
+		      }
+		    v = TREE_OPERAND (v, 0);
+		    break;
+		  case REALPART_EXPR:
+		  case IMAGPART_EXPR:
+		    v = NULL_TREE;
+		    break;
+		  case COMPONENT_REF:
+		    if (TREE_CODE (TREE_TYPE (TREE_OPERAND (v, 0)))
+			== RECORD_TYPE
+			&& TREE_CHAIN (TREE_OPERAND (v, 1)))
+		      {
+			v = NULL_TREE;
+			break;
+		      }
+		    v = TREE_OPERAND (v, 0);
+		    break;
+		  default:
+		    v = pt_var;
+		    break;
+		  }
+	      if (v == pt_var)
 		var = pt_var;
 	    }
-	  else
-	    var = pt_var;
+	}
+      else
+	var = pt_var;
 
-	  bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var);
-	  if (bytes != error_mark_node)
+      if (var != pt_var)
+	var_size = TYPE_SIZE_UNIT (TREE_TYPE (var));
+      else if (!pt_var_size)
+	return unknown[object_size_type];
+      else
+	var_size = pt_var_size;
+      bytes = compute_object_offset (TREE_OPERAND (ptr, 0), var);
+      if (bytes != error_mark_node)
+	{
+	  if (TREE_CODE (bytes) == INTEGER_CST
+	      && tree_int_cst_lt (var_size, bytes))
+	    bytes = size_zero_node;
+	  else
+	    bytes = size_binop (MINUS_EXPR, var_size, bytes);
+	}
+      if (var != pt_var
+	  && pt_var_size
+	  && TREE_CODE (pt_var) == INDIRECT_REF
+	  && bytes != error_mark_node)
+	{
+	  tree bytes2 = compute_object_offset (TREE_OPERAND (ptr, 0), pt_var);
+	  if (bytes2 != error_mark_node)
 	    {
-	      if (TREE_CODE (bytes) == INTEGER_CST
-		  && tree_int_cst_lt (TYPE_SIZE_UNIT (TREE_TYPE (var)), bytes))
-		bytes = size_zero_node;
+	      if (TREE_CODE (bytes2) == INTEGER_CST
+		  && tree_int_cst_lt (pt_var_size, bytes2))
+		bytes2 = size_zero_node;
 	      else
-		bytes = size_binop (MINUS_EXPR,
-				    TYPE_SIZE_UNIT (TREE_TYPE (var)), bytes);
+		bytes2 = size_binop (MINUS_EXPR, var_size, bytes2);
+	      bytes = size_binop (MIN_EXPR, bytes, bytes2);
 	    }
 	}
-      else
-	bytes = TYPE_SIZE_UNIT (TREE_TYPE (pt_var));
-
-      if (host_integerp (bytes, 1))
-	return tree_low_cst (bytes, 1);
     }
+  else if (!pt_var_size)
+    return unknown[object_size_type];
+  else
+    bytes = pt_var_size;
+
+  if (host_integerp (bytes, 1))
+    return tree_low_cst (bytes, 1);
 
   return unknown[object_size_type];
 }
@@ -332,11 +433,11 @@ compute_builtin_object_size (tree ptr, i
     init_offset_limit ();
 
   if (TREE_CODE (ptr) == ADDR_EXPR)
-    return addr_object_size (ptr, object_size_type);
+    return addr_object_size (NULL, ptr, object_size_type);
 
   if (TREE_CODE (ptr) == SSA_NAME
-	   && POINTER_TYPE_P (TREE_TYPE (ptr))
-	   && object_sizes[object_size_type] != NULL)
+      && POINTER_TYPE_P (TREE_TYPE (ptr))
+      && object_sizes[object_size_type] != NULL)
     {
       if (!bitmap_bit_p (computed[object_size_type], SSA_NAME_VERSION (ptr)))
 	{
@@ -477,7 +578,7 @@ expr_object_size (struct object_size_inf
 	      || !POINTER_TYPE_P (TREE_TYPE (value)));
 
   if (TREE_CODE (value) == ADDR_EXPR)
-    bytes = addr_object_size (value, object_size_type);
+    bytes = addr_object_size (osi, value, object_size_type);
   else
     bytes = unknown[object_size_type];
 
@@ -633,7 +734,7 @@ plus_stmt_object_size (struct object_siz
 	  unsigned HOST_WIDE_INT off = tree_low_cst (op1, 1);
 
           /* op0 will be ADDR_EXPR here.  */
-	  bytes = compute_builtin_object_size (op0, object_size_type);
+	  bytes = addr_object_size (osi, op0, object_size_type);
 	  if (bytes == unknown[object_size_type])
 	    ;
 	  else if (off > offset_limit)
--- gcc/testsuite/gcc.dg/builtin-object-size-2.c.jj	2008-09-05 12:54:37.000000000 +0200
+++ gcc/testsuite/gcc.dg/builtin-object-size-2.c	2009-06-04 17:38:18.000000000 +0200
@@ -130,13 +130,13 @@ test1 (void *q, int x)
     abort ();    
   if (__builtin_object_size (&vara[5], 1) != (size_t) -1)
     abort ();
-  if (__builtin_object_size (&vara[0].a, 1) != (size_t) -1)
+  if (__builtin_object_size (&vara[0].a, 1) != sizeof (vara[0].a))
     abort ();
-  if (__builtin_object_size (&vara[10].a[0], 1) != (size_t) -1)
+  if (__builtin_object_size (&vara[10].a[0], 1) != sizeof (vara[0].a))
     abort ();
-  if (__builtin_object_size (&vara[5].a[4], 1) != (size_t) -1)
+  if (__builtin_object_size (&vara[5].a[4], 1) != sizeof (vara[0].a) - 4)
     abort ();
-  if (__builtin_object_size (&vara[5].b, 1) != (size_t) -1)
+  if (__builtin_object_size (&vara[5].b, 1) != sizeof (vara[0].b))
     abort ();
   if (__builtin_object_size (&vara[7].c[7], 1) != (size_t) -1)
     abort ();
--- gcc/testsuite/gcc.dg/builtin-object-size-4.c.jj	2008-09-05 12:54:37.000000000 +0200
+++ gcc/testsuite/gcc.dg/builtin-object-size-4.c	2009-06-04 17:56:47.000000000 +0200
@@ -130,13 +130,13 @@ test1 (void *q, int x)
     abort ();    
   if (__builtin_object_size (&vara[5], 3) != 0)
     abort ();
-  if (__builtin_object_size (&vara[0].a, 3) != 0)
+  if (__builtin_object_size (&vara[0].a, 3) != sizeof (vara[0].a))
     abort ();
-  if (__builtin_object_size (&vara[10].a[0], 3) != 0)
+  if (__builtin_object_size (&vara[10].a[0], 3) != sizeof (vara[0].a))
     abort ();
-  if (__builtin_object_size (&vara[5].a[4], 3) != 0)
+  if (__builtin_object_size (&vara[5].a[4], 3) != sizeof (vara[0].a) - 4)
     abort ();
-  if (__builtin_object_size (&vara[5].b, 3) != 0)
+  if (__builtin_object_size (&vara[5].b, 3) != sizeof (vara[0].b))
     abort ();
   if (__builtin_object_size (&vara[7].c[7], 3) != 0)
     abort ();
--- gcc/testsuite/gcc.dg/builtin-object-size-6.c.jj	2009-06-04 18:13:13.000000000 +0200
+++ gcc/testsuite/gcc.dg/builtin-object-size-6.c	2009-06-04 19:09:35.000000000 +0200
@@ -0,0 +1,327 @@
+/* { dg-do run } */
+/* { dg-options "-O2" } */
+
+typedef __SIZE_TYPE__ size_t;
+extern void abort (void);
+extern void exit (int);
+extern void *malloc (size_t);
+extern void free (void *);
+
+struct A
+{
+  char a[10];
+  int b;
+  char c[10];
+};
+
+void
+__attribute__ ((noinline))
+test1 (struct A *p)
+{
+  char *c;
+  if (__builtin_object_size (&p->a, 0) != (size_t) -1)
+    abort ();
+  if (__builtin_object_size (&p->a[0], 0) != (size_t) -1)
+    abort ();
+  if (__builtin_object_size (&p->a[3], 0) != (size_t) -1)
+    abort ();
+  if (__builtin_object_size (&p->b, 0) != (size_t) -1)
+    abort ();
+  if (__builtin_object_size (&p->c, 0) != (size_t) -1)
+    abort ();
+  c = p->a;
+  if (__builtin_object_size (c, 0) != (size_t) -1)
+    abort ();
+  c = &p->a[0];
+  if (__builtin_object_size (c, 0) != (size_t) -1)
+    abort ();
+  c = &p->a[3];
+  if (__builtin_object_size (c, 0) != (size_t) -1)
+    abort ();
+  c = (char *) &p->b;
+  if (__builtin_object_size (c, 0) != (size_t) -1)
+    abort ();
+  c = (char *) &p->c;
+  if (__builtin_object_size (c, 0) != (size_t) -1)
+    abort ();
+  if (__builtin_object_size (&p->a, 1) != sizeof (p->a))
+    abort ();
+  if (__builtin_object_size (&p->a[0], 1) != sizeof (p->a))
+    abort ();
+  if (__builtin_object_size (&p->a[3], 1) != sizeof (p->a) - 3)
+    abort ();
+  if (__builtin_object_size (&p->b, 1) != sizeof (p->b))
+    abort ();
+  if (__builtin_object_size (&p->c, 1) != (size_t) -1)
+    abort ();
+  c = p->a;
+  if (__builtin_object_size (c, 1) != sizeof (p->a))
+    abort ();
+  c = &p->a[0];
+  if (__builtin_object_size (c, 1) != sizeof (p->a))
+    abort ();
+  c = &p->a[3];
+  if (__builtin_object_size (c, 1) != sizeof (p->a) - 3)
+    abort ();
+  c = (char *) &p->b;
+  if (__builtin_object_size (c, 1) != sizeof (p->b))
+    abort ();
+  c = (char *) &p->c;
+  if (__builtin_object_size (c, 1) != (size_t) -1)
+    abort ();
+  if (__builtin_object_size (&p->a, 2) != 0)
+    abort ();
+  if (__builtin_object_size (&p->a[0], 2) != 0)
+    abort ();
+  if (__builtin_object_size (&p->a[3], 2) != 0)
+    abort ();
+  if (__builtin_object_size (&p->b, 2) != 0)
+    abort ();
+  if (__builtin_object_size (&p->c, 2) != 0)
+    abort ();
+  c = p->a;
+  if (__builtin_object_size (c, 2) != 0)
+    abort ();
+  c = &p->a[0];
+  if (__builtin_object_size (c, 2) != 0)
+    abort ();
+  c = &p->a[3];
+  if (__builtin_object_size (c, 2) != 0)
+    abort ();
+  c = (char *) &p->b;
+  if (__builtin_object_size (c, 2) != 0)
+    abort ();
+  c = (char *) &p->c;
+  if (__builtin_object_size (c, 2) != 0)
+    abort ();
+  if (__builtin_object_size (&p->a, 3) != sizeof (p->a))
+    abort ();
+  if (__builtin_object_size (&p->a[0], 3) != sizeof (p->a))
+    abort ();
+  if (__builtin_object_size (&p->a[3], 3) != sizeof (p->a) - 3)
+    abort ();
+  if (__builtin_object_size (&p->b, 3) != sizeof (p->b))
+    abort ();
+  if (__builtin_object_size (&p->c, 3) != 0)
+    abort ();
+  c = p->a;
+  if (__builtin_object_size (c, 3) != sizeof (p->a))
+    abort ();
+  c = &p->a[0];
+  if (__builtin_object_size (c, 3) != sizeof (p->a))
+    abort ();
+  c = &p->a[3];
+  if (__builtin_object_size (c, 3) != sizeof (p->a) - 3)
+    abort ();
+  c = (char *) &p->b;
+  if (__builtin_object_size (c, 3) != sizeof (p->b))
+    abort ();
+  c = (char *) &p->c;
+  if (__builtin_object_size (c, 3) != 0)
+    abort ();
+}
+
+void
+__attribute__ ((noinline))
+test2 (void)
+{
+  char *c;
+  size_t s = 2 * sizeof (struct A);
+  struct A *p = malloc (2 * sizeof (struct A));
+  if (__builtin_object_size (&p->a, 0) != s)
+    abort ();
+  if (__builtin_object_size (&p->a[0], 0) != s)
+    abort ();
+  if (__builtin_object_size (&p->a[3], 0) != s - 3)
+    abort ();
+  if (__builtin_object_size (&p->b, 0) != s - __builtin_offsetof (struct A, b))
+    abort ();
+  if (__builtin_object_size (&p->c, 0) != s - __builtin_offsetof (struct A, c))
+    abort ();
+  c = p->a;
+  if (__builtin_object_size (c, 0) != s)
+    abort ();
+  c = &p->a[0];
+  if (__builtin_object_size (c, 0) != s)
+    abort ();
+  c = &p->a[3];
+  if (__builtin_object_size (c, 0) != s - 3)
+    abort ();
+  c = (char *) &p->b;
+  if (__builtin_object_size (c, 0) != s - __builtin_offsetof (struct A, b))
+    abort ();
+  c = (char *) &p->c;
+  if (__builtin_object_size (c, 0) != s - __builtin_offsetof (struct A, c))
+    abort ();
+  if (__builtin_object_size (&p->a, 1) != sizeof (p->a))
+    abort ();
+  if (__builtin_object_size (&p->a[0], 1) != sizeof (p->a))
+    abort ();
+  if (__builtin_object_size (&p->a[3], 1) != sizeof (p->a) - 3)
+    abort ();
+  if (__builtin_object_size (&p->b, 1) != sizeof (p->b))
+    abort ();
+  if (__builtin_object_size (&p->c, 1) != s - __builtin_offsetof (struct A, c))
+    abort ();
+  c = p->a;
+  if (__builtin_object_size (c, 1) != sizeof (p->a))
+    abort ();
+  c = &p->a[0];
+  if (__builtin_object_size (c, 1) != sizeof (p->a))
+    abort ();
+  c = &p->a[3];
+  if (__builtin_object_size (c, 1) != sizeof (p->a) - 3)
+    abort ();
+  c = (char *) &p->b;
+  if (__builtin_object_size (c, 1) != sizeof (p->b))
+    abort ();
+  c = (char *) &p->c;
+  if (__builtin_object_size (c, 1) != s - __builtin_offsetof (struct A, c))
+    abort ();
+  if (__builtin_object_size (&p->a, 2) != s)
+    abort ();
+  if (__builtin_object_size (&p->a[0], 2) != s)
+    abort ();
+  if (__builtin_object_size (&p->a[3], 2) != s - 3)
+    abort ();
+  if (__builtin_object_size (&p->b, 2) != s - __builtin_offsetof (struct A, b))
+    abort ();
+  if (__builtin_object_size (&p->c, 2) != s - __builtin_offsetof (struct A, c))
+    abort ();
+  c = p->a;
+  if (__builtin_object_size (c, 2) != s)
+    abort ();
+  c = &p->a[0];
+  if (__builtin_object_size (c, 2) != s)
+    abort ();
+  c = &p->a[3];
+  if (__builtin_object_size (c, 2) != s - 3)
+    abort ();
+  c = (char *) &p->b;
+  if (__builtin_object_size (c, 2) != s - __builtin_offsetof (struct A, b))
+    abort ();
+  c = (char *) &p->c;
+  if (__builtin_object_size (c, 2) != s - __builtin_offsetof (struct A, c))
+    abort ();
+  if (__builtin_object_size (&p->a, 3) != sizeof (p->a))
+    abort ();
+  if (__builtin_object_size (&p->a[0], 3) != sizeof (p->a))
+    abort ();
+  if (__builtin_object_size (&p->a[3], 3) != sizeof (p->a) - 3)
+    abort ();
+  if (__builtin_object_size (&p->b, 3) != sizeof (p->b))
+    abort ();
+  if (__builtin_object_size (&p->c, 3) != s - __builtin_offsetof (struct A, c))
+    abort ();
+  c = p->a;
+  if (__builtin_object_size (c, 3) != sizeof (p->a))
+    abort ();
+  c = &p->a[0];
+  if (__builtin_object_size (c, 3) != sizeof (p->a))
+    abort ();
+  c = &p->a[3];
+  if (__builtin_object_size (c, 3) != sizeof (p->a) - 3)
+    abort ();
+  c = (char *) &p->b;
+  if (__builtin_object_size (c, 3) != sizeof (p->b))
+    abort ();
+  c = (char *) &p->c;
+  if (__builtin_object_size (c, 3) != s - __builtin_offsetof (struct A, c))
+    abort ();
+  free (p);
+}
+
+void
+__attribute__ ((noinline))
+test3 (void)
+{
+  char *c;
+  size_t s;
+  struct A *p = malloc (4);
+  if (__builtin_object_size (&p->a, 0) != 4)
+    abort ();
+  if (__builtin_object_size (&p->a[0], 0) != 4)
+    abort ();
+  if (__builtin_object_size (&p->a[3], 0) != 1)
+    abort ();
+  if (__builtin_object_size (&p->b, 0) != 0)
+    abort ();
+  if (__builtin_object_size (&p->c, 0) != 0)
+    abort ();
+  if (__builtin_object_size (&p->a, 1) != 4)
+    abort ();
+  if (__builtin_object_size (&p->a[0], 1) != 4)
+    abort ();
+  if (__builtin_object_size (&p->a[3], 1) != 1)
+    abort ();
+  if (__builtin_object_size (&p->b, 1) != 0)
+    abort ();
+  if (__builtin_object_size (&p->c, 1) != 0)
+    abort ();
+  free (p);
+  s = __builtin_offsetof (struct A, c) + 4;
+  p = malloc (s);
+  if (__builtin_object_size (&p->a, 0) != s)
+    abort ();
+  if (__builtin_object_size (&p->a[0], 0) != s)
+    abort ();
+  if (__builtin_object_size (&p->a[3], 0) != s - 3)
+    abort ();
+  if (__builtin_object_size (&p->b, 0) != s - __builtin_offsetof (struct A, b))
+    abort ();
+  if (__builtin_object_size (&p->c, 0) != 4)
+    abort ();
+  if (__builtin_object_size (&p->a, 1) != sizeof (p->a))
+    abort ();
+  if (__builtin_object_size (&p->a[0], 1) != sizeof (p->a))
+    abort ();
+  if (__builtin_object_size (&p->a[3], 1) != sizeof (p->a) - 3)
+    abort ();
+  if (__builtin_object_size (&p->b, 1) != sizeof (p->b))
+    abort ();
+  if (__builtin_object_size (&p->c, 1) != 4)
+    abort ();
+  free (p);
+}
+
+struct B
+{
+  struct A a[4];
+};
+
+void
+__attribute__ ((noinline))
+test4 (struct B *q, int i)
+{
+  if (__builtin_object_size (&q->a[2].a[2], 1) != sizeof (q->a[0].a) - 2)
+    abort ();
+  if (__builtin_object_size (&q->a[2].c[2], 1) != sizeof (q->a[0].c) - 2)
+    abort ();
+  if (__builtin_object_size (&q->a[3].a[2], 1) != sizeof (q->a[0].a) - 2)
+    abort ();
+  /* c is here the last field in the structure, it might be used similarly
+     as a flexible array member.  */
+  if (__builtin_object_size (&q->a[3].c[2], 1) != (size_t) -1)
+    abort ();
+  if (__builtin_object_size (&q->a[i].a[2], 1) != sizeof (q->a[0].a) - 2)
+    abort ();
+  /* c might be here the last field in the structure, it might be used
+     similarly as a flexible array member.  */
+  if (__builtin_object_size (&q->a[i].c[2], 1) != (size_t) -1)
+    abort ();
+}
+
+int
+main (void)
+{
+  struct A a, *p = &a;
+  struct B b, *q = &b;
+  int i = 1;
+  __asm ("" : "+r" (p));
+  test1 (p);
+  test2 ();
+  test3 ();
+  __asm ("" : "+r" (q), "+r" (i));
+  test4 (q, i);
+  exit (0);
+}

	Jakub


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