]> gcc.gnu.org Git - gcc.git/commitdiff
analyzer: stop exploring the path after certain diagnostics [PR108830]
authorDavid Malcolm <dmalcolm@redhat.com>
Tue, 21 Feb 2023 21:58:36 +0000 (16:58 -0500)
committerDavid Malcolm <dmalcolm@redhat.com>
Tue, 21 Feb 2023 21:58:36 +0000 (16:58 -0500)
PR analyzer/108830 reports a situation in which there are lots of
followup -Wanalyzer-null-dereference warnings after the first access of
a NULL pointer, leading to very noisy output from -fanalyzer.

The analyzer's logic for stopping emitting multiple warnings from a
state machine doesn't quite work for NULL pointers: it attempts to
transition the malloc state machine's NULL pointer to the "stop" state,
which doesn't seem to make much sense in retrospect, and seems to get
confused over types.

Similarly, poisoned_value_diagnostic can be very noisy for uninit
variables, emitting a warning for every access to an uninitialized
variable.  In theory, region_model::check_for_poison makes some attempts
to suppress followups, but only for the symbolic value itself; if the
user's code keeps accessing the same region, we would get a warning on
each one.  For example, this showed up in Doom's s_sound.c where there
were 7 followup uninit warnings after the first uninit warning in
"S_ChangeMusic".

This patch adds an extra mechanism, giving pending diagnostics the
option of stopping the analysis of an execution path if they're saved
for emission on it, and turning this on for these warnings:
  -Wanalyzer-null-dereference
  -Wanalyzer-null-argument
  -Wanalyzer-use-after-free
  -Wanalyzer-use-of-pointer-in-stale-stack-frame
  -Wanalyzer-use-of-uninitialized-value

Doing so should hopefully reduce the cascades of diagnostics that
-fanalyzer can sometimes emit.

I added a -fno-analyzer-suppress-followups for the cases where you
really want the followup warnings (e.g. in some DejaGnu tests, and
for microbenchmarks of UB detection, such as PR analyzer/104224).

Integration testing shows this patch reduces the number of probable
false positives reported by 94, and finds one more true positive:

Comparison: 9.34% -> 10.91%
  GOOD:  66 ->  67  (+1)
   BAD: 641 -> 547 (-94)

where the affected warnings/projects are:

  -Wanalyzer-null-dereference: 0.00% GOOD: 0 BAD: 269 -> 239 (-30)
     Unclassified: 257 -> 228 (-29)
                  apr-1.7.0:  12 ->   5  (-7)
                       doom:   1 ->   0  (-1)
              haproxy-2.7.1:  47 ->  41  (-6)
       ImageMagick-7.1.0-57:  13 ->   9  (-4)
                 qemu-7.2.0: 165 -> 154 (-11)

      Known false: 7 -> 6 (-1)
                   xz-5.4.0:   4 ->   3  (-1)

  -Wanalyzer-use-of-uninitialized-value: 0.00% GOOD: 0 BAD: 143 -> 80 (-63)
      Known false: 47 -> 16 (-31)
                       doom: 42 -> 11 (-31)

     Unclassified: 96 -> 64 (-32)
              coreutils-9.1: 14 -> 10  (-4)
              haproxy-2.7.1: 29 -> 23  (-6)
                 qemu-7.2.0: 48 -> 26 (-22)

  -Wanalyzer-null-argument: 0.00% -> 2.33% GOOD: 0 -> 1 (+1) BAD: 43 -> 42 (-1)
     Unclassified: 39 -> 38 (-1)
      due to coreutils-9.1: 9 -> 8 (-1)

    True positive: 0 -> 1 (+1)
      (in haproxy-2.7.1)

gcc/analyzer/ChangeLog:
PR analyzer/108830
* analyzer.opt (fanalyzer-suppress-followups): New option.
* engine.cc (impl_region_model_context::warn): Terminate the path
if the diagnostic's terminate_path_p vfunc returns true and
-fanalyzer-suppress-followups is true (the default).
(impl_sm_context::warn): Likewise, for both overloads.
* pending-diagnostic.h (pending_diagnostic::terminate_path_p): New
vfunc.
* program-state.cc (program_state::on_edge): Terminate the path if
the ctxt requests it during updating the edge.
* region-model.cc (poisoned_value_diagnostic::terminate_path_p):
New vfunc.
* sm-malloc.cc (null_deref::terminate_path_p): New vfunc.
(null_arg::terminate_path_p): New vfunc.

gcc/ChangeLog:
PR analyzer/108830
* doc/invoke.texi: Document -fno-analyzer-suppress-followups.

gcc/testsuite/ChangeLog:
PR analyzer/108830
* gcc.dg/analyzer/attribute-nonnull.c: Update for
-Wanalyzer-use-of-uninitialized-value terminating analysis along
a path.
* gcc.dg/analyzer/call-summaries-2.c: Likewise.
* gcc.dg/analyzer/data-model-1.c: Likewise.
* gcc.dg/analyzer/data-model-5.c: Likewise.
* gcc.dg/analyzer/doom-s_sound-pr108867.c: New test.
* gcc.dg/analyzer/memset-CVE-2017-18549-1.c: Add
-fno-analyzer-suppress-followups.
* gcc.dg/analyzer/null-deref-pr108830.c: New test.
* gcc.dg/analyzer/pipe-1.c: Add -fno-analyzer-suppress-followups.
* gcc.dg/analyzer/pipe-void-return.c: Likewise.
* gcc.dg/analyzer/pipe2-1.c: Likewise.
* gcc.dg/analyzer/pr101547.c: Update for
-Wanalyzer-use-of-uninitialized-value terminating analysis along
a path.
* gcc.dg/analyzer/pr101875.c: Likewise.
* gcc.dg/analyzer/pr104224-split.c: New test, based on...
* gcc.dg/analyzer/pr104224.c: Add
-fno-analyzer-suppress-followups.
* gcc.dg/analyzer/realloc-2.c: Add
-fno-analyzer-suppress-followups.
* gcc.dg/analyzer/realloc-3.c: Likewise.
* gcc.dg/analyzer/realloc-5.c: Likewise.
* gcc.dg/analyzer/stdarg-1-ms_abi.c: Likewise.
* gcc.dg/analyzer/stdarg-1-sysv_abi.c: Likewise.
* gcc.dg/analyzer/stdarg-1.c: Likewise.
* gcc.dg/analyzer/symbolic-1.c: Likewise.
* gcc.dg/analyzer/symbolic-7.c: Update for
-Wanalyzer-use-of-uninitialized-value terminating analysis along a
path.
* gcc.dg/analyzer/uninit-4.c: Likewise.
* gcc.dg/analyzer/uninit-8.c: New test.
* gcc.dg/analyzer/uninit-pr94713.c: Update for
-Wanalyzer-use-of-uninitialized-value terminating analysis along a
path.
* gcc.dg/analyzer/zlib-6a.c: Add -fno-analyzer-suppress-followups.

