analyzer: fix zero-fill of calloc
authorDavid Malcolm <dmalcolm@redhat.com>
Thu, 3 Feb 2022 16:15:48 +0000 (11:15 -0500)
committerDavid Malcolm <dmalcolm@redhat.com>
Thu, 3 Feb 2022 22:45:47 +0000 (17:45 -0500)
It turned out that the analyzer wasn't treating calloc regions
as zero-filled, due to binding_cluster::fill_region getting an
unknown value for the byte_size_size_sval, and thus
get_or_create_repeated_svalue returning an unknown_svalue, which
was then used to fill the region.

Fixed thusly.

gcc/analyzer/ChangeLog:
* region-model-impl-calls.cc (region_model::impl_call_calloc): Use
a sized_region when calling zero_fill_region.

gcc/testsuite/ChangeLog:
* gcc.dg/analyzer/calloc-1.c: New test.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
gcc/analyzer/region-model-impl-calls.cc
gcc/testsuite/gcc.dg/analyzer/calloc-1.c [new file with mode: 0644]

index c20058e..779d943 100644 (file)
@@ -373,7 +373,9 @@ region_model::impl_call_calloc (const call_details &cd)
                                  nmemb_sval, size_sval);
   const region *new_reg
     = create_region_for_heap_alloc (prod_sval, cd.get_ctxt ());
-  zero_fill_region (new_reg);
+  const region *sized_reg
+    = m_mgr->get_sized_region (new_reg, NULL_TREE, prod_sval);
+  zero_fill_region (sized_reg);
   if (cd.get_lhs_type ())
     {
       const svalue *ptr_sval
diff --git a/gcc/testsuite/gcc.dg/analyzer/calloc-1.c b/gcc/testsuite/gcc.dg/analyzer/calloc-1.c
new file mode 100644 (file)
index 0000000..bc28128
--- /dev/null
@@ -0,0 +1,27 @@
+#include "analyzer-decls.h"
+
+typedef __SIZE_TYPE__ size_t;
+
+#define NULL ((void *)0)
+
+extern void *calloc (size_t __nmemb, size_t __size)
+  __attribute__ ((__nothrow__ , __leaf__))
+  __attribute__ ((__malloc__))
+  __attribute__ ((__alloc_size__ (1, 2))) ;
+
+char *test_1 (size_t sz)
+{
+  char *p;
+
+  p = calloc (1, 3);
+  if (!p)
+    return NULL;
+
+  __analyzer_dump_capacity (p); /* { dg-warning "capacity: '\\(\[^\n\r\]*\\)3'" } */
+
+  __analyzer_eval (p[0] == 0); /* { dg-warning "TRUE" } */
+  __analyzer_eval (p[1] == 0); /* { dg-warning "TRUE" } */
+  __analyzer_eval (p[2] == 0); /* { dg-warning "TRUE" } */
+
+  return p;
+}