Re: [PATCH] D12358: [Analyzer] Widening loops which do not exit

2015-10-29 Thread Sean Eveson via cfe-commits
seaneveson updated this revision to Diff 38717.
seaneveson added a comment.

Updated to latest revision


http://reviews.llvm.org/D12358

Files:
  include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
  include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
  lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
  lib/StaticAnalyzer/Core/CMakeLists.txt
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  lib/StaticAnalyzer/Core/LoopWidening.cpp
  test/Analysis/analyzer-config.c
  test/Analysis/analyzer-config.cpp
  test/Analysis/loop-widening.c

Index: test/Analysis/loop-widening.c
===
--- /dev/null
+++ test/Analysis/loop-widening.c
@@ -0,0 +1,190 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-max-loop 4 -analyzer-config widen-loops=true -verify %s
+
+void clang_analyzer_eval(int);
+void clang_analyzer_warnIfReached();
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void free(void *);
+
+void loop_which_iterates_limit_times_not_widened() {
+  int i;
+  int x = 1;
+  // Check loop isn't widened by checking x isn't invalidated
+  for (i = 0; i < 1; ++i) {}
+  clang_analyzer_eval(x == 1); // expected-warning {{TRUE}}
+  for (i = 0; i < 2; ++i) {}
+  clang_analyzer_eval(x == 1); // expected-warning {{TRUE}}
+  for (i = 0; i < 3; ++i) {}
+  // FIXME loss of precision as a result of evaluating the widened loop body
+  //   *instead* of the last iteration.
+  clang_analyzer_eval(x == 1); // expected-warning {{UNKNOWN}}
+}
+
+int a_global;
+
+void loop_evaluated_before_widening() {
+  int i;
+  a_global = 1;
+  for (i = 0; i < 10; ++i) {
+if (i == 2) {
+  // True before widening then unknown after.
+  clang_analyzer_eval(a_global == 1); // expected-warning{{TRUE}} expected-warning{{UNKNOWN}}
+}
+  }
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void warnings_after_loop() {
+  int i;
+  for (i = 0; i < 10; ++i) {}
+  char *m = (char*)malloc(12);
+} // expected-warning {{Potential leak of memory pointed to by 'm'}}
+
+void for_loop_exits() {
+  int i;
+  for (i = 0; i < 10; ++i) {}
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void while_loop_exits() {
+  int i = 0;
+  while (i < 10) {++i;}
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void do_while_loop_exits() {
+  int i = 0;
+  do {++i;} while (i < 10);
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void loop_body_is_widened() {
+  int i = 0;
+  while (i < 100) {
+if (i > 10) {
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+++i;
+  }
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void invariably_infinite_loop() {
+  int i = 0;
+  while (1) { ++i; }
+  clang_analyzer_warnIfReached(); // no-warning
+}
+
+void invariably_infinite_break_loop() {
+  int i = 0;
+  while (1) {
+++i;
+int x = 1;
+if (!x) break;
+  }
+  clang_analyzer_warnIfReached(); // no-warning
+}
+
+void reachable_break_loop() {
+  int i = 0;
+  while (1) {
+++i;
+if (i == 100) break;
+  }
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void condition_constrained_true_in_loop() {
+  int i = 0;
+  while (i < 50) {
+clang_analyzer_eval(i < 50); // expected-warning {{TRUE}}
+++i;
+  }
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void condition_constrained_false_after_loop() {
+  int i = 0;
+  while (i < 50) {
+++i;
+  }
+  clang_analyzer_eval(i >= 50); // expected-warning {{TRUE}}
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void multiple_exit_test() {
+  int x = 0;
+  int i = 0;
+  while (i < 50) {
+if (x) {
+  i = 10;
+  break;
+}
+++i;
+  }
+  // Reachable by 'normal' exit
+  if (i == 50) clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  // Reachable by break point
+  if (i == 10) clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  // Not reachable
+  if (i < 10) clang_analyzer_warnIfReached(); // no-warning
+  if (i > 10 && i < 50) clang_analyzer_warnIfReached(); // no-warning
+}
+
+void pointer_doesnt_leak_from_loop() {
+  int *h_ptr = (int *) malloc(sizeof(int));
+  for (int i = 0; i < 2; ++i) {}
+  for (int i = 0; i < 10; ++i) {} // no-warning
+  free(h_ptr);
+}
+
+int g_global;
+
+void unknown_after_loop(int s_arg) {
+  g_global = 0;
+  s_arg = 1;
+  int s_local = 2;
+  int *h_ptr = malloc(sizeof(int));
+
+  for (int i = 0; i < 10; ++i) {}
+
+  clang_analyzer_eval(g_global); // expected-warning {{UNKNOWN}}
+  clang_analyzer_eval(s_arg); // expected-warning {{UNKNOWN}}
+  clang_analyzer_eval(s_local); // expected-warning {{UNKNOWN}}
+  clang_analyzer_eval(h_ptr == 0); // expected-warning {{UNKNOWN}}
+  free(h_ptr);
+}
+
+void variable_bound_exiting_loops_widened(int x) {
+  int i = 0;
+  int t = 1;
+  while (i < x) {

Re: [PATCH] D12358: [Analyzer] Widening loops which do not exit

2015-10-29 Thread Sean Eveson via cfe-commits
This revision was automatically updated to reflect the committed changes.
Closed by commit rL251621: [Analyzer] Widening loops which do not exit 
(authored by seaneveson).

Changed prior to commit:
  http://reviews.llvm.org/D12358?vs=38717=38718#toc

Repository:
  rL LLVM

http://reviews.llvm.org/D12358

Files:
  cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
  cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
  cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
  cfe/trunk/lib/StaticAnalyzer/Core/CMakeLists.txt
  cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
  cfe/trunk/lib/StaticAnalyzer/Core/LoopWidening.cpp
  cfe/trunk/test/Analysis/analyzer-config.c
  cfe/trunk/test/Analysis/analyzer-config.cpp
  cfe/trunk/test/Analysis/loop-widening.c

Index: cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
===
--- cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
@@ -262,6 +262,9 @@
   /// \sa shouldInlineLambdas
   Optional InlineLambdas;
 
+  /// \sa shouldWidenLoops
+  Optional WidenLoops;
+
   /// A helper function that retrieves option for a given full-qualified
   /// checker name.
   /// Options for checkers can be specified via 'analyzer-config' command-line
@@ -526,6 +529,10 @@
   /// generated each time a LambdaExpr is visited.
   bool shouldInlineLambdas();
 
+  /// Returns true if the analysis should try to widen loops.
+  /// This is controlled by the 'widen-loops' config option.
+  bool shouldWidenLoops();
+
 public:
   AnalyzerOptions() :
 AnalysisStoreOpt(RegionStoreModel),
Index: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
===
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
@@ -0,0 +1,37 @@
+//===--- LoopWidening.h - Instruction class definition --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===--===//
+///
+/// This header contains the declarations of functions which are used to widen
+/// loops which do not otherwise exit. The widening is done by invalidating
+/// anything which might be modified by the body of the loop.
+///
+//===--===//
+
+#ifndef LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_LOOPWIDENING_H
+#define LLVM_CLANG_STATICANALYZER_CORE_PATHSENSITIVE_LOOPWIDENING_H
+
+#include "clang/Analysis/CFG.h"
+#include "clang/StaticAnalyzer/Core/PathSensitive/ProgramState.h"
+
+namespace clang {
+namespace ento {
+
+/// \brief Get the states that result from widening the loop.
+///
+/// Widen the loop by invalidating anything that might be modified
+/// by the loop body in any iteration.
+ProgramStateRef getWidenedLoopState(ProgramStateRef PrevState,
+const LocationContext *LCtx,
+unsigned BlockCount,
+const Stmt *LoopStmt);
+
+} // end namespace ento
+} // end namespace clang
+
+#endif
Index: cfe/trunk/test/Analysis/analyzer-config.c
===
--- cfe/trunk/test/Analysis/analyzer-config.c
+++ cfe/trunk/test/Analysis/analyzer-config.c
@@ -25,6 +25,7 @@
 // CHECK-NEXT: min-cfg-size-treat-functions-as-large = 14
 // CHECK-NEXT: mode = deep
 // CHECK-NEXT: region-store-small-struct-limit = 2
+// CHECK-NEXT: widen-loops = false
 // CHECK-NEXT: [stats]
-// CHECK-NEXT: num-entries = 14
+// CHECK-NEXT: num-entries = 15
 
Index: cfe/trunk/test/Analysis/loop-widening.c
===
--- cfe/trunk/test/Analysis/loop-widening.c
+++ cfe/trunk/test/Analysis/loop-widening.c
@@ -0,0 +1,190 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-max-loop 4 -analyzer-config widen-loops=true -verify %s
+
+void clang_analyzer_eval(int);
+void clang_analyzer_warnIfReached();
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void free(void *);
+
+void loop_which_iterates_limit_times_not_widened() {
+  int i;
+  int x = 1;
+  // Check loop isn't widened by checking x isn't invalidated
+  for (i = 0; i < 1; ++i) {}
+  clang_analyzer_eval(x == 1); // expected-warning {{TRUE}}
+  for (i = 0; i < 2; ++i) {}
+  clang_analyzer_eval(x == 1); // expected-warning {{TRUE}}
+  for (i = 0; i < 3; ++i) {}
+  // FIXME loss of precision as a result of evaluating the widened loop body
+  //   *instead* of the last iteration.
+  clang_analyzer_eval(x == 1); // 

Re: [PATCH] D12358: [Analyzer] Widening loops which do not exit

2015-10-28 Thread Devin Coughlin via cfe-commits
dcoughlin accepted this revision.
dcoughlin added a comment.

LGTM. Please commit. Thanks for tackling this, Sean!


http://reviews.llvm.org/D12358



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D12358: [Analyzer] Widening loops which do not exit

2015-10-27 Thread Sean Eveson via cfe-commits
seaneveson updated this revision to Diff 38519.
seaneveson added a comment.

Removed checking for already exited loops
Addressed Comments


http://reviews.llvm.org/D12358

Files:
  include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
  include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
  lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
  lib/StaticAnalyzer/Core/CMakeLists.txt
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  lib/StaticAnalyzer/Core/LoopWidening.cpp
  test/Analysis/analyzer-config.c
  test/Analysis/analyzer-config.cpp
  test/Analysis/loop-widening.c

Index: test/Analysis/loop-widening.c
===
--- test/Analysis/loop-widening.c
+++ test/Analysis/loop-widening.c
@@ -0,0 +1,190 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-max-loop 4 -analyzer-config widen-loops=true -verify %s
+
+void clang_analyzer_eval(int);
+void clang_analyzer_warnIfReached();
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void free(void *);
+
+void loop_which_iterates_limit_times_not_widened() {
+  int i;
+  int x = 1;
+  // Check loop isn't widened by checking x isn't invalidated
+  for (i = 0; i < 1; ++i) {}
+  clang_analyzer_eval(x == 1); // expected-warning {{TRUE}}
+  for (i = 0; i < 2; ++i) {}
+  clang_analyzer_eval(x == 1); // expected-warning {{TRUE}}
+  for (i = 0; i < 3; ++i) {}
+  // FIXME loss of precision as a result of evaluating the widened loop body
+  //   *instead* of the last iteration.
+  clang_analyzer_eval(x == 1); // expected-warning {{UNKNOWN}}
+}
+
+int a_global;
+
+void loop_evaluated_before_widening() {
+  int i;
+  a_global = 1;
+  for (i = 0; i < 10; ++i) {
+if (i == 2) {
+  // True before widening then unknown after.
+  clang_analyzer_eval(a_global == 1); // expected-warning{{TRUE}} expected-warning{{UNKNOWN}}
+}
+  }
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void warnings_after_loop() {
+  int i;
+  for (i = 0; i < 10; ++i) {}
+  char *m = (char*)malloc(12);
+} // expected-warning {{Potential leak of memory pointed to by 'm'}}
+
+void for_loop_exits() {
+  int i;
+  for (i = 0; i < 10; ++i) {}
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void while_loop_exits() {
+  int i = 0;
+  while (i < 10) {++i;}
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void do_while_loop_exits() {
+  int i = 0;
+  do {++i;} while (i < 10);
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void loop_body_is_widened() {
+  int i = 0;
+  while (i < 100) {
+if (i > 10) {
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+++i;
+  }
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void invariably_infinite_loop() {
+  int i = 0;
+  while (1) { ++i; }
+  clang_analyzer_warnIfReached(); // no-warning
+}
+
+void invariably_infinite_break_loop() {
+  int i = 0;
+  while (1) {
+++i;
+int x = 1;
+if (!x) break;
+  }
+  clang_analyzer_warnIfReached(); // no-warning
+}
+
+void reachable_break_loop() {
+  int i = 0;
+  while (1) {
+++i;
+if (i == 100) break;
+  }
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void condition_constrained_true_in_loop() {
+  int i = 0;
+  while (i < 50) {
+clang_analyzer_eval(i < 50); // expected-warning {{TRUE}}
+++i;
+  }
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void condition_constrained_false_after_loop() {
+  int i = 0;
+  while (i < 50) {
+++i;
+  }
+  clang_analyzer_eval(i >= 50); // expected-warning {{TRUE}}
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void multiple_exit_test() {
+  int x = 0;
+  int i = 0;
+  while (i < 50) {
+if (x) {
+  i = 10;
+  break;
+}
+++i;
+  }
+  // Reachable by 'normal' exit
+  if (i == 50) clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  // Reachable by break point
+  if (i == 10) clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  // Not reachable
+  if (i < 10) clang_analyzer_warnIfReached(); // no-warning
+  if (i > 10 && i < 50) clang_analyzer_warnIfReached(); // no-warning
+}
+
+void pointer_doesnt_leak_from_loop() {
+  int *h_ptr = (int *) malloc(sizeof(int));
+  for (int i = 0; i < 2; ++i) {}
+  for (int i = 0; i < 10; ++i) {} // no-warning
+  free(h_ptr);
+}
+
+int g_global;
+
+void unknown_after_loop(int s_arg) {
+  g_global = 0;
+  s_arg = 1;
+  int s_local = 2;
+  int *h_ptr = malloc(sizeof(int));
+
+  for (int i = 0; i < 10; ++i) {}
+
+  clang_analyzer_eval(g_global); // expected-warning {{UNKNOWN}}
+  clang_analyzer_eval(s_arg); // expected-warning {{UNKNOWN}}
+  clang_analyzer_eval(s_local); // expected-warning {{UNKNOWN}}
+  clang_analyzer_eval(h_ptr == 0); // expected-warning {{UNKNOWN}}
+  free(h_ptr);
+}
+
+void 

Re: [PATCH] D12358: [Analyzer] Widening loops which do not exit

2015-10-27 Thread Sean Eveson via cfe-commits
seaneveson marked 5 inline comments as done.


Comment at: test/Analysis/loop-widening.c:160
@@ +159,3 @@
+void variable_bound_exiting_loops_widened(int x) {
+  int i = 0;
+  int t = 1;

The inner loop will now be widened in the first example test, which 
'coincidentally' widens the outer loop as well. This means this text now passes.


http://reviews.llvm.org/D12358



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D12358: [Analyzer] Widening loops which do not exit

2015-10-26 Thread Sean Eveson via cfe-commits
seaneveson marked an inline comment as done.
seaneveson added a comment.

Hi Devin,

Sorry it also took me so long to get back to you.



Comment at: include/clang/StaticAnalyzer/Core/AnalyzerOptions.h:266
@@ +265,3 @@
+  /// \sa shouldWidenLoops
+  bool WidenLoops;
+

dcoughlin wrote:
> Is this field used?
No. Thanks I'll fix that.


Comment at: lib/StaticAnalyzer/Core/ExprEngine.cpp:1407
@@ +1406,3 @@
+const CFGBlock *Following = getBlockAfterLoop(L.getDst());
+if (Following && nodeBuilder.getContext().Eng.blockWasVisited(Following))
+  return;

dcoughlin wrote:
> What is the purpose of checking whether the block has already been visited by 
> some other path?
> 
> If I understand correctly, this will stop the analyzer from widening before 
> the "last" iteration through the loop and so will result in a sink after that 
> iteration. What this means is that we will never explore the code beyond the 
> loop in the widened state -- but isn't this the whole point of the widening?
> 
> So, for example, in your `variable_bound_exiting_loops_not_widened()` test, 
> don't we want the clang_analyzer_eval() statement after the loop to be 
> symbolically executed on 4 separate paths? That is, once when i is 0, once 
> when i is 1, once when i is 2 and once when i is $conj_i$ + 1 where $conj_i$ 
> is the value conjured for i when widening.
> 
> Also, in general, analysis of one path should not depend at all on whether 
> another path has been explored. This is because we want the analyzer to be 
> free choose different strategies about path exploration (e.g., BFS vs. DFS, 
> prioritizing some paths over others, etc.) without changing the issues 
> reported on along any given path. For this reason, I don't think we 
> necessarily want to track and expose `blockWasVisited()` on CoreEngine or use 
> this to determine when to permit a sink.
> 
> 
I was trying to avoid doing unnecessary invalidation, where the variable bound 
loop had already exited. I suppose this won’t be a concern when the 
invalidation is improved. If everyone is happy for loops that have already 
exited to be widened then I will remove the related changes.


Comment at: lib/StaticAnalyzer/Core/LoopWidening.cpp:98
@@ +97,3 @@
+  RegionAndSymbolInvalidationTraits ITraits;
+  for (int RegionIndex = 0; RegionIndex < NumRegions; ++ RegionIndex) {
+ITraits.setTrait(Regions[RegionIndex],

dcoughlin wrote:
> I get a warning here about comparing a signed int (RegionIndex) to an 
> unsigned (NumRegions).
> 
> I think you can avoid this and simplify things by using a range-based for 
> loop:
> ```
>   const MemRegion *Regions[] = {
>   ...
>   };
>   RegionAndSymbolInvalidationTraits ITraits;
>   for (auto *Region : Regions) {
> ...
>   }
> ```
Will do. Thanks.


http://reviews.llvm.org/D12358



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D12358: [Analyzer] Widening loops which do not exit

2015-10-20 Thread Devin Coughlin via cfe-commits
dcoughlin added a comment.

Hi Sean,

Sorry it took me so long to get back to you.



Comment at: include/clang/StaticAnalyzer/Core/AnalyzerOptions.h:266
@@ +265,3 @@
+  /// \sa shouldWidenLoops
+  bool WidenLoops;
+

Is this field used?


Comment at: lib/StaticAnalyzer/Core/ExprEngine.cpp:1407
@@ +1406,3 @@
+const CFGBlock *Following = getBlockAfterLoop(L.getDst());
+if (Following && nodeBuilder.getContext().Eng.blockWasVisited(Following))
+  return;

What is the purpose of checking whether the block has already been visited by 
some other path?

If I understand correctly, this will stop the analyzer from widening before the 
"last" iteration through the loop and so will result in a sink after that 
iteration. What this means is that we will never explore the code beyond the 
loop in the widened state -- but isn't this the whole point of the widening?

So, for example, in your `variable_bound_exiting_loops_not_widened()` test, 
don't we want the clang_analyzer_eval() statement after the loop to be 
symbolically executed on 4 separate paths? That is, once when i is 0, once when 
i is 1, once when i is 2 and once when i is $conj_i$ + 1 where $conj_i$ is the 
value conjured for i when widening.

Also, in general, analysis of one path should not depend at all on whether 
another path has been explored. This is because we want the analyzer to be free 
choose different strategies about path exploration (e.g., BFS vs. DFS, 
prioritizing some paths over others, etc.) without changing the issues reported 
on along any given path. For this reason, I don't think we necessarily want to 
track and expose `blockWasVisited()` on CoreEngine or use this to determine 
when to permit a sink.




Comment at: lib/StaticAnalyzer/Core/LoopWidening.cpp:98
@@ +97,3 @@
+  RegionAndSymbolInvalidationTraits ITraits;
+  for (int RegionIndex = 0; RegionIndex < NumRegions; ++ RegionIndex) {
+ITraits.setTrait(Regions[RegionIndex],

I get a warning here about comparing a signed int (RegionIndex) to an unsigned 
(NumRegions).

I think you can avoid this and simplify things by using a range-based for loop:
```
  const MemRegion *Regions[] = {
  ...
  };
  RegionAndSymbolInvalidationTraits ITraits;
  for (auto *Region : Regions) {
...
  }
```


http://reviews.llvm.org/D12358



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D12358: [Analyzer] Widening loops which do not exit

2015-10-15 Thread Sean Eveson via cfe-commits
seaneveson marked 3 inline comments as done.
seaneveson added a comment.

In http://reviews.llvm.org/D12358#266391, @dcoughlin wrote:

> I think this is an acceptable loss of precision because, in general, it is 
> unlikely that a concrete-bounded loop will be executed *exactly* 
> maxBlockVisitOnPath times. You could add special syntactic checks to try to 
> detect this, but I think it is unlikely to make much different in practice.


I agree.

The problem can be solved by executing the widened state after the last 
iteration, rather than instead of it. This can only really be done by changing 
the max block visit approach. This needs to be done in the future in order to 
support nested loops. This precision issue could also be resolved at that time.



Comment at: include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h:84
@@ +83,3 @@
+  /// The blocks that have been visited during analysis
+  llvm::DenseSet blocksVisited;
+

The BlockCount is specific to the path of analysis, so it can't be used to 
check if a loop has been exited before. I've added this set to store and 
identify previously visited blocks. Is there a better way this can/could be 
done?


Comment at: lib/StaticAnalyzer/Core/LoopWidening.cpp:65
@@ +64,3 @@
+  if (FalseBranch)
+return FalseBranch;
+  // If there isn't a false branch we still have to check for break points

Perfect, thanks.

Perhaps it could be changed back to false when the invalidation is better? Then 
it could catch true positives e.g.
```
int *a = new int[10]
for (int i = 0; i < 100; ++i) {
  if (i > 90) 
++a;
  ...
}
```


Comment at: test/Analysis/loop-widening.c:159
@@ +158,3 @@
+
+void variable_bound_exiting_loops_not_widened(int x) {
+  int i = 0;

Thank you for the example tests.

When an inner loop is widened, any outer loops are widened 'coincidentally' 
since everything is invalidated. This means the second example test passes. 
When an inner loop is not widened the outer loop will not be widened. This is 
because a sink is generated when the max block count is reached the second time 
through the outer loop. i.e.
```
for (i = 0; i < 10; i++) {
  for (j = 0; j < 2; j++) {
// A sink is generated here on the second iteration of the outer loop,
// since this block was already visited twice (when i == 0).
...
  }
}
// Never reach here
```
This means the first example test does not pass. I’ve added the tests with a 
FIXME comment.



http://reviews.llvm.org/D12358



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


Re: [PATCH] D12358: [Analyzer] Widening loops which do not exit

2015-10-15 Thread Sean Eveson via cfe-commits
seaneveson updated this revision to Diff 37462.
seaneveson added a comment.

Set CausedByPointerEscape to true
Check if the loop has already been exited before widening
Changed tests to use void clang_analyze_eval(int)
Added variable bound loop tests
Added nested loop tests


http://reviews.llvm.org/D12358

Files:
  include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
  include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
  include/clang/StaticAnalyzer/Core/PathSensitive/LoopWidening.h
  lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
  lib/StaticAnalyzer/Core/CMakeLists.txt
  lib/StaticAnalyzer/Core/CoreEngine.cpp
  lib/StaticAnalyzer/Core/ExprEngine.cpp
  lib/StaticAnalyzer/Core/LoopWidening.cpp
  test/Analysis/analyzer-config.c
  test/Analysis/analyzer-config.cpp
  test/Analysis/loop-widening.c

Index: test/Analysis/loop-widening.c
===
--- test/Analysis/loop-widening.c
+++ test/Analysis/loop-widening.c
@@ -0,0 +1,202 @@
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,unix.Malloc,debug.ExprInspection -analyzer-store=region -analyzer-max-loop 4 -analyzer-config widen-loops=true -verify %s
+
+void clang_analyzer_eval(int);
+void clang_analyzer_warnIfReached();
+
+typedef __typeof(sizeof(int)) size_t;
+void *malloc(size_t);
+void free(void *);
+
+void loop_which_iterates_limit_times_not_widened() {
+  int i;
+  int x = 1;
+  // Check loop isn't widened by checking x isn't invalidated
+  for (i = 0; i < 1; ++i) {}
+  clang_analyzer_eval(x == 1); // expected-warning {{TRUE}}
+  for (i = 0; i < 2; ++i) {}
+  clang_analyzer_eval(x == 1); // expected-warning {{TRUE}}
+  for (i = 0; i < 3; ++i) {}
+  // FIXME loss of precision as a result of evaluating the widened loop body
+  //   *instead* of the last iteration.
+  clang_analyzer_eval(x == 1); // expected-warning {{UNKNOWN}}
+}
+
+int a_global;
+
+void loop_evaluated_before_widening() {
+  int i;
+  a_global = 1;
+  for (i = 0; i < 10; ++i) {
+if (i == 2) {
+  // True before widening then unknown after.
+  clang_analyzer_eval(a_global == 1); // expected-warning{{TRUE}} expected-warning{{UNKNOWN}}
+}
+  }
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void warnings_after_loop() {
+  int i;
+  for (i = 0; i < 10; ++i) {}
+  char *m = (char*)malloc(12);
+} // expected-warning {{Potential leak of memory pointed to by 'm'}}
+
+void for_loop_exits() {
+  int i;
+  for (i = 0; i < 10; ++i) {}
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void while_loop_exits() {
+  int i = 0;
+  while (i < 10) {++i;}
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void do_while_loop_exits() {
+  int i = 0;
+  do {++i;} while (i < 10);
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void loop_body_is_widened() {
+  int i = 0;
+  while (i < 100) {
+if (i > 10) {
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+++i;
+  }
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void invariably_infinite_loop() {
+  int i = 0;
+  while (1) { ++i; }
+  clang_analyzer_warnIfReached(); // no-warning
+}
+
+void invariably_infinite_break_loop() {
+  int i = 0;
+  while (1) {
+++i;
+int x = 1;
+if (!x) break;
+  }
+  clang_analyzer_warnIfReached(); // no-warning
+}
+
+void reachable_break_loop() {
+  int i = 0;
+  while (1) {
+++i;
+if (i == 100) break;
+  }
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void condition_constrained_true_in_loop() {
+  int i = 0;
+  while (i < 50) {
+clang_analyzer_eval(i < 50); // expected-warning {{TRUE}}
+++i;
+  }
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void condition_constrained_false_after_loop() {
+  int i = 0;
+  while (i < 50) {
+++i;
+  }
+  clang_analyzer_eval(i >= 50); // expected-warning {{TRUE}}
+  clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+}
+
+void multiple_exit_test() {
+  int x = 0;
+  int i = 0;
+  while (i < 50) {
+if (x) {
+  i = 10;
+  break;
+}
+++i;
+  }
+  // Reachable by 'normal' exit
+  if (i == 50) clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  // Reachable by break point
+  if (i == 10) clang_analyzer_warnIfReached(); // expected-warning{{REACHABLE}}
+  // Not reachable
+  if (i < 10) clang_analyzer_warnIfReached(); // no-warning
+  if (i > 10 && i < 50) clang_analyzer_warnIfReached(); // no-warning
+}
+
+void pointer_doesnt_leak_from_loop() {
+  int *h_ptr = (int *) malloc(sizeof(int));
+  for (int i = 0; i < 2; ++i) {}
+  for (int i = 0; i < 10; ++i) {} // no-warning
+  free(h_ptr);
+}
+
+int g_global;
+
+void unknown_after_loop(int s_arg) {
+  g_global = 0;
+  s_arg = 1;
+  int s_local = 2;
+  int *h_ptr = malloc(sizeof(int));
+  
+  for (int i = 0; i < 10; ++i) {}
+  
+  clang_analyzer_eval(g_global); // expected-warning 

Re: [PATCH] D12358: [Analyzer] Widening loops which do not exit

2015-10-13 Thread Devin Coughlin via cfe-commits
dcoughlin added a comment.

> There is a loss of precision for loops that need to be executed exactly 
> maxBlockVisitOnPath times, as the loop body is executed with the widened 
> state instead of the last iteration.


I think this is an acceptable loss of precision because, in general, it is 
unlikely that a concrete-bounded loop will be executed *exactly* 
maxBlockVisitOnPath times. You could add special syntactic checks to try to 
detect this, but I think it is unlikely to make much different in practice.



Comment at: lib/StaticAnalyzer/Core/LoopWidening.cpp:64
@@ +63,3 @@
+  }
+  return PrevState->invalidateRegions(Regions, getLoopCondition(LoopStmt),
+  BlockCount, LCtx, false, nullptr,

Passing `true` here instead of `false` for `CausedByPointerEscape` should fix 
the false alarm. This will cause invalidation to tell the MallocChecker that 
the pointer has escaped and so shouldn't be treated as a leak.


Comment at: test/Analysis/loop-widening.c:3
@@ +2,3 @@
+
+extern void clang_analyzer_eval(_Bool);
+extern void clang_analyzer_warnIfReached();

There seems to be some weirdness when using `_Bool` in the prototype (vs. int). 
It adds an extra `!= 0` to symbolic expressions, which can result in 
clang_analyzer_eval() yielding `UNKNOWN` when using `extern void 
clang_analyze_eval(int)` would print `TRUE` or `FALSE`.

We should track this down and fix it, but for now I think it is better to use 
`extern void clang_analyze_eval(int)`.


Comment at: test/Analysis/loop-widening.c:13
@@ +12,3 @@
+  int x = 1;
+  // Check loop isn't widened by checking x isn't invalidated
+  for (i = 0; i < 1; ++i) {}

This is clever.


Comment at: test/Analysis/loop-widening.c:111
@@ +110,3 @@
+  }
+  if (i < 50) {
+clang_analyzer_warnIfReached(); // no-warning

After changing the `clang_analyzer_eval()` prototype to take an int, you can 
use `clang_analyzer_eval(i >= 50); // expected-warning {{TRUE}}`.


Comment at: test/Analysis/loop-widening.c:158
@@ +157,3 @@
+  clang_analyzer_eval(h_ptr); // expected-warning {{UNKNOWN}}
+  free(h_ptr);
+}

I think it would be good to add some nested loop tests. For example:


```
void nested1() {
  int i = 0, j = 0;
  for (i = 0; i < 10; i++) {
clang_analyzer_eval(i < 10); // expected-warning {{TRUE}}
for (j = 0; j < 2; j++) {
  clang_analyzer_eval(j < 2); // expected-warning {{TRUE}}
}
clang_analyzer_eval(j >= 2); // expected-warning {{TRUE}}
  }
  clang_analyzer_eval(i >= 10); // expected-warning {{TRUE}}
}

void nested2() {
  int i = 0, j = 0;
  for (i = 0; i < 2; i++) {
clang_analyzer_eval(i < 2); // expected-warning {{TRUE}}
for (j = 0; j < 10; j++) {
  clang_analyzer_eval(j < 10); // expected-warning {{TRUE}}
}
clang_analyzer_eval(j >= 10); // expected-warning {{TRUE}}
  }
  clang_analyzer_eval(i >= 2); // expected-warning {{TRUE}}
}
```


http://reviews.llvm.org/D12358



___
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits