diff mbox series

[09/10] tree-object-size: Dynamic sizes for ADDR_EXPR

Message ID 20211109190137.1107736-10-siddhesh@gotplt.org
State New
Headers show
Series __builtin_dynamic_object_size | expand

Commit Message

Siddhesh Poyarekar Nov. 9, 2021, 7:01 p.m. UTC
Allow dynamic expressions from ADDR_EXPR for
__builtin_dynamic_object_size.  Offsets in objects still need to be
constant for now because offset computation need more validation to
support, e.g. negative offsets with dynamic sizes.

gcc/ChangeLog:

	* tree-object-size.c (size_known_p): New function.
	(addr_object_size): Build dynamic expressions for object
	sizes.
	(estimate_size): Limit PLUS_EXPR rewriting to static object
	sizes.
	(call_object_size): Call size_known_p.

gcc/testsuite/ChangeLog:

	* gcc.dg/builtin-dynamic-object-size-0.c: Add new tests.
	* gcc.dg/builtin-object-size-1.c (test1) [DYNAMIC_OBJECT_SIZE]:
	Adjust expected output for dynamic object sizes.
	* gcc.dg/builtin-object-size-2.c (test1) [DYNAMIC_OBJECT_SIZE]:
	Likewise.
	* gcc.dg/builtin-object-size-3.c (test1) [DYNAMIC_OBJECT_SIZE]:
	Likewise.
	* gcc.dg/builtin-object-size-4.c (test1) [DYNAMIC_OBJECT_SIZE]:
	Likewise.

Signed-off-by: Siddhesh Poyarekar <siddhesh@gotplt.org>
---
 .../gcc.dg/builtin-dynamic-object-size-0.c    | 71 ++++++++++++++
 gcc/testsuite/gcc.dg/builtin-object-size-1.c  | 30 +++++-
 gcc/testsuite/gcc.dg/builtin-object-size-2.c  | 43 +++++++--
 gcc/testsuite/gcc.dg/builtin-object-size-3.c  | 25 ++++-
 gcc/testsuite/gcc.dg/builtin-object-size-4.c  | 17 ++--
 gcc/tree-object-size.c                        | 93 +++++++++++--------
 6 files changed, 221 insertions(+), 58 deletions(-)
diff mbox series

Patch

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index 4ad49a51878..a1db63b2d45 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -219,6 +219,60 @@  test_deploop (size_t sz, size_t cond)
   return __builtin_dynamic_object_size (bin, 0);
 }
 
+/* Address expressions.  */
+
+struct dynarray_struct
+{
+  long a;
+  char c[16];
+  int b;
+};
+
+size_t
+__attribute__ ((noinline))
+test_dynarray_struct (size_t sz, size_t off)
+{
+  struct dynarray_struct bin[sz];
+
+  return __builtin_dynamic_object_size (&bin[off].c, 0);
+}
+
+size_t
+__attribute__ ((noinline))
+test_dynarray_struct_subobj (size_t sz, size_t off)
+{
+  struct dynarray_struct bin[sz];
+
+  return __builtin_dynamic_object_size (&bin[off].c[4], 1);
+}
+
+size_t
+__attribute__ ((noinline))
+test_dynarray_struct_subobj2 (size_t sz, size_t off, size_t *objsz)
+{
+  struct dynarray_struct2
+    {
+      long a;
+      int b;
+      char c[sz];
+    };
+
+  struct dynarray_struct2 bin;
+
+  *objsz = sizeof (bin);
+
+  return __builtin_dynamic_object_size (&bin.c[off], 1);
+}
+
+size_t
+__attribute__ ((noinline))
+test_substring (size_t sz, size_t off)
+{
+  char str[sz];
+
+  return __builtin_dynamic_object_size (&str[off], 0);
+}
+
 size_t
 __attribute__ ((access (__read_write__, 1, 2)))
 test_parmsz_simple (void *obj, size_t sz)
@@ -286,6 +340,23 @@  main (int argc, char **argv)
     FAIL ();
   if (test_dynarray (__builtin_strlen (argv[0])) != __builtin_strlen (argv[0]))
     FAIL ();
