analyzer: fix apparent hang with -fanalyzer-verbosity=0 [PR analyzer/99886]
authorDavid Malcolm <dmalcolm@redhat.com>
Mon, 5 Apr 2021 14:48:01 +0000 (10:48 -0400)
committerDavid Malcolm <dmalcolm@redhat.com>
Mon, 5 Apr 2021 14:48:01 +0000 (10:48 -0400)
The analyzer appeared to enter an infinite loop on malloc-1.c
when -fanalyzer-verbosity=0 was used.  In fact, it was slowly
counting from 0 to 0xffffffff.

Root cause is looping up to effectively ((unsigned)0) - 1 in
diagnostic_manager::consolidate_conditions when there are no events
in the path.

Fixed by the following, which uses signed integers when subtracting
from path->num_events () when simplifying checker_paths.

gcc/analyzer/ChangeLog:
PR analyzer/99886
* diagnostic-manager.cc
(diagnostic_manager::prune_interproc_events): Use signed integers
when subtracting one from path->num_events ().
(diagnostic_manager::consolidate_conditions): Likewise.  Convert
next_idx to a signed int.

gcc/testsuite/ChangeLog:
PR analyzer/99886
* gcc.dg/analyzer/pr99886.c: New test.

gcc/analyzer/diagnostic-manager.cc
gcc/testsuite/gcc.dg/analyzer/pr99886.c [new file with mode: 0644]

index 9ec3e89..443ff05 100644 (file)
@@ -2081,7 +2081,7 @@ diagnostic_manager::prune_interproc_events (checker_path *path) const
   do
     {
       changed = false;
-      int idx = path->num_events () - 1;
+      int idx = (signed)path->num_events () - 1;
       while (idx >= 0)
        {
          /* Prune [..., call, function-entry, return, ...] triples.  */
@@ -2200,7 +2200,9 @@ diagnostic_manager::consolidate_conditions (checker_path *path) const
   if (flag_analyzer_verbose_edges)
     return;
 
-  for (unsigned start_idx = 0; start_idx < path->num_events () - 1; start_idx++)
+  for (int start_idx = 0;
+       start_idx < (signed)path->num_events () - 1;
+       start_idx++)
     {
       if (path->cfg_edge_pair_at_p (start_idx))
        {
@@ -2231,7 +2233,7 @@ diagnostic_manager::consolidate_conditions (checker_path *path) const
               [start_idx, next_idx)
             where all apart from the final event are on the same line,
             and all are either TRUE or FALSE edges, matching the initial.  */
-         unsigned next_idx = start_idx + 2;
+         int next_idx = start_idx + 2;
          while (path->cfg_edge_pair_at_p (next_idx)
                 && same_line_as_p (start_exp_loc, path, next_idx))
            {
diff --git a/gcc/testsuite/gcc.dg/analyzer/pr99886.c b/gcc/testsuite/gcc.dg/analyzer/pr99886.c
new file mode 100644 (file)
index 0000000..da768ba
--- /dev/null
@@ -0,0 +1,21 @@
+/* Regression test for hang with -fanalyzer-verbosity=0.  */
+/* { dg-additional-options "-fanalyzer-verbosity=0" } */
+
+#include <stdlib.h>
+
+struct coord {
+  float x;
+  float y;
+};
+
+void test_34 (void)
+{
+  float *q;
+  struct coord *p = malloc (sizeof (struct coord));
+  if (!p)
+    return;
+  p->x = 0.0f;
+  q = &p->x;
+  free (p);
+  *q = 1.0f; /* { dg-warning "use after 'free' of 'q'" } */
+};