Signed-off-by: David Malcolm <dmalcolm@redhat.com>
33 files changed:
gcc/analyzer/analyzer.opt
gcc/analyzer/engine.cc
gcc/analyzer/pending-diagnostic.h
gcc/analyzer/program-state.cc
gcc/analyzer/region-model.cc
gcc/analyzer/sm-malloc.cc
gcc/doc/invoke.texi
gcc/testsuite/gcc.dg/analyzer/attribute-nonnull.c
gcc/testsuite/gcc.dg/analyzer/call-summaries-2.c
gcc/testsuite/gcc.dg/analyzer/data-model-1.c
gcc/testsuite/gcc.dg/analyzer/data-model-5.c
gcc/testsuite/gcc.dg/analyzer/doom-s_sound-pr108867.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/memset-CVE-2017-18549-1.c
gcc/testsuite/gcc.dg/analyzer/null-deref-pr108830.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/pipe-1.c
gcc/testsuite/gcc.dg/analyzer/pipe-void-return.c
gcc/testsuite/gcc.dg/analyzer/pipe2-1.c
gcc/testsuite/gcc.dg/analyzer/pr101547.c
gcc/testsuite/gcc.dg/analyzer/pr101875.c
gcc/testsuite/gcc.dg/analyzer/pr104224-split.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/pr104224.c
gcc/testsuite/gcc.dg/analyzer/realloc-2.c
gcc/testsuite/gcc.dg/analyzer/realloc-3.c
gcc/testsuite/gcc.dg/analyzer/realloc-5.c
gcc/testsuite/gcc.dg/analyzer/stdarg-1-ms_abi.c
gcc/testsuite/gcc.dg/analyzer/stdarg-1-sysv_abi.c
gcc/testsuite/gcc.dg/analyzer/stdarg-1.c
gcc/testsuite/gcc.dg/analyzer/symbolic-1.c
gcc/testsuite/gcc.dg/analyzer/symbolic-7.c
gcc/testsuite/gcc.dg/analyzer/uninit-4.c
gcc/testsuite/gcc.dg/analyzer/uninit-8.c [new file with mode: 0644]
gcc/testsuite/gcc.dg/analyzer/uninit-pr94713.c
gcc/testsuite/gcc.dg/analyzer/zlib-6a.c

index b4dcdb8f45152b5227143d5a6d38ea4d0302213f..9d1a937e40398f2336ca3aa06bac04dcfb6327dc 100644 (file)
@@ -262,6 +262,10 @@ fanalyzer-state-merge
 Common Var(flag_analyzer_state_merge) Init(1)
 Merge similar-enough states during analysis.
 
+fanalyzer-suppress-followups
+Common Var(flag_analyzer_suppress_followups) Init(1)
+Stop exploring an execution path after certain diagnostics.
+
 fanalyzer-transitivity
 Common Var(flag_analyzer_transitivity) Init(0)
 Enable transitivity of constraints during analysis.
index 24ded2670197901c5d64efce85dd07ff7fa9a2f3..a5965c2b8ff048e47d9c1687d5298a11020a5bee 100644 (file)
@@ -125,11 +125,20 @@ impl_region_model_context::warn (std::unique_ptr<pending_diagnostic> d)
       return false;
     }
   if (m_eg)
-    return m_eg->get_diagnostic_manager ().add_diagnostic
-      (m_enode_for_diag, m_enode_for_diag->get_supernode (),
-       m_stmt, m_stmt_finder, std::move (d));
-  else
-    return false;
+    {
+      bool terminate_path = d->terminate_path_p ();
+      if (m_eg->get_diagnostic_manager ().add_diagnostic
+         (m_enode_for_diag, m_enode_for_diag->get_supernode (),
+          m_stmt, m_stmt_finder, std::move (d)))
+       {
+         if (m_path_ctxt
+             && terminate_path
+             && flag_analyzer_suppress_followups)
+           m_path_ctxt->terminate_path ();
+         return true;
+       }
+    }
+  return false;
 }
 
 void
@@ -378,9 +387,14 @@ public:
       = (var
         ? m_old_smap->get_state (var_old_sval, m_eg.get_ext_state ())
         : m_old_smap->get_global_state ());
+    bool terminate_path = d->terminate_path_p ();
     m_eg.get_diagnostic_manager ().add_diagnostic
       (&m_sm, m_enode_for_diag, snode, stmt, m_stmt_finder,
        var, var_old_sval, current, std::move (d));
+    if (m_path_ctxt
+       && terminate_path
+       && flag_analyzer_suppress_followups)
+      m_path_ctxt->terminate_path ();
   }
 
   void warn (const supernode *snode, const gimple *stmt,
@@ -393,9 +407,14 @@ public:
       = (sval
         ? m_old_smap->get_state (sval, m_eg.get_ext_state ())
         : m_old_smap->get_global_state ());
+    bool terminate_path = d->terminate_path_p ();
     m_eg.get_diagnostic_manager ().add_diagnostic
       (&m_sm, m_enode_for_diag, snode, stmt, m_stmt_finder,
        NULL_TREE, sval, current, std::move (d));
+    if (m_path_ctxt
+       && terminate_path
+       && flag_analyzer_suppress_followups)
+      m_path_ctxt->terminate_path ();
   }
 
   /* Hook for picking more readable trees for SSA names of temporaries,
index d9e9e7f89052b15fa148fc4e0409c1198dd98273..6423c8be4ea61694d423080617d0cb8f6d310f30 100644 (file)
@@ -173,6 +173,10 @@ class pending_diagnostic
      having to generate feasible execution paths for them).  */
   virtual int get_controlling_option () const = 0;
 
+  /* Vfunc to give the diagnostic the chance to terminate the execution
+     path being explored.  By default, don't terminate the path.  */
+  virtual bool terminate_path_p () const { return false; }
+
   /* Vfunc for emitting the diagnostic.  The rich_location will have been
      populated with a diagnostic_path.
      Return true if a diagnostic is actually emitted.  */
