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.

Successfully bootstrapped & regrtested on x86_64-pc-linux-gnu.
Pushed to trunk as r11-7987-g69b66ff02353a87585329bb3cf4ac20d6dee1b16.

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      |  8 +++++---
 gcc/testsuite/gcc.dg/analyzer/pr99886.c | 21 +++++++++++++++++++++
 2 files changed, 26 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/analyzer/pr99886.c

diff --git a/gcc/analyzer/diagnostic-manager.cc 
b/gcc/analyzer/diagnostic-manager.cc
index 9ec3e899e85..443ff058f65 100644
--- a/gcc/analyzer/diagnostic-manager.cc
+++ b/gcc/analyzer/diagnostic-manager.cc
@@ -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
index 00000000000..da768ba6298
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/analyzer/pr99886.c
@@ -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'" } */
+};
-- 
2.26.2

Reply via email to