+  if (test_dynarray_struct (42, 4) !=
+      ((42 - 4) * sizeof (struct dynarray_struct)
+       - __builtin_offsetof (struct dynarray_struct, c)))
+    FAIL ();
+  if (test_dynarray_struct (42, 48) != 0)
+    FAIL ();
+  if (test_substring (128, 4) != 128 - 4)
+    FAIL ();
+  if (test_substring (128, 142) != 0)
+    FAIL ();
+  if (test_dynarray_struct_subobj (42, 4) != 16 - 4)
+    FAIL ();
+  if (test_dynarray_struct_subobj (42, 48) != 0)
+    FAIL ();
+  size_t objsz = 0;
+  if (test_dynarray_struct_subobj2 (42, 4, &objsz) != objsz - 4 - 12)
+    FAIL ();
   if (test_dynarray_cond (0) != 16)
     FAIL ();
   if (test_dynarray_cond (1) != 8)
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-1.c b/gcc/testsuite/gcc.dg/builtin-object-size-1.c
index 606141f9405..ba5a34c1f8e 100644
--- a/gcc/testsuite/gcc.dg/builtin-object-size-1.c
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-1.c
@@ -81,30 +81,56 @@  test1 (void *q, int x)
     r = malloc (30);
   else
     r = calloc (2, 16);
+#ifdef DYNAMIC_OBJECT_SIZE
+  if (__builtin_object_size (r, 0) != (x < 20 ? 30 : 2 * 16))
+    abort ();
+#else
   /* We may duplicate this test onto the two exit paths.  On one path
      the size will be 32, the other it will be 30.  If we don't duplicate
      this test, then the size will be 32.  */
   if (__builtin_object_size (r, 0) != 2 * 16
       && __builtin_object_size (r, 0) != 30)
     abort ();
+#endif
   if (x < 20)
     r = malloc (30);
   else
     r = calloc (2, 14);
+#ifdef DYNAMIC_OBJECT_SIZE
+  if (__builtin_object_size (r, 0) != (x < 20 ? 30 : 2 * 14))
+    abort ();
+#else
   if (__builtin_object_size (r, 0) != 30)
     abort ();
+#endif
   if (x < 30)
     r = malloc (sizeof (a));
   else
     r = &a.a[3];
+#ifdef DYNAMIC_OBJECT_SIZE
+  if (__builtin_object_size (r, 0) != (x < 30 ? sizeof (a) : sizeof (a) - 3))
+    abort ();
+#else
   if (__builtin_object_size (r, 0) != sizeof (a))
     abort ();
+#endif
   r = memcpy (r, "a", 2);
+#ifdef DYNAMIC_OBJECT_SIZE
+  if (__builtin_object_size (r, 0) != (x < 30 ? sizeof (a) : sizeof (a) - 3))
+    abort ();
+#else
   if (__builtin_object_size (r, 0) != sizeof (a))
     abort ();
+#endif
   r = memcpy (r + 2, "b", 2) + 2;
+#ifdef DYNAMIC_OBJECT_SIZE
+  if (__builtin_object_size (r, 0)
+      != (x < 30 ? sizeof (a) - 4 : sizeof (a) - 7))
+    abort ();
+#else
   if (__builtin_object_size (r, 0) != sizeof (a) - 4)
     abort ();
