public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH] analyzer: Fix handling of non-ints inside allocation size checker [PR106181]
@ 2022-07-05 19:49 Tim Lange
  2022-07-05 21:37 ` Floating-point allocation sizes? (was Re: [PATCH] analyzer: Fix handling of non-ints inside allocation size checker [PR106181]) David Malcolm
  0 siblings, 1 reply; 4+ messages in thread
From: Tim Lange @ 2022-07-05 19:49 UTC (permalink / raw)
  To: gcc-patches, dmalcolm; +Cc: Tim Lange

This patch fixes the ICE reported in PR106181 by Arseny Solokha. With
this patch, the allocation size checker tries to handle floating-point
operands of allocation size arguments. Constant sizes get implicitly
converted and symbolic sizes are handled as long as the floating-point
operand could also be represented as a positive integer. In all other
cases and on unhandled constants, the checker falls back to not
emitting a warning.
Also, I unified the logic on zero byte allocations.

Regression-tested on x86_64 linux.

2022-07-05  Tim Lange  <mail@tim-lange.me>

gcc/analyzer/ChangeLog:

	PR analyzer/106181
	* region-model.cc (capacity_compatible_with_type):
	Can handle non-integer constants now.
	(region_model::check_region_size): Adapted to the new signature of
	capacity_compatible_with_type.

gcc/testsuite/ChangeLog:

	PR analyzer/106181
	* gcc.dg/analyzer/allocation-size-1.c: New tests.
	* gcc.dg/analyzer/allocation-size-2.c: New tests.
	* gcc.dg/analyzer/pr106181.c: New test.

---
 gcc/analyzer/region-model.cc                  | 44 ++++++++++++++++---
 .../gcc.dg/analyzer/allocation-size-1.c       | 29 +++++++++++-
 .../gcc.dg/analyzer/allocation-size-2.c       | 22 ++++++++++
 gcc/testsuite/gcc.dg/analyzer/pr106181.c      |  7 +++
 4 files changed, 95 insertions(+), 7 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/pr106181.c

diff --git a/gcc/analyzer/region-model.cc b/gcc/analyzer/region-model.cc
index 5d939327e01..e097ecb3c07 100644
--- a/gcc/analyzer/region-model.cc
+++ b/gcc/analyzer/region-model.cc
@@ -2904,13 +2904,45 @@ private:
 
 static bool
 capacity_compatible_with_type (tree cst, tree pointee_size_tree,
-			       bool is_struct)
+			       bool is_struct, bool floor_real)
 {
-  gcc_assert (TREE_CODE (cst) == INTEGER_CST);
   gcc_assert (TREE_CODE (pointee_size_tree) == INTEGER_CST);
-
   unsigned HOST_WIDE_INT pointee_size = TREE_INT_CST_LOW (pointee_size_tree);
-  unsigned HOST_WIDE_INT alloc_size = TREE_INT_CST_LOW (cst);
+
+  unsigned HOST_WIDE_INT alloc_size;
+  switch (TREE_CODE (cst))
+    {
+    default:
+      /* Assume all unhandled operands are compatible.  */
+      return true;
+    case INTEGER_CST:
+      alloc_size = TREE_INT_CST_LOW (cst);
+      break;
+    case REAL_CST:
+      {
+	const REAL_VALUE_TYPE *rv = TREE_REAL_CST_PTR (cst);
+	if (floor_real)
+	  {
+	    /* If the size is constant real at compile-time,
+	       we can model the conversion.  */
+	    alloc_size = real_to_integer (rv);
+	  }
+	else
+	  {
+	    /* On expressions where the value of one operator isn't
+	       representable as an integer or is negative, we give up and
+	       just assume that the programmer knows what they are doing.  */
+	    HOST_WIDE_INT i;
+	    if (real_isneg (rv) || !real_isinteger (rv, &i))
+	      return true;
+	    alloc_size = i;
+	  }
+      }
+      break;
+    }
+
+  if (alloc_size == 0)
+    return true;
 
   if (is_struct)
     return alloc_size >= pointee_size;
@@ -2920,7 +2952,7 @@ capacity_compatible_with_type (tree cst, tree pointee_size_tree,
 static bool
 capacity_compatible_with_type (tree cst, tree pointee_size_tree)
 {
-  return capacity_compatible_with_type (cst, pointee_size_tree, false);
+  return capacity_compatible_with_type (cst, pointee_size_tree, false, false);
 }
 
 /* Checks whether SVAL could be a multiple of SIZE_CST.
@@ -3145,7 +3177,7 @@ region_model::check_region_size (const region *lhs_reg, const svalue *rhs_sval,
 		= as_a <const constant_svalue *> (capacity);
 	tree cst_cap = cst_cap_sval->get_constant ();
 	if (!capacity_compatible_with_type (cst_cap, pointee_size_tree,
-					    is_struct))
+					    is_struct, true))
 	  ctxt->warn (new dubious_allocation_size (lhs_reg, rhs_reg,
 						   cst_cap));
       }
diff --git a/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c b/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c
index 4a78a81d054..1a1c8e75c98 100644
--- a/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c
+++ b/gcc/testsuite/gcc.dg/analyzer/allocation-size-1.c
@@ -114,4 +114,31 @@ void test_10 (int32_t n)
 {
   char *ptr = malloc (7 * n);
   free (ptr);
-}
\ No newline at end of file
+}
+
+void test_11 ()
+{
+  int32_t *ptr = malloc (3.0); /* { dg-line malloc11 } */
+  free (ptr);  
+  /* { dg-warning "allocated buffer size is not a multiple of the pointee's size \\\[CWE-131\\\]" "warning" { target *-*-* } malloc11 } */
+  /* { dg-message "'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc11 } */
+}
+
+void test_12 ()
+{
+  int32_t *ptr = malloc (4.0);
+  free (ptr);
+}
+
+void test_13 ()
+{
+  int32_t *ptr = malloc (4.7);
+  free (ptr);
+}
+
+void test_14 ()
+{
+  /* Test round towards zero.  */
+  int32_t *ptr = malloc (-0.9);
+  free (ptr);
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/allocation-size-2.c b/gcc/testsuite/gcc.dg/analyzer/allocation-size-2.c
index d541d5ef8db..babf9ae668d 100644
--- a/gcc/testsuite/gcc.dg/analyzer/allocation-size-2.c
+++ b/gcc/testsuite/gcc.dg/analyzer/allocation-size-2.c
@@ -154,3 +154,25 @@ void test_13 (void)
   else
     free (ptr);
 }
+
+void test_14 (int32_t n)
+{
+  int32_t *ptr = malloc (n * 3.0); /* { dg-line malloc14 } */
+  free (ptr);  
+  /* { dg-warning "allocated buffer size is not a multiple of the pointee's size \\\[CWE-131\\\]" "warning" { target *-*-* } malloc14 } */
+  /* { dg-message "'int32_t \\*' (\\\{aka '(long )?int \\*'\\\})? here; 'sizeof \\(int32_t (\\\{aka (long )?int\\\})?\\)' is '4'" "note" { target *-*-* } malloc14 } */
+}
+
+void test_15 (int32_t n)
+{
+  int32_t *ptr = malloc (n * 4.0);
+  free (ptr);
+}
+
+void test_16 (int32_t n)
+{
+  /* Should not emit a warning because we can not reason whether the result
+     of the floating-point arithmetic actually is a valid size or not.  */
+  int32_t *ptr = malloc (n * 3.1);
+  free (ptr);
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/pr106181.c b/gcc/testsuite/gcc.dg/analyzer/pr106181.c
new file mode 100644
index 00000000000..6df4e4538c0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/pr106181.c
@@ -0,0 +1,7 @@
+#include <stdint.h>
+
+int32_t *
+foo (int32_t x)
+{
+  return __builtin_calloc (x * 1.1, 1);
+}
-- 
2.36.1


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2022-07-05 23:12 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-07-05 19:49 [PATCH] analyzer: Fix handling of non-ints inside allocation size checker [PR106181] Tim Lange
2022-07-05 21:37 ` Floating-point allocation sizes? (was Re: [PATCH] analyzer: Fix handling of non-ints inside allocation size checker [PR106181]) David Malcolm
2022-07-05 21:57   ` Prathamesh Kulkarni
2022-07-05 23:12   ` Tim Lange

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).