index 9a1a8cd8e5284d3f04593c6dcdbb842c4a46b5b6..8dade4b5b3e01ee2a45e7943172a3d7674da4422 100644 (file)
@@ -1105,6 +1105,27 @@ program_state::on_edge (exploded_graph &eg,
                        const superedge *succ,
                        uncertainty_t *uncertainty)
 {
+  class my_path_context : public path_context
+  {
+  public:
+    my_path_context (bool &terminated) : m_terminated (terminated) {}
+    void bifurcate (std::unique_ptr<custom_edge_info>) final override
+    {
+      gcc_unreachable ();
+    }
+
+    void terminate_path () final override
+    {
+      m_terminated = true;
+    }
+
+    bool terminate_path_p () const final override
+    {
+      return m_terminated;
+    }
+    bool &m_terminated;
+  };
+
   /* Update state.  */
   const program_point &point = enode->get_point ();
   const gimple *last_stmt = point.get_supernode ()->get_last_stmt ();
@@ -1117,11 +1138,12 @@ program_state::on_edge (exploded_graph &eg,
      Adding the relevant conditions for the edge could also trigger
      sm-state transitions (e.g. transitions due to ptrs becoming known
      to be NULL or non-NULL) */
-
+  bool terminated = false;
+  my_path_context path_ctxt (terminated);
   impl_region_model_context ctxt (eg, enode,
                                  &enode->get_state (),
                                  this,
-                                 uncertainty, NULL,
+                                 uncertainty, &path_ctxt,
                                  last_stmt);
   if (!m_region_model->maybe_update_for_edge (*succ,
                                              last_stmt,
@@ -1134,6 +1156,8 @@ program_state::on_edge (exploded_graph &eg,
                     succ->m_dest->m_index);
       return false;
     }
+  if (terminated)
+    return false;
 
   program_state::detect_leaks (enode->get_state (), *this,
                               NULL, eg.get_ext_state (),
index e3de74bbf45baf39469ee53be32facaf74b13b55..f844b519f6131e28fea2ea21bf2f8409bf40f9e5 100644 (file)
@@ -505,6 +505,8 @@ public:
       }
   }
 
+  bool terminate_path_p () const final override { return true; }
+
   bool emit (rich_location *rich_loc) final override
   {
     switch (m_pkind)
index c24fe7374812d11e3e691b752c7a6da5079d8c00..1ea9b30fa13d5594c627599b9b2e53e3b863fb21 100644 (file)
@@ -1150,6 +1150,8 @@ public:
     return OPT_Wanalyzer_null_dereference;
   }
 
+  bool terminate_path_p () const final override { return true; }
+
   bool emit (rich_location *rich_loc) final override
   {
     /* CWE-476: NULL Pointer Dereference.  */
@@ -1203,6 +1205,8 @@ public:
     return OPT_Wanalyzer_null_argument;
   }
 
+  bool terminate_path_p () const final override { return true; }
+
   bool emit (rich_location *rich_loc) final override
   {
     /* CWE-476: NULL Pointer Dereference.  */
index 078d29d5313871a9e06b9a3ed71d29afe90f651f..bcf8510945b105fb84f62e360b0d490e7b6f8b13 100644 (file)
@@ -428,6 +428,7 @@ Objective-C and Objective-C++ Dialects}.
 -fanalyzer-fine-grained @gol
 -fno-analyzer-state-merge @gol
 -fno-analyzer-state-purge @gol
+-fno-analyzer-suppress-followups @gol
 -fanalyzer-transitivity @gol
 -fno-analyzer-undo-inlining @gol
 -fanalyzer-verbose-edges @gol
@@ -11012,6 +11013,30 @@ and which aren't relevant to leak analysis.
 With @option{-fno-analyzer-state-purge} this purging of state can
 be suppressed, for debugging state-handling issues.
 
+@item -fno-analyzer-suppress-followups
+@opindex fanalyzer-suppress-followups
+@opindex fno-analyzer-suppress-followups
+This option is intended for analyzer developers.
+
+By default the analyzer will stop exploring an execution path after
+encountering certain diagnostics, in order to avoid potentially issuing a
+cascade of follow-up diagnostics.
+
+The diagnostics that terminate analysis along a path are:
+
+@itemize
+@item @option{-Wanalyzer-null-argument}
+@item @option{-Wanalyzer-null-dereference}
+@item @option{-Wanalyzer-use-after-free}
+@item @option{-Wanalyzer-use-of-pointer-in-stale-stack-frame}
+@item @option{-Wanalyzer-use-of-uninitialized-value}
+@end itemize
+
+With @option{-fno-analyzer-suppress-followups} the analyzer will
+continue to explore such paths even after such diagnostics, which may
+be helpful for debugging issues in the analyzer, or for microbenchmarks
+for detecting undefined behavior.
+
 @item -fanalyzer-transitivity
 @opindex fanalyzer-transitivity
 @opindex fno-analyzer-transitivity
index 7c71a71c9305a0d44dcf2bfccbd9e9dd65f206cc..5700256c06a4629f73f05de75aa58fe127da8dcd 100644 (file)
@@ -16,8 +16,6 @@ void test_1 (void *p, void *q, void *r)
   foo(p, q, r);
   foo(NULL, q, r); /* { dg-warning "use of NULL where non-null expected" "warning" } */
   /* { dg-message "argument 1 NULL where non-null expected" "note" { target *-*-* } .-1 } */
-  foo(p, NULL, r);
-  foo(p, q, NULL); /* { dg-warning "use of NULL where non-null expected" } */
 }
 
 void test_1a (void *q, void *r)
@@ -27,12 +25,29 @@ void test_1a (void *q, void *r)
   /* { dg-message "argument 1 \\('p'\\) NULL where non-null expected" "note" { target *-*-* } .-1 } */
 }
 
-void test_2 (void *p, void *q, void *r)
+void test_1b (void *p, void *r)
+{
+  foo(p, NULL, r);
+}
+
+void test_1c (void *p, void *q, void *r)
+{
+  foo(p, q, NULL); /* { dg-warning "use of NULL where non-null expected" } */
+}
+
+void test_2a (void *p, void *q, void *r)
 {
   bar(p, q, r);
-  bar(NULL, q, r); /* { dg-warning "use of NULL where non-null expected" "warning" } */
+}
+
+void test_2b (void *p, void *q, void *r)
+{
   bar(p, NULL, r); /* { dg-warning "use of NULL where non-null expected" "warning" } */
   /* { dg-message "argument 2 NULL where non-null expected" "note" { target *-*-* } .-1 } */
+}
+
+void test_2c (void *p, void *q, void *r)
+{
   bar(p, q, NULL); /* { dg-warning "use of NULL where non-null expected" "warning" } */
 }
 
index 2d82d02e4e22b3c085f153ca89a4ad727ba5a2b2..1bac24f4c67ee9a4e2facf14de4877daeef81fbb 100644 (file)
@@ -607,17 +607,22 @@ void partially_inits (int *p, int v)
   p[1] = v;
 }
 
-void test_partially_inits (int x)
+void test_partially_inits_0 (int x)
 {
   int arr[2];
   partially_inits (arr, x);
   partially_inits (arr, x);
 
-  __analyzer_eval (arr[0]); /* { dg-warning "UNKNOWN" "eval" } */
-  /* { dg-warning "use of uninitialized value 'arr\\\[0\\\]'" "uninit" { target *-*-* } .-1 } */
+  __analyzer_eval (arr[0]); /* { dg-warning "use of uninitialized value 'arr\\\[0\\\]'" } */
+}
+
+void test_partially_inits_1 (int x)
+{
+  int arr[2];
+  partially_inits (arr, x);
+  partially_inits (arr, x);
 
-  __analyzer_eval (arr[1] == x); /* { dg-warning "UNKNOWN" "eval" } */ 
-  /* { dg-bogus "use of uninitialized value 'arr\\\[1\\\]'" "uninit" { xfail *-*-* } .-1 } */
+  __analyzer_eval (arr[1] == x); /* { dg-bogus "use of uninitialized value 'arr\\\[1\\\]'" "uninit" { xfail *-*-* } } */
   // TODO(xfail), and eval should be "TRUE"
 }
 
index d8930d189bbda878f39a448c74157f6d004bdf93..86d1ccf11a7c9be784f83e8631f41f6b02112cc9 100644 (file)
@@ -351,9 +351,8 @@ void test_19 (void)
 {
   int i, j; /* { dg-message "region created on stack here" } */
   /* Compare two uninitialized locals.  */
-    __analyzer_eval (i == j); /* { dg-warning "UNKNOWN" "unknown " } */
-    /* { dg-warning "use of uninitialized value 'i'" "uninit i" { target *-*-* } .-1 } */
-    /* { dg-warning "use of uninitialized value 'j'" "uninit j" { target *-*-* } .-2 } */
+    __analyzer_eval (i == j); /* { dg-warning "use of uninitialized value 'i'" "uninit i" } */
+    /* { dg-warning "use of uninitialized value 'j'" "uninit j" { target *-*-* } .-1 } */
 }
 
 void test_20 (int i, int j)
@@ -653,11 +652,6 @@ void test_29b (void)
   __analyzer_eval (p[9].x == 109024); /* { dg-warning "TRUE" } */
   __analyzer_eval (p[9].y == 109025); /* { dg-warning "TRUE" } */
 
-  __analyzer_eval (p[10].x == 0); /* { dg-warning "UNKNOWN" "unknown" } */
-  /* { dg-warning "use of uninitialized value 'p\\\[10\\\].x'" "uninit" { target *-*-* } .-1 } */
-  __analyzer_eval (p[10].y == 0); /* { dg-warning "UNKNOWN" "unknown" } */
-  /* { dg-warning "use of uninitialized value 'p\\\[10\\\].y'" "uninit" { target *-*-* } .-1 } */
-
   q = &p[7];
 
   __analyzer_eval (q->x == 107024); /* { dg-warning "TRUE" } */
@@ -679,6 +673,8 @@ void test_29b (void)
 
   __analyzer_eval (q->x == 107024); /* { dg-warning "TRUE" } */
   __analyzer_eval (q->y == 107025); /* { dg-warning "TRUE" } */
+
+  __analyzer_eval (p[10].x == 0); /* { dg-warning "use of uninitialized value 'p\\\[10\\\].x'" } */
 }
 
 void test_29c (int len)