+#endif
   r = &a.a[4];
   r = memset (r, 'a', 2);
   if (__builtin_object_size (r, 0)
@@ -140,14 +166,16 @@  test1 (void *q, int x)
     abort ();
   if (__builtin_object_size (var + 10, 0) != x)
     abort ();
+  if (__builtin_object_size (&var[5], 0) != x + 5)
+    abort ();
 #else
   if (__builtin_object_size (var, 0) != (size_t) -1)
     abort ();
   if (__builtin_object_size (var + 10, 0) != (size_t) -1)
     abort ();
-#endif
   if (__builtin_object_size (&var[5], 0) != (size_t) -1)
     abort ();
+#endif
   if (__builtin_object_size (zerol, 0) != 0)
     abort ();
   if (__builtin_object_size (&zerol, 0) != 0)
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-2.c b/gcc/testsuite/gcc.dg/builtin-object-size-2.c
index 57fd17d5a45..4af30e8c580 100644
--- a/gcc/testsuite/gcc.dg/builtin-object-size-2.c
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-2.c
@@ -75,30 +75,56 @@  test1 (void *q, int x)
     r = malloc (30);
   else
     r = calloc (2, 16);
+#ifdef DYNAMIC_OBJECT_SIZE
+  if (__builtin_object_size (r, 1) != (x < 20 ? 30 : 2 * 16))
+    abort ();
+#else
   /* We may duplicate this test onto the two exit paths.  On one path
      the size will be 32, the other it will be 30.  If we don't duplicate
      this test, then the size will be 32.  */
   if (__builtin_object_size (r, 1) != 2 * 16
       && __builtin_object_size (r, 1) != 30)
     abort ();
+#endif
   if (x < 20)
     r = malloc (30);
   else
     r = calloc (2, 14);
+#ifdef DYNAMIC_OBJECT_SIZE
+  if (__builtin_object_size (r, 1) != (x < 20 ? 30 : 2 * 14))
+    abort ();
+#else
   if (__builtin_object_size (r, 1) != 30)
     abort ();
+#endif
   if (x < 30)
     r = malloc (sizeof (a));
   else
     r = &a.a[3];
+#ifdef DYNAMIC_OBJECT_SIZE
+  if (__builtin_object_size (r, 1) != (x < 30 ? sizeof (a) : sizeof (a) - 3))
+    abort ();
+#else
   if (__builtin_object_size (r, 1) != sizeof (a))
     abort ();
+#endif
   r = memcpy (r, "a", 2);
+#ifdef DYNAMIC_OBJECT_SIZE
+  if (__builtin_object_size (r, 1) != (x < 30 ? sizeof (a) : sizeof (a) - 3))
+    abort ();
+#else
   if (__builtin_object_size (r, 1) != sizeof (a))
     abort ();
+#endif
   r = memcpy (r + 2, "b", 2) + 2;
+#ifdef DYNAMIC_OBJECT_SIZE
+  if (__builtin_object_size (r, 0)
+      != (x < 30 ? sizeof (a) - 4 : sizeof (a) - 7))
+    abort ();
+#else
   if (__builtin_object_size (r, 1) != sizeof (a) - 4)
     abort ();
+#endif
   r = &a.a[4];
   r = memset (r, 'a', 2);
   if (__builtin_object_size (r, 1) != sizeof (a.a) - 4)
@@ -142,27 +168,28 @@  test1 (void *q, int x)
     abort ();
   if (__builtin_object_size (var + 10, 1) != x)
     abort ();
+  if (__builtin_object_size (&var[5], 1) != x + 5)
+    abort ();
+  if (__builtin_object_size (vara, 1) != (x + 10) * sizeof (struct A))
+    abort ();
+  if (__builtin_object_size (vara + 10, 1) != x * sizeof (struct A))
+    abort ();    
+  if (__builtin_object_size (&vara[5], 1) != (x + 5) * sizeof (struct A))
+    abort ();
 #else
   if (__builtin_object_size (var, 1) != (size_t) -1)
     abort ();
   if (__builtin_object_size (var + 10, 1) != (size_t) -1)
     abort ();
-#endif
   if (__builtin_object_size (&var[5], 1) != (size_t) -1)
     abort ();
-#ifdef DYNAMIC_OBJECT_SIZE
-  if (__builtin_object_size (vara, 1) != (x + 10) * sizeof (struct A))
-    abort ();
-  if (__builtin_object_size (vara + 10, 1) != x * sizeof (struct A))
-    abort ();    
-#else
   if (__builtin_object_size (vara, 1) != (size_t) -1)
     abort ();
   if (__builtin_object_size (vara + 10, 1) != (size_t) -1)
     abort ();    
-#endif
   if (__builtin_object_size (&vara[5], 1) != (size_t) -1)
     abort ();
+#endif
   if (__builtin_object_size (&vara[0].a, 1) != sizeof (vara[0].a))
     abort ();
   if (__builtin_object_size (&vara[10].a[0], 1) != sizeof (vara[0].a))
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-3.c b/gcc/testsuite/gcc.dg/builtin-object-size-3.c
index 5b323ca3527..ce4418e785b 100644
--- a/gcc/testsuite/gcc.dg/builtin-object-size-3.c
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-3.c
@@ -42,9 +42,17 @@  test1 (void *q, int x)
     abort ();
   if (__builtin_object_size (q, 2) != 0)
     abort ();
+#ifdef DYNAMIC_OBJECT_SIZE
+  if (__builtin_object_size (r, 2)
+      != (x < 0
+	  ? sizeof (a) - __builtin_offsetof (struct A, a) - 9
+	  : sizeof (a) - __builtin_offsetof (struct A, c) - 1))
+    abort ();
+#else
   if (__builtin_object_size (r, 2)
       != sizeof (a) - __builtin_offsetof (struct A, c) - 1)
     abort ();
+#endif
   if (x < 6)
     r = &w[2].a[1];
   else
@@ -58,15 +66,28 @@  test1 (void *q, int x)
   if (__builtin_object_size (&y.b, 2)
       != sizeof (a) - __builtin_offsetof (struct A, b))
     abort ();
+#ifdef DYNAMIC_OBJECT_SIZE
+  if (__builtin_object_size (r, 2)
+      != (x < 6
+	  ? 2 * sizeof (w[0]) - __builtin_offsetof (struct A, a) - 1
+	  : sizeof (a) - __builtin_offsetof (struct A, a) - 6))
+    abort ();
+#else
   if (__builtin_object_size (r, 2)
       != sizeof (a) - __builtin_offsetof (struct A, a) - 6)
     abort ();
+#endif
   if (x < 20)
     r = malloc (30);
   else
     r = calloc (2, 16);
+#ifdef DYNAMIC_OBJECT_SIZE
+  if (__builtin_object_size (r, 2) != (x < 20 ? 30 : 2 * 16))
+    abort ();
+#else
   if (__builtin_object_size (r, 2) != 30)
     abort ();
+#endif
   if (x < 20)
     r = malloc (30);
   else
@@ -145,14 +166,16 @@  test1 (void *q, int x)
     abort ();
   if (__builtin_object_size (var + 10, 2) != x)
     abort ();
+  if (__builtin_object_size (&var[5], 2) != x + 5)
+    abort ();
 #else
   if (__builtin_object_size (var, 2) != 0)
     abort ();
   if (__builtin_object_size (var + 10, 2) != 0)
     abort ();
-#endif
   if (__builtin_object_size (&var[5], 2) != 0)
     abort ();
+#endif
   if (__builtin_object_size (zerol, 2) != 0)
     abort ();
   if (__builtin_object_size (&zerol, 2) != 0)
diff --git a/gcc/testsuite/gcc.dg/builtin-object-size-4.c b/gcc/testsuite/gcc.dg/builtin-object-size-4.c
index 2d222301eff..81e0255dcc4 100644
--- a/gcc/testsuite/gcc.dg/builtin-object-size-4.c
+++ b/gcc/testsuite/gcc.dg/builtin-object-size-4.c
@@ -155,27 +155,28 @@  test1 (void *q, int x)
     abort ();
   if (__builtin_object_size (var + 10, 3) != x)
     abort ();
+  if (__builtin_object_size (&var[5], 3) != x + 5)
+    abort ();
+  if (__builtin_object_size (vara, 3) != (x + 10) * sizeof (struct A))
+    abort ();
+  if (__builtin_object_size (vara + 10, 3) != x * sizeof (struct A))
+    abort ();    
+  if (__builtin_object_size (&vara[5], 3) != (x + 5) * sizeof (struct A))
+    abort ();
 #else
   if (__builtin_object_size (var, 3) != 0)
     abort ();
   if (__builtin_object_size (var + 10, 3) != 0)
     abort ();
-#endif
   if (__builtin_object_size (&var[5], 3) != 0)
     abort ();
-#ifdef DYNAMIC_OBJECT_SIZE
-  if (__builtin_object_size (vara, 3) != (x + 10) * sizeof (struct A))
-    abort ();
-  if (__builtin_object_size (vara + 10, 3) != x * sizeof (struct A))
-    abort ();    
-#else
   if (__builtin_object_size (vara, 3) != 0)
     abort ();
   if (__builtin_object_size (vara + 10, 3) != 0)
     abort ();    
-#endif
   if (__builtin_object_size (&vara[5], 3) != 0)
     abort ();
+#endif
   if (__builtin_object_size (&vara[0].a, 3) != sizeof (vara[0].a))
     abort ();
   if (__builtin_object_size (&vara[10].a[0], 3) != sizeof (vara[0].a))
diff --git a/gcc/tree-object-size.c b/gcc/tree-object-size.c
index d5b0c8226f0..865fc3feea5 100644
--- a/gcc/tree-object-size.c
+++ b/gcc/tree-object-size.c
@@ -123,6 +123,16 @@  size_unknown_p (tree val, int object_size_type)
 	  && tree_to_uhwi (val) == unknown (object_size_type));
 }
 
