analyzer: fix false leak diagnostic on offsets from malloc [PR97608]
authorDavid Malcolm <dmalcolm@redhat.com>
Thu, 29 Oct 2020 00:10:39 +0000 (20:10 -0400)
committerDavid Malcolm <dmalcolm@redhat.com>
Thu, 29 Oct 2020 00:10:39 +0000 (20:10 -0400)
gcc/analyzer/ChangeLog:
PR analyzer/97608
* region-model-reachability.cc (reachable_regions::handle_sval):
Operands of reachable reversible operations are reachable.

gcc/testsuite/ChangeLog:
PR analyzer/97608
* gcc.dg/analyzer/malloc-1.c (test_42d): New.
* gcc.dg/analyzer/pr97608.c: New test.

gcc/analyzer/region-model-reachability.cc
gcc/testsuite/gcc.dg/analyzer/malloc-1.c
gcc/testsuite/gcc.dg/analyzer/pr97608.c [new file with mode: 0644]

index 52525e1144be6342d48870faf7a47783cca5010b..f6f25cc9177bbd1729b09d1a82aa361165a66896 100644 (file)
@@ -181,6 +181,40 @@ reachable_regions::handle_sval (const svalue *sval)
     }
   if (const svalue *cast = sval->maybe_undo_cast ())
     handle_sval (cast);
+
+  /* If SVAL is the result of a reversible operation, then the operands
+     are reachable.  */
+  switch (sval->get_kind ())
+    {
+    default:
+      break;
+    case SK_UNARYOP:
+      {
+       const unaryop_svalue *unaryop_sval = (const unaryop_svalue *)sval;
+       switch (unaryop_sval->get_op ())
+         {
+         default:
+           break;
+         case NEGATE_EXPR:
+           handle_sval (unaryop_sval->get_arg ());
+           break;
+         }
+      }
+      break;
+    case SK_BINOP:
+      {
+       const binop_svalue *binop_sval = (const binop_svalue *)sval;
+       switch (binop_sval->get_op ())
+         {
+         default:
+           break;
+         case POINTER_PLUS_EXPR:
+           handle_sval (binop_sval->get_arg0 ());
+           handle_sval (binop_sval->get_arg1 ());
+           break;
+         }
+      }
+    }
 }
 
 /* Add SVAL.  If it is a pointer, add the pointed-to region.
index c3e1330ec6a9ee708cdbf7d752b7e2376bab2b13..38ce1a52987bfb50bb172fc2c152bb079f4d306c 100644 (file)
@@ -509,6 +509,14 @@ void test_42c (void)
   free (q - 64); /* this is probably OK.  */
 } /* { dg-bogus "leak of 'p'" } */
 
+void *
+test_42d (void)
+{
+  void *p = malloc (1024);
+  void *q = p + 64;
+  return q;
+} /* { dg-bogus "leak of 'p'" } */
+
 #if 0
 void test_31 (void *p)
 {
diff --git a/gcc/testsuite/gcc.dg/analyzer/pr97608.c b/gcc/testsuite/gcc.dg/analyzer/pr97608.c
new file mode 100644 (file)
index 0000000..a2bc130
--- /dev/null
@@ -0,0 +1,17 @@
+#include <stdlib.h>
+
+void *f (void)
+{
+  void *p = malloc (8);
+  if (p == NULL)
+    abort ();
+  return (void *) ((char *) p + 0);
+}
+
+void *g (void)
+{
+  void *p = malloc (8);
+  if (p == NULL)
+    abort ();
+  return (void *) ((char *) p + 1);
+}