@@ -704,11 +700,6 @@ void test_29c (int len)
   __analyzer_eval (p[9].x == 109024); /* { dg-warning "TRUE" } */
   __analyzer_eval (p[9].y == 109025); /* { dg-warning "TRUE" } */
 
-  __analyzer_eval (p[10].x == 0); /* { dg-warning "UNKNOWN" "unknown" } */
-  /* { dg-warning "use of uninitialized value '\\*p\\\[10\\\].x'" "uninit" { target *-*-* } .-1 } */
-  __analyzer_eval (p[10].y == 0); /* { dg-warning "UNKNOWN" "unknown" } */
-  /* { dg-warning "use of uninitialized value '\\*p\\\[10\\\].y'" "uninit" { target *-*-* } .-1 } */
-
   q = &p[7];
 
   __analyzer_eval (q->x == 107024); /* { dg-warning "TRUE" } */
@@ -730,6 +721,8 @@ void test_29c (int len)
 
   __analyzer_eval (q->x == 107024); /* { dg-warning "TRUE" } */
   __analyzer_eval (q->y == 107025); /* { dg-warning "TRUE" } */
+
+  __analyzer_eval (p[10].x == 0); /* { dg-warning "use of uninitialized value '\\*p\\\[10\\\].x'" } */
 }
 
 void test_30 (void *ptr)
index 2135c70eb8dd3340eb6839e1e5dbac3f9b298528..b71bad757a19321c2621b44ffce68e87f80e74ae 100644 (file)
@@ -90,10 +90,6 @@ void unref (base_obj *obj)
 {
   if (--obj->ob_refcnt == 0) /* { dg-bogus "dereference of uninitialized pointer 'obj'" } */
     obj->ob_type->tp_dealloc (obj);
-  /* { dg-warning "dereference of NULL 'obj'" "deref of NULL" { target *-*-* } .-2 } */
-  /* FIXME: ideally we wouldn't issue this, as we've already issued a
-     warning about str_obj which is now in the "stop" state; the cast
-     confuses things.  */
 }
 
 void test_1 (const char *str)