+/* Return true if VAL is represents a known size for OBJECT_SIZE_TYPE.  */
+
+static inline bool
+size_known_p (tree val, int object_size_type)
+{
+  return (!size_unknown_p (val, object_size_type)
+	  && ((object_size_type & OST_DYNAMIC)
+	      || TREE_CODE (val) == INTEGER_CST));
+}
+
 /* Return a tree with initial value for OBJECT_SIZE_TYPE.  */
 
 static inline tree
@@ -391,16 +401,15 @@  addr_object_size (struct object_size_info *osi, const_tree ptr,
       if (!size_unknown_p (sz, object_size_type))
 	{
 	  tree offset = TREE_OPERAND (pt_var, 1);
-	  if (TREE_CODE (offset) != INTEGER_CST
-	      || TREE_CODE (sz) != INTEGER_CST)
+	  if (TREE_CODE (offset) != INTEGER_CST)
 	    sz = size_unknown (object_size_type);
 	  else
 	    sz = size_for_offset (sz, offset);
 	}
 
       if (!size_unknown_p (sz, object_size_type)
-	  && TREE_CODE (sz) == INTEGER_CST
-	  && compare_tree_int (sz, offset_limit) < 0)
+	  && (TREE_CODE (sz) != INTEGER_CST
+	      || compare_tree_int (sz, offset_limit) < 0))
 	pt_var_size = sz;
     }
   else if (DECL_P (pt_var))