diff --git a/gcc/testsuite/gcc.dg/analyzer/doom-s_sound-pr108867.c b/gcc/testsuite/gcc.dg/analyzer/doom-s_sound-pr108867.c
new file mode 100644 (file)
index 0000000..ebbfed2
--- /dev/null
@@ -0,0 +1,653 @@
+/* Reduced from Doom's linuxdoom-1.10/s_sound.c, which is GPLv2 or later.  */
+
+/* { dg-additional-options "-fno-analyzer-call-summaries -Wno-analyzer-too-complex" } */
+
+typedef struct _IO_FILE FILE;
+extern FILE* stderr;
+extern int
+fprintf(FILE* __restrict __stream, const char* __restrict __format, ...);
+extern int
+sprintf(char* __restrict __s, const char* __restrict __format, ...)
+  __attribute__((__nothrow__));
+extern int
+abs(int __x) __attribute__((__nothrow__, __leaf__)) __attribute__((__const__));
+
+typedef enum
+{
+  false,
+  true
+} boolean;
+
+typedef unsigned char byte;
+
+void
+I_Error(char* error, ...);
+
+typedef enum
+{
+  shareware,
+  registered,
+  commercial,
+  /* [...snip...] */
+} GameMode_t;
+
+typedef int fixed_t;
+
+fixed_t
+FixedMul(fixed_t a, fixed_t b);
+
+extern fixed_t finesine[5 * 8192 / 4];
+typedef unsigned angle_t;
+
+typedef struct mobj_s
+{
+  /* [...snip...] */
+  fixed_t x;
+  fixed_t y;
+  fixed_t z;
+  /* [...snip...] */
+  angle_t angle;
+  /* [...snip...] */
+} mobj_t;
+
+typedef struct player_s
+{
+  mobj_t* mo;
+  /* [...snip...] */
+} player_t;
+
+extern GameMode_t gamemode;
+extern int gameepisode;
+extern int gamemap;
+extern int consoleplayer;
+extern player_t players[4];
+
+typedef struct sfxinfo_struct sfxinfo_t;
+
+struct sfxinfo_struct
+{
+  /* [...snip...] */
+  int priority;
+  sfxinfo_t* link;
+  int pitch;
+  int volume;
+  void* data;
+  int usefulness;
+  int lumpnum;
+};
+
+typedef struct
+{
+  char* name;
+  int lumpnum;
+  void* data;
+  int handle;
+} musicinfo_t;
+
+extern sfxinfo_t S_sfx[];
+
+extern musicinfo_t S_music[];
+
+typedef enum
+{
+  mus_None,
+  mus_e1m1,
+  /* [...snip...] */
+  mus_e1m5,
+  /* [...snip...] */
+  mus_e1m9,
+  /* [...snip...] */
+  mus_e2m4,
+  mus_e2m5,
+  mus_e2m6,
+  mus_e2m7,
+  /* [...snip...] */
+  mus_e3m2,
+  mus_e3m3,
+  mus_e3m4,
+  /* [...snip...] */
+  mus_runnin,
+  /* [...snip...] */
+  NUMMUSIC
+} musicenum_t;
+
+typedef enum
+{
+  /* [...snip...] */
+  sfx_sawup,
+  /* [...snip...] */
+  sfx_sawhit,
+  /* [...snip...] */
+  sfx_itemup,
+  /* [...snip...] */
+  sfx_tink,
+  /* [...snip...] */
+  NUMSFX
+} sfxenum_t;
+
+
+void
+I_SetChannels();
+
+int
+I_GetSfxLumpNum(sfxinfo_t* sfxinfo);
+
+int
+I_StartSound(int id, int vol, int sep, int pitch, int priority);
+
+void
+I_StopSound(int handle);
+int
+I_SoundIsPlaying(int handle);
+void
+I_UpdateSoundParams(int handle, int vol, int sep, int pitch);
+
+void
+I_SetMusicVolume(int volume);
+
+void
+I_PauseSong(int handle);
+void
+I_ResumeSong(int handle);
+int
+I_RegisterSong(void* data);
+
+void
+I_PlaySong(int handle, int looping);
+
+void
+I_StopSong(int handle);
+
+void
+I_UnRegisterSong(int handle);
+void
+S_StopSound(void* origin);
+void
+S_ChangeMusic(int music_id, int looping);
+void
+S_StopMusic(void);
+
+void
+S_SetMusicVolume(int volume);
+void
+S_SetSfxVolume(int volume);
+
+void*
+Z_Malloc(int size, int tag, void* ptr);
+void
+Z_ChangeTag2(void* ptr, int tag);
+
+typedef struct memblock_s
+{
+  /* [...snip...] */
+  int id;
+  /* [...snip...] */
+} memblock_t;
+int
+M_Random(void);
+int
+W_GetNumForName(char* name);
+void*
+W_CacheLumpNum(int lump, int tag);
+angle_t
+R_PointToAngle2(fixed_t x1, fixed_t y1, fixed_t x2, fixed_t y2);
+
+typedef struct
+{
+  sfxinfo_t* sfxinfo;
+  void* origin;
+  int handle;
+} channel_t;
+static channel_t* channels;
+
+int snd_SfxVolume = 15;
+int snd_MusicVolume = 15;
+static boolean mus_paused;
+static musicinfo_t* mus_playing = 0;
+int numChannels;
+static int nextcleanup;
+
+int
+S_getChannel(void* origin, sfxinfo_t* sfxinfo);
+
+int
+S_AdjustSoundParams(mobj_t* listener,
+                    mobj_t* source,
+                    int* vol,
+                    int* sep,
+                    int* pitch);
+void
+S_StopChannel(int cnum);
+
+void
+S_Init(int sfxVolume, int musicVolume)
+{
+  int i;
+
+  fprintf(stderr, "S_Init: default sfx volume %d\n", sfxVolume);
+
+  I_SetChannels();
+
+  S_SetSfxVolume(sfxVolume);
+
+  S_SetMusicVolume(musicVolume);
+
+  channels = (channel_t*)Z_Malloc(numChannels * sizeof(channel_t), 1, 0);
+
+  for (i = 0; i < numChannels; i++)
+    channels[i].sfxinfo = 0;
+
+  mus_paused = 0;
+
+  for (i = 1; i < NUMSFX; i++)
+    S_sfx[i].lumpnum = S_sfx[i].usefulness = -1;
+}
+void
+S_Start(void)
+{
+  int cnum;
+  int mnum;
+
+  for (cnum = 0; cnum < numChannels; cnum++)
+    if (channels[cnum].sfxinfo)
+      S_StopChannel(cnum);
+
+  mus_paused = 0;
+
+  if (gamemode == commercial)
+    mnum = mus_runnin + gamemap - 1;
+  else {
+    int spmus[] = {
+
+      mus_e3m4, mus_e3m2, mus_e3m3, mus_e1m5, mus_e2m7,
+      mus_e2m4, mus_e2m6, mus_e2m5, mus_e1m9
+    };
+
+    if (gameepisode < 4)
+      mnum = mus_e1m1 + (gameepisode - 1) * 9 + gamemap - 1;
+    else
+      mnum = spmus[gamemap - 1];
+  }
+
+  S_ChangeMusic(mnum, true);
+
+  nextcleanup = 15;
+}
+
+void
+S_StartSoundAtVolume(void* origin_p, int sfx_id, int volume)
+{
+
+  int rc;
+  int sep;
+  int pitch;
+  int priority;
+  sfxinfo_t* sfx;
+  int cnum;
+
+  mobj_t* origin = (mobj_t*)origin_p;
+  if (sfx_id < 1 || sfx_id > NUMSFX)
+    I_Error("Bad sfx #: %d", sfx_id);
+
+  sfx = &S_sfx[sfx_id];
+
+  if (sfx->link) {
+    pitch = sfx->pitch;
+    priority = sfx->priority;
+    volume += sfx->volume;
+
+    if (volume < 1)
+      return;
+
+    if (volume > snd_SfxVolume)
+      volume = snd_SfxVolume;
+  } else {
+    pitch = 128;
+    priority = 64;
+  }
+
+  if (origin && origin != players[consoleplayer].mo) {
+    rc = S_AdjustSoundParams(
+      players[consoleplayer].mo, origin, &volume, &sep, &pitch);
+
+    if (origin->x == players[consoleplayer].mo->x &&
+        origin->y == players[consoleplayer].mo->y) {
+      sep = 128;
+    }
+
+    if (!rc)
+      return;
+  } else {
+    sep = 128;
+  }
+
+  if (sfx_id >= sfx_sawup && sfx_id <= sfx_sawhit) {
+    pitch += 8 - (M_Random() & 15);
+
+    if (pitch < 0)
+      pitch = 0;
+    else if (pitch > 255)
+      pitch = 255;
+  } else if (sfx_id != sfx_itemup && sfx_id != sfx_tink) {
+    pitch += 16 - (M_Random() & 31);
+
+    if (pitch < 0)
+      pitch = 0;
+    else if (pitch > 255)
+      pitch = 255;
+  }
+
+  S_StopSound(origin);
+
+  cnum = S_getChannel(origin, sfx);
+
+  if (cnum < 0)
+    return;
+  if (sfx->lumpnum < 0)
+    sfx->lumpnum = I_GetSfxLumpNum(sfx);
+
+  if (!sfx->data) {
+    fprintf(stderr, "S_StartSoundAtVolume: 16bit and not pre-cached - wtf?\n");
+  }
+
+  if (sfx->usefulness++ < 0)
+    sfx->usefulness = 1;
+
+  channels[cnum].handle = I_StartSound(sfx_id,
+
+                                       volume,
+                                       sep,
+                                       pitch,
+                                       priority);
+}
+
+void
+S_StartSound(void* origin, int sfx_id)
+{
+
+  S_StartSoundAtVolume(origin, sfx_id, snd_SfxVolume);
+}
+
+void
+S_StopSound(void* origin)
+{
+
+  int cnum;
+
+  for (cnum = 0; cnum < numChannels; cnum++) {
+    if (channels[cnum].sfxinfo && channels[cnum].origin == origin) {
+      S_StopChannel(cnum);
+      break;
+    }
+  }
+}
+void
+S_PauseSound(void)
+{
+  if (mus_playing && !mus_paused) {
+    I_PauseSong(mus_playing->handle);
+    mus_paused = true;
+  }
+}
+
+void
+S_ResumeSound(void)
+{
+  if (mus_playing && mus_paused) {
+    I_ResumeSong(mus_playing->handle);
+    mus_paused = false;
+  }
+}
+
+void
+S_UpdateSounds(void* listener_p)
+{
+  int audible;
+  int cnum;
+  int volume;
+  int sep;
+  int pitch;
+  sfxinfo_t* sfx;
+  channel_t* c;
+
+  mobj_t* listener = (mobj_t*)listener_p;
+  for (cnum = 0; cnum < numChannels; cnum++) {
+    c = &channels[cnum];
+    sfx = c->sfxinfo;
+
+    if (c->sfxinfo) {
+      if (I_SoundIsPlaying(c->handle)) {
+
+        volume = snd_SfxVolume;
+        pitch = 128;
+        sep = 128;
+
+        if (sfx->link) {
+          pitch = sfx->pitch;
+          volume += sfx->volume;
+          if (volume < 1) {
+            S_StopChannel(cnum);
+            continue;
+          } else if (volume > snd_SfxVolume) {
+            volume = snd_SfxVolume;
+          }
+        }
+
+        if (c->origin && listener_p != c->origin) {
+          audible =
+            S_AdjustSoundParams(listener, c->origin, &volume, &sep, &pitch);
+
+          if (!audible) {
+            S_StopChannel(cnum);
+          } else
+            I_UpdateSoundParams(c->handle, volume, sep, pitch);
+        }
+      } else {
+
+        S_StopChannel(cnum);
+      }
+    }
+  }
+}
+
+void
+S_SetMusicVolume(int volume)
+{
+  if (volume < 0 || volume > 127) {
+    I_Error("Attempt to set music volume at %d", volume);
+  }
+
+  I_SetMusicVolume(127);
+  I_SetMusicVolume(volume);
+  snd_MusicVolume = volume;
+}
+
+void
+S_SetSfxVolume(int volume)
+{
+
+  if (volume < 0 || volume > 127)
+    I_Error("Attempt to set sfx volume at %d", volume);
+
+  snd_SfxVolume = volume;
+}
+
+void
+S_StartMusic(int m_id)
+{
+  S_ChangeMusic(m_id, false);
+}
+
+void
+S_ChangeMusic(int musicnum, int looping)
+{
+  musicinfo_t* music;
+  char namebuf[9];
+
+  if ((musicnum <= mus_None) || (musicnum >= NUMMUSIC)) {
+    I_Error("Bad music number %d", musicnum);
+  } else
+    music = &S_music[musicnum];
+
+  /* We don't know that I_Error exits, so actually a false positive;
+     see PR analyzer/108867.  */
+
+  if (mus_playing == music) /* { dg-warning "use of uninitialized value 'music'" } */
+    return;
+
+  S_StopMusic();
+
+  /* We shouldn't issue further warnings about 'music' being
+     uninitialized.  */
+
+  if (!music->lumpnum) { /* { dg-bogus "use of uninitialized value 'music'" } */
+    sprintf(namebuf, "d_%s", music->name); /* { dg-bogus "use of uninitialized value 'music'" } */
+    music->lumpnum = W_GetNumForName(namebuf); /* { dg-bogus "use of uninitialized value 'music'" } */
+  }
+
+  music->data = (void*)W_CacheLumpNum(music->lumpnum, 3); /* { dg-bogus "use of uninitialized value 'music'" } */
+  music->handle = I_RegisterSong(music->data); /* { dg-bogus "use of uninitialized value 'music'" } */
+
+  I_PlaySong(music->handle, looping); /* { dg-bogus "use of uninitialized value 'music'" } */
+
+  mus_playing = music; /* { dg-bogus "use of uninitialized value 'music'" } */
+}
+
+void
+S_StopMusic(void)
+{
+  if (mus_playing) {
+    if (mus_paused)
+      I_ResumeSong(mus_playing->handle);
+
+    I_StopSong(mus_playing->handle);
+    I_UnRegisterSong(mus_playing->handle);
+    {
+      if (((memblock_t*)((byte*)(mus_playing->data) - sizeof(memblock_t)))
+            ->id != 0x1d4a11)
+        I_Error("Z_CT at "
+                "s_sound.c"
+                ":%i",
+                699);
+      Z_ChangeTag2(mus_playing->data, 101);
+    };
+    ;
+
+    mus_playing->data = 0;
+    mus_playing = 0;
+  }
+}
+
+void
+S_StopChannel(int cnum)
+{
+
+  int i;
+  channel_t* c = &channels[cnum];
+
+  if (c->sfxinfo) {
+
+    if (I_SoundIsPlaying(c->handle)) {
+
+      I_StopSound(c->handle);
+    }
+
+    for (i = 0; i < numChannels; i++) {
+      if (cnum != i && c->sfxinfo == channels[i].sfxinfo) {
+        break;
+      }
+    }
+
+    c->sfxinfo->usefulness--;
+
+    c->sfxinfo = 0;
+  }
+}
+int
+S_AdjustSoundParams(mobj_t* listener,
+                    mobj_t* source,
+                    int* vol,
+                    int* sep,
+                    int* pitch)
+{
+  fixed_t approx_dist;
+  fixed_t adx;
+  fixed_t ady;
+  angle_t angle;
+
+  adx = abs(listener->x - source->x);
+  ady = abs(listener->y - source->y);
+
+  approx_dist = adx + ady - ((adx < ady ? adx : ady) >> 1);
+
+  if (gamemap != 8 && approx_dist > (1200 * 0x10000)) {
+    return 0;
+  }
+
+  angle = R_PointToAngle2(listener->x, listener->y, source->x, source->y);
+
+  if (angle > listener->angle)
+    angle = angle - listener->angle;
+  else
+    angle = angle + (0xffffffff - listener->angle);
+
+  angle >>= 19;
+
+  *sep = 128 - (FixedMul((96 * 0x10000), finesine[angle]) >> 16);
+
+  if (approx_dist < (160 * 0x10000)) {
+    *vol = snd_SfxVolume;
+  } else if (gamemap == 8) {
+    if (approx_dist > (1200 * 0x10000))
+      approx_dist = (1200 * 0x10000);
+
+    *vol =
+      15 + ((snd_SfxVolume - 15) * (((1200 * 0x10000) - approx_dist) >> 16)) /
+             (((1200 * 0x10000) - (160 * 0x10000)) >> 16);
+  } else {
+
+    *vol = (snd_SfxVolume * (((1200 * 0x10000) - approx_dist) >> 16)) /
+           (((1200 * 0x10000) - (160 * 0x10000)) >> 16);
+  }
+
+  return (*vol > 0);
+}
+int
+S_getChannel(void* origin, sfxinfo_t* sfxinfo)
+{
+
+  int cnum;
+
+  channel_t* c;
+
+  for (cnum = 0; cnum < numChannels; cnum++) {
+    if (!channels[cnum].sfxinfo)
+      break;
+    else if (origin && channels[cnum].origin == origin) {
+      S_StopChannel(cnum);
+      break;
+    }
+  }
+
+  if (cnum == numChannels) {
+
+    for (cnum = 0; cnum < numChannels; cnum++)
+      if (channels[cnum].sfxinfo->priority >= sfxinfo->priority) /* { dg-warning "dereference of NULL" } */
+        break;
+
+    if (cnum == numChannels) {
+
+      return -1;
+    } else {
+
+      S_StopChannel(cnum);
+    }
+  }
+
+  c = &channels[cnum];
+
+  c->sfxinfo = sfxinfo;
+  c->origin = origin;
+
+  return cnum;
+}
index b12408a69a01611d890f6cbe1088e68aa6798b46..418168d413e55a38ea1960c21ecff001491a9243 100644 (file)
@@ -5,6 +5,8 @@
    It was fixed by e.g. 342ffc26693b528648bdc9377e51e4f2450b4860 on linux-4.13.y
    in linux-stable.  */
 