@@ -416,8 +425,9 @@  addr_object_size (struct object_size_info *osi, const_tree ptr,
 
   if (pt_var_size)
     {
-      /* Validate the size determined above.  */
-      if (compare_tree_int (pt_var_size, offset_limit) >= 0)
+      /* Validate the size determined above if it is a constant.  */
+      if (TREE_CODE (pt_var_size) == INTEGER_CST
+	  && compare_tree_int (pt_var_size, offset_limit) >= 0)
 	return false;
     }
 
@@ -441,7 +451,7 @@  addr_object_size (struct object_size_info *osi, const_tree ptr,
 	    var = TREE_OPERAND (var, 0);
 	  if (! TYPE_SIZE_UNIT (TREE_TYPE (var))
 	      || ! tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (var)))
-	      || (pt_var_size
+	      || (pt_var_size && TREE_CODE (pt_var_size) == INTEGER_CST
 		  && tree_int_cst_lt (pt_var_size,
 				      TYPE_SIZE_UNIT (TREE_TYPE (var)))))
 	    var = pt_var;
@@ -455,17 +465,11 @@  addr_object_size (struct object_size_info *osi, const_tree ptr,
 		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)
+		    if (TYPE_SIZE_UNIT (TREE_TYPE (TREE_OPERAND (v, 0))))
 		      {
 			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)))