+/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
+
 #include "analyzer-decls.h"
 #include <string.h>
 
diff --git a/gcc/testsuite/gcc.dg/analyzer/null-deref-pr108830.c b/gcc/testsuite/gcc.dg/analyzer/null-deref-pr108830.c
new file mode 100644 (file)
index 0000000..417ab00
--- /dev/null
@@ -0,0 +1,94 @@
+/* Reduced from apr-1.7.0/tables/apr_hash.c: 'apr_hash_merge' */
+
+/* { dg-additional-options "-Wno-analyzer-too-complex" } */
+
+#define NULL ((void*)0)
+
+typedef __SIZE_TYPE__ size_t;
+
+extern void*
+memset(void* __s, int __c, size_t __n)
+  __attribute__((__nothrow__, __leaf__, __nonnull__(1)));
+
+typedef struct apr_pool_t apr_pool_t;
+
+void*
+apr_palloc(apr_pool_t* p, size_t size)
+  __attribute__((alloc_size(2), nonnull(1)));
+
+typedef struct apr_hash_t apr_hash_t;
+typedef struct apr_hash_index_t apr_hash_index_t;
+typedef unsigned int (*apr_hashfunc_t)(const char* key, size_t* klen);
+typedef struct apr_hash_entry_t apr_hash_entry_t;
+
+struct apr_hash_entry_t
+{
+  apr_hash_entry_t* next;
+  unsigned int hash;
+  const void* key;
+  size_t klen;
+  const void* val;
+};
+
+struct apr_hash_t
+{
+  apr_pool_t* pool;
+  apr_hash_entry_t** array;
+  /* [...snip.../ */
+  unsigned int count, max, seed;
+  apr_hashfunc_t hash_func;
+  apr_hash_entry_t* free;
+};
+
+static apr_hash_entry_t**
+alloc_array(apr_hash_t* ht, unsigned int max)
+{
+  return memset(apr_palloc(ht->pool, sizeof(*ht->array) * (max + 1)),
+                0,
+                sizeof(*ht->array) * (max + 1));
+}
+
+apr_hash_t*
+apr_hash_merge(apr_pool_t* p,
+               const apr_hash_t* overlay,
+               const apr_hash_t* base)
+{
+  apr_hash_t* res;
+  apr_hash_entry_t* new_vals = NULL;
+  apr_hash_entry_t* iter;
+  unsigned int i, j, k;
+  res = apr_palloc(p, sizeof(apr_hash_t));
+  res->pool = p;
+  res->free = NULL;
+  res->hash_func = base->hash_func;
+  res->count = base->count;
+  res->max = (overlay->max > base->max) ? overlay->max : base->max;
+  if (base->count + overlay->count > res->max) {
+    res->max = res->max * 2 + 1;
+  }
+  res->seed = base->seed;
+  res->array = alloc_array(res, res->max);
+  if (base->count + overlay->count) {
+    new_vals =
+      apr_palloc(p, sizeof(apr_hash_entry_t) * (base->count + overlay->count));
+  }
+  j = 0;
+  for (k = 0; k <= base->max; k++) {
+    for (iter = base->array[k]; iter; iter = iter->next) {
+      i = iter->hash & res->max;
+      /* We should only warn for the first of these
+        (it's actually a false positive, but we don't have the
+        invariante to know that).  */
+      new_vals[j].klen = iter->klen;   /* { dg-warning "dereference of NULL 'new_vals'" } */
+      /* ...but not for subsequent ones: */
+      new_vals[j].key = iter->key;      /* { dg-bogus "dereference of NULL 'new_vals'" "PR analyzer/108830" } */
+      new_vals[j].val = iter->val;      /* { dg-bogus "dereference of NULL 'new_vals'" "PR analyzer/108830" } */
+      new_vals[j].hash = iter->hash;    /* { dg-bogus "dereference of NULL 'new_vals'" "PR analyzer/108830" } */
+      new_vals[j].next = res->array[i]; /* { dg-bogus "dereference of NULL 'new_vals'" "PR analyzer/108830" } */
+      res->array[i] = &new_vals[j];     /* { dg-bogus "dereference of NULL 'new_vals'" "PR analyzer/108830" } */
+      j++;
+    }
+  }
+  /* [...snip...] */
+  return res;
+}
index 6b95442e3227b3852d6e40977a567c42ee8c818d..156f0114fd52b3863ad0abf1ecce876aba55ab96 100644 (file)
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
+
 #include "analyzer-decls.h"
 
 extern int pipe(int pipefd[2]);