+			if (domain && TYPE_MAX_VALUE (domain))
 			  {
 			    v = NULL_TREE;
 			    break;
@@ -532,20 +536,20 @@  addr_object_size (struct object_size_info *osi, const_tree ptr,
 	var = pt_var;
 
       if (var != pt_var)
-	var_size = TYPE_SIZE_UNIT (TREE_TYPE (var));
+	{
+	  var_size = TYPE_SIZE_UNIT (TREE_TYPE (var));
+	  if (!TREE_CONSTANT (var_size))
+	    var_size = get_or_create_ssa_default_def (cfun, var_size);
+	  if (!var_size)
+	    return false;
+	}
       else if (!pt_var_size)
 	return false;
       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);
-	}
+	bytes = size_for_offset (var_size, bytes);
       if (var != pt_var
 	  && pt_var_size
 	  && TREE_CODE (pt_var) == MEM_REF
@@ -554,11 +558,7 @@  addr_object_size (struct object_size_info *osi, const_tree ptr,
 	  tree bytes2 = compute_object_offset (TREE_OPERAND (ptr, 0), pt_var);
 	  if (bytes2 != error_mark_node)
 	    {
-	      if (TREE_CODE (bytes2) == INTEGER_CST
-		  && tree_int_cst_lt (pt_var_size, bytes2))
-		bytes2 = size_zero_node;
-	      else
-		bytes2 = size_binop (MINUS_EXPR, pt_var_size, bytes2);
+	      bytes2 = size_for_offset (pt_var_size, bytes2);
 	      bytes = size_binop (MIN_EXPR, bytes, bytes2);
 	    }
 	}
@@ -568,8 +568,13 @@  addr_object_size (struct object_size_info *osi, const_tree ptr,
   else
     bytes = pt_var_size;
 
-  *psize = bytes;
-  return true;
+  if (size_known_p (bytes, object_size_type))
+    {
+      *psize = bytes;
+      return true;
+    }
+
+  return false;
 }
 
 
@@ -739,19 +744,27 @@  estimate_size (object_size_info *osi, tree size, bitmap *visitlog = NULL)
     case PLUS_EXPR:
 	{
 	  tree ret = estimate_size (osi, TREE_OPERAND (size, 0), visitlog);
+	  tree off = TREE_OPERAND (size, 1);
 
 	  if (size_unknown_p (ret, object_size_type))
 	    return size_unknown (object_size_type);
 
-	  tree off = TREE_OPERAND (size, 1);
-	  gcc_checking_assert (TREE_CODE (off) == INTEGER_CST);
-
-	  if (code == PLUS_EXPR)
-	    off = fold_build1 (NEGATE_EXPR, sizetype, off);
-
-	  if (tree_fits_uhwi_p (ret) && tree_int_cst_le (ret, off))
-	    return size_int (0);
-	  return size_binop (MINUS_EXPR, ret, off);
+	  /* We don't need this for dynamic object sizes because we don't make
+	     reducing estimates like in case of static sizes.  Instead, we
+	     return an expression that gives the precise size after a specific
+	     number of iterations, reducing to zero at runtime if the pointer
+	     being evaluated overflows.  */
+	  if (!(object_size_type & OST_DYNAMIC))
+	    {
+	      gcc_checking_assert (TREE_CODE (off) == INTEGER_CST);
+	      if (code == PLUS_EXPR)
+		{
+		  off = fold_build1 (NEGATE_EXPR, sizetype, off);
+		  ret = size_binop (MAX_EXPR, ret, off);
+		  code = MINUS_EXPR;
+		}
+	    }
+	  return size_binop (code, ret, off);
 	}
     case INTEGER_CST:
     default:
@@ -1163,7 +1176,7 @@  call_object_size (struct object_size_info *osi, gcall *call)
 
   tree bytes = alloc_object_size (call, object_size_type);
 
-  if ((object_size_type & OST_DYNAMIC) || TREE_CODE (bytes) == INTEGER_CST)
+  if (size_known_p (bytes, object_size_type))
     return bytes;
 
   return  size_unknown (object_size_type);