index 0de676305f665051318f83ece46b02ed917e4375..8b1822d97f990cc11da23a571bc22a9456592d98 100644 (file)
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
+
 extern void pipe(int pipefd[2]);
 extern int close(int fd);
 
index d7afc9caaf959e2a7a5872ef6de354a648bb12db..aa0684e5c86c7024a3c6ba920a5ababba1b3006b 100644 (file)
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
+
 #include "analyzer-decls.h"
 
 extern int pipe2(int pipefd[2], int flags);
index b42e64ce3389ffa2a24f3a5ae04356ee1f335321..d1c3c915e0e48439f2e1320e9c6653b89c54692c 100644 (file)
@@ -2,10 +2,18 @@ char *
 fopen (const char *restrict, const char *restrict);
 
 void
-k2 (void)
+k2_uninit (void)
 {
   char *setfiles[1];
   int i; /* { dg-message "region created on stack here" } */
 
   setfiles[i] = fopen ("", ""); /* { dg-warning "use of uninitialized value 'i'" } */
+}
+
+void
+k2_leak (int i)
+{
+  char *setfiles[1];
+
+  setfiles[i] = fopen ("", "");
 } /* { dg-warning "leak of FILE" } */
index 7700c7d030ff56da32d1a33d3778c682b550c6d1..4bef2f161a48d19764b93337a659d6adb04d074e 100644 (file)
@@ -5,12 +5,22 @@ void
 err (void);
 
 void
-k2 (void)
+k2_uninit (void)
 {
   char *setfiles[1];
   int i; /* { dg-message "region created on stack here" } */
 
   setfiles[i] = fopen("", ""); /* { dg-warning "use of uninitialized value 'i'" } */
-  if (!setfiles[i]) /* { dg-warning "use of uninitialized value 'i'" } */
+  if (!setfiles[i])
+    err ();
+}
+
+void
+k2_leak (int i)
+{
+  char *setfiles[1];
+
+  setfiles[i] = fopen("", "");
+  if (!setfiles[i])
     err ();
 } /* { dg-warning "leak of FILE" } */
diff --git a/gcc/testsuite/gcc.dg/analyzer/pr104224-split.c b/gcc/testsuite/gcc.dg/analyzer/pr104224-split.c
new file mode 100644 (file)
index 0000000..b90fe55
--- /dev/null
@@ -0,0 +1,136 @@
+#include <stdio.h>
+
+struct test {
+        int one;
+        int two;
+};
+
+void func2(const struct test *t)
+{
+        if (t->one == 0)
+                printf("init func2\n");
+
+        if (t->two == 0)  /* { dg-warning "uninitialized" } */
+                printf("uninit func2\n");
+}
+
+void func1(struct test *t)
+{
+        t->one = 1;
+        func2(t);
+}
+
+int func3(int num)
+{
+        if (num)
+                return num;
+        else
+                return 0;
+}
+
+void func4(int *a, int max)
+{
+        int i;
+        // skip the first
+        for (i=1; i<max; i++)
+                a[i] = 0;
+}
+
+void func5(const int *a, int max)
+{
+        /* a[0] is uninitialized, but the rest of the array is initialized.  */
+        int i;
+        for (i=0; i<max; i++) {
+                if (a[i]) /* { dg-warning "uninitialized" "" { xfail *-*-* } } */
+                        printf("func5: %d\n", i);
+        }
+}
+
+int func6(const int *num)
+{
+        if (*num)  /* { dg-warning "uninitialized" } */
+                return *num;
+        else
+                return 0;
+}
+
+int j;
+int func7(void)
+{
+        return j;  /* { dg-bogus "uninitialized" } */
+}
+
+void func8(const int *a, int max)
+{
+        int i;
+        for (i=0; i<max; i++) {
+                if (a[i]) /* { dg-warning "uninitialized" } */
+                        printf("func8: %d\n", i);
+        }
+}
+
+enum {RED, AMBER, GREEN, BLACK};
+
+int test_1 (void)
+{
+        struct test t;  /* { dg-message "region created on stack here" } */
+
+        func1(&t);
+        return 0;
+}
+
+int test_2 (void)
+{
+        int num;  /* { dg-message "region created on stack here" } */
+
+        func3(num);  /* { dg-warning "use of uninitialized value 'num'" } */
+        return 0;
+}
+
+int test_3 (void)
+{
+        int arry[10];
+
+        func4(arry, 10);
+        func5(arry, 10);
+
+        return 0;
+}
+
+int test_4 (void)
+{
+        int num;  /* { dg-message "region created on stack here" } */
+
+        func6(&num);
+        return 0;
+}
+
+int test_5 (void)
+{
+        int arry_2[10];  /* { dg-message "region created on stack here" } */
+
+        printf("func7: %d\n", func7());
+        func8(arry_2, 10);
+
+        return 0;
+}
+
+int test_6 (void)
+{
+        int go;  /* { dg-message "region created on stack here" } */
+        int color = BLACK;
+
+        switch (color) {
+        case RED:
+        case AMBER:
+                go = 0;
+                break;
+        case GREEN:
+                go = 1;
+                break;
+        }
+
+        printf("go :%d\n", go); /* { dg-warning "use of uninitialized value 'go'" } */
+
+        return 0;
+}
index b047c4ca5f205281ce7965756ae6a326b2fb8f6d..1ff5f9eae71017ab3cead256891ccf45e90bdd00 100644 (file)
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
+
 #include <stdio.h>
 
 struct test {
index a39775354a33b1b91b4ea1a2225045d5ddccc8b3..ab3e4b6628a3693dee76c6539851bbe34f35cf17 100644 (file)
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
+
 #include "analyzer-decls.h"
 
 typedef __SIZE_TYPE__ size_t;
index 89676e1ca0d4f458e020cdc7e2e042d293c4f288..eec61497d5b4dbf6b979c0a276adcf2c42267a1c 100644 (file)
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
+
 #include "analyzer-decls.h"
 
 typedef __SIZE_TYPE__ size_t;
index 75f0b70a99635f92a437f57aa0676c3be06b0e81..137e05b87aa5a44ffa1b8a30a1f41dcf1ef3c9f1 100644 (file)
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
+
 #include "analyzer-decls.h"
 
 typedef __SIZE_TYPE__ size_t;
index e55f10de66be10bb843c7af39f65f5f09c50f85f..4422075e2b59ea8f7ef06a25d0e75ad62096f9dd 100644 (file)
@@ -1,5 +1,6 @@
 /* As per stdarg-1.c, but using the ms_abi versions of the builtins.  */
 
+/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
 /* { dg-do compile { target { x86_64-*-* && lp64 } } } */
 
 #include "analyzer-decls.h"
index fb49b3584e2a2feded19b4ad6822fd05325f89de..ba90df205884e33909f29dc41caf71276983afe3 100644 (file)
@@ -1,5 +1,6 @@
 /* As per stdarg-1.c, but using the sysv_abi versions of the builtins.  */
 
+/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
 /* { dg-do compile { target { x86_64-*-* && lp64 } } } */
 
 #include "analyzer-decls.h"
index f2766a505227bac0b8b7d8cc046531c34863f9d6..4d5431b822c4bed466a6392194456be63f1cd9ae 100644 (file)
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
+
 #include "analyzer-decls.h"
 
 /* Unpacking a va_list.  */
index 2f4e00bcc25d0c3818c885fba441ededabc1652f..0d78242381a6be39f4b4a061dd711ad4a7da022f 100644 (file)
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
+
 #include "analyzer-decls.h"
 
 /* The example from store.h  */
index 665e0b645d393effef5a8f4eca5c1c15bcef213b..c1464555e8ac4a52b6b1d49745e370a24d1afd2b 100644 (file)
@@ -31,16 +31,20 @@ void test_2 (int i)
   __analyzer_eval (arr[i] == 42); /* { dg-warning "UNKNOWN" } */
 }
 
-void test_3 (int i)
+void test_3_concrete_read (int i)
 {
   /* An array that can't have been touched.  */
   int arr[2];
   
   /* Concrete reads.  */
-  __analyzer_eval (arr[0] == 42); /* { dg-warning "UNKNOWN" "unknown" } */
-  /* { dg-warning "use of uninitialized value 'arr\\\[0\\\]'" "uninit" { target *-*-* } .-1 } */
+  __analyzer_eval (arr[0] == 42); /* { dg-warning "use of uninitialized value 'arr\\\[0\\\]'" } */
+}
 
+void test_3_symbolic_read (int i)
+{
+  /* An array that can't have been touched.  */
+  int arr[2];
+  
   /* Symbolic read.  */
-  __analyzer_eval (arr[i] == 42); /* { dg-warning "UNKNOWN" "unknown" } */
-  /* { dg-warning "use of uninitialized value 'arr\\\[i\\\]'" "uninit" { target *-*-* } .-1 } */
+  __analyzer_eval (arr[i] == 42); /* { dg-warning "use of uninitialized value 'arr\\\[i\\\]'" } */
 }
index 616cb3423481f29922517cb5841c2f7f49d385ec..31c6ae0c611b17c309ab68a3233c90d8a57c517d 100644 (file)
@@ -22,7 +22,7 @@ alloc_foo (int a, int b)
   return p;
 }
 
-void test (int x, int y, int z)
+void test_access_inited_fields (int x, int y, int z)
 {
   struct foo *p = alloc_foo (x, z);
   if (!p)
@@ -30,10 +30,20 @@ void test (int x, int y, int z)
 
   __analyzer_eval (p->i == x); /* { dg-warning "TRUE" } */
 
-  __analyzer_eval (p->j == y); /* { dg-warning "UNKNOWN" "unknown" } */
-  /* { dg-warning "use of uninitialized value '\\*p\\.j'" "uninit" { target *-*-* } .-1 } */
-
   __analyzer_eval (p->k == z); /* { dg-warning "TRUE" } */
   
   free (p);
 }
+
+void test_stop_after_accessing_uninit (int x, int y, int z)
+{
+  struct foo *p = alloc_foo (x, z);
+  if (!p)
+    return;
+
+  __analyzer_eval (p->i == x); /* { dg-warning "TRUE" } */
+
+  __analyzer_eval (p->j == y); /* { dg-warning "use of uninitialized value '\\*p\\.j'" } */
+
+  __analyzer_dump_path (); /* { dg-bogus "path" } */
+}
diff --git a/gcc/testsuite/gcc.dg/analyzer/uninit-8.c b/gcc/testsuite/gcc.dg/analyzer/uninit-8.c
new file mode 100644 (file)
index 0000000..2fa1052
--- /dev/null
@@ -0,0 +1,73 @@
+struct st
+{
+  int a, b, c, d, e;
+};
+
+int
+test_1 (int flag, struct st *p)
+{
+  struct st *q;
+  int result = 0;
+  if (flag)
+    q = p;
+  /* We should only warn about the first use of uninit for 'q':  */
+  result += q->a; /* { dg-warning "use of uninitialized value 'q'" } */
+  /* ...and not for these:  */
+  result += q->b; /* { dg-bogus "use of uninitialized value 'q'" } */
+  result += q->c; /* { dg-bogus "use of uninitialized value 'q'" } */
+  result += q->d; /* { dg-bogus "use of uninitialized value 'q'" } */
+  result += q->e; /* { dg-bogus "use of uninitialized value 'q'" } */
+  return result;
+}
+
+int
+test_2 (int flag, struct st *p, struct st *r)
+{
+  struct st *q;
+  int result = 0;
+  if (flag)
+    q = p;
+  /* We should only warn about the first use of uninit for 'q':  */
+  if (q == r) /* { dg-warning "use of uninitialized value 'q'" } */
+    result += 1;
+  /* ...and not for these, after a conditional:  */
+  result += q->b; /* { dg-bogus "use of uninitialized value 'q'" } */
+  result += q->c; /* { dg-bogus "use of uninitialized value 'q'" } */
+  result += q->d; /* { dg-bogus "use of uninitialized value 'q'" } */
+  result += q->e; /* { dg-bogus "use of uninitialized value 'q'" } */
+  return result;
+}
+
+int
+test_3 (int flag, int val)
+{
+  int result = 0;
+  int idx;
+  if (flag)
+    idx = val;
+  switch (idx) /* { dg-warning "use of uninitialized value 'idx'" } */
+    {
+    case 0:
+      result = 3;
+      break;
+    case 1:
+      result = 4;
+      break;
+    default:
+      result = 5;
+      break;      
+    }
+  switch (idx) /* { dg-bogus "use of uninitialized value 'idx'" } */
+    {
+    case 0:
+      result += 3;
+      break;
+    case 1:
+      result += 4;
+      break;
+    default:
+      result += 5;
+      break;
+    }
+  return result;
+}
index e3bb8ceb5b3812a035838734c77aacbb4272b1ef..cb91462c36ba944b3cfa4ac0419ec7165f584e6d 100644 (file)
@@ -1,11 +1,19 @@
 void f1 (int *);
 void f2 (int);
 
-int foo (void)
+int test_1 (void)
 {
   int *p; /* { dg-message "region created on stack here" } */
 
   f1 (p); /* { dg-warning "use of uninitialized value 'p'" } */
+  f1 (p); /* { dg-bogus "use of uninitialized value 'p'" "no followup warnings" } */
+  return 0;
+}
+
+int test_2 (void)
+{
+  int *p; /* { dg-message "region created on stack here" } */
+
   f2 (p[0]); /* { dg-warning "use of uninitialized value 'p'" } */
   return 0;
 }
index 9676e0b384575ce63e60e8de606ac71d4609f5a7..8c83de4863bc71bc09dd7a3fabe82cc001977aad 100644 (file)
@@ -1,3 +1,5 @@
+/* { dg-additional-options "-fno-analyzer-suppress-followups" } */
+
 typedef unsigned char Byte;
 typedef unsigned int uInt;
 typedef unsigned long uLong;
This page took 0.196263 seconds and 5 git commands to generate.