Author: george.karpenkov
Date: Mon Feb 12 14:39:57 2018
New Revision: 324956

URL: http://llvm.org/viewvc/llvm-project?rev=324956&view=rev
Log:
[analyzer] Exploration strategy prioritizing unexplored coverage first

See reviews.llvm.org/M1 for evaluation, and
lists.llvm.org/pipermail/cfe-dev/2018-January/056718.html for
discussion.

Differential Revision: https://reviews.llvm.org/D42775

Added:
    cfe/trunk/test/Analysis/exploration_order/
    cfe/trunk/test/Analysis/exploration_order/prefer_unexplored.cc
Modified:
    cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
    cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/CoreEngine.cpp

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h?rev=324956&r1=324955&r2=324956&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/AnalyzerOptions.h Mon Feb 12 
14:39:57 2018
@@ -191,6 +191,7 @@ public:
   enum class ExplorationStrategyKind {
     DFS,
     BFS,
+    UnexploredFirst,
     BFSBlockDFSContents,
     NotSet
   };

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h?rev=324956&r1=324955&r2=324956&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h 
(original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/WorkList.h Mon 
Feb 12 14:39:57 2018
@@ -83,6 +83,7 @@ public:
   static std::unique_ptr<WorkList> makeDFS();
   static std::unique_ptr<WorkList> makeBFS();
   static std::unique_ptr<WorkList> makeBFSBlockDFSContents();
+  static std::unique_ptr<WorkList> makeUnexploredFirst();
 };
 
 } // end GR namespace

Modified: cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp?rev=324956&r1=324955&r2=324956&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/AnalyzerOptions.cpp Mon Feb 12 14:39:57 
2018
@@ -58,22 +58,25 @@ AnalyzerOptions::UserModeKind AnalyzerOp
 AnalyzerOptions::ExplorationStrategyKind
 AnalyzerOptions::getExplorationStrategy() {
   if (ExplorationStrategy == ExplorationStrategyKind::NotSet) {
-    StringRef StratStr = Config.insert(
-            std::make_pair("exploration_strategy", "dfs")).first->second;
-    ExplorationStrategy = llvm::StringSwitch<ExplorationStrategyKind>(StratStr)
-      .Case("dfs", ExplorationStrategyKind::DFS)
-      .Case("bfs", ExplorationStrategyKind::BFS)
-      .Case("bfs_block_dfs_contents", 
ExplorationStrategyKind::BFSBlockDFSContents)
-      .Default(ExplorationStrategyKind::NotSet);
-    assert(ExplorationStrategy != ExplorationStrategyKind::NotSet
-        && "User mode is invalid.");
+    StringRef StratStr =
+        Config
+            .insert(std::make_pair("exploration_strategy", "dfs"))
+            .first->second;
+    ExplorationStrategy =
+        llvm::StringSwitch<ExplorationStrategyKind>(StratStr)
+            .Case("dfs", ExplorationStrategyKind::DFS)
+            .Case("bfs", ExplorationStrategyKind::BFS)
+            .Case("unexplored_first",
+                  ExplorationStrategyKind::UnexploredFirst)
+            .Case("bfs_block_dfs_contents",
+                  ExplorationStrategyKind::BFSBlockDFSContents)
+            .Default(ExplorationStrategyKind::NotSet);
+    assert(ExplorationStrategy != ExplorationStrategyKind::NotSet &&
+           "User mode is invalid.");
   }
   return ExplorationStrategy;
-
 }
 
-
-
 IPAKind AnalyzerOptions::getIPAMode() {
   if (IPAMode == IPAK_NotSet) {
 

Modified: cfe/trunk/lib/StaticAnalyzer/Core/CoreEngine.cpp
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CoreEngine.cpp?rev=324956&r1=324955&r2=324956&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CoreEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CoreEngine.cpp Mon Feb 12 14:39:57 2018
@@ -19,6 +19,7 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h"
 #include "llvm/ADT/Statistic.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/Support/Casting.h"
 
 using namespace clang;
@@ -33,6 +34,9 @@ STATISTIC(NumReachedMaxSteps,
 STATISTIC(NumPathsExplored,
             "The # of paths explored by the analyzer.");
 
+STATISTIC(MaxQueueSize, "Maximum size of the worklist");
+STATISTIC(MaxReachableSize, "Maximum size of auxiliary worklist set");
+
 
//===----------------------------------------------------------------------===//
 // Worklist classes for exploration of reachable states.
 
//===----------------------------------------------------------------------===//
@@ -128,6 +132,64 @@ std::unique_ptr<WorkList> WorkList::make
   return llvm::make_unique<BFSBlockDFSContents>();
 }
 
+class UnexploredFirstStack : public WorkList {
+
+  /// Stack of nodes known to have statements we have not traversed yet.
+  SmallVector<WorkListUnit, 20> StackUnexplored;
+
+  /// Stack of all other nodes.
+  SmallVector<WorkListUnit, 20> StackOthers;
+
+  typedef unsigned BlockID;
+  typedef std::pair<BlockID, const StackFrameContext *> LocIdentifier;
+  llvm::DenseSet<LocIdentifier> Reachable;
+
+public:
+  bool hasWork() const override {
+    return !(StackUnexplored.empty() && StackOthers.empty());
+  }
+
+  void enqueue(const WorkListUnit &U) override {
+    const ExplodedNode *N = U.getNode();
+    auto BE = N->getLocation().getAs<BlockEntrance>();
+
+    if (!BE) {
+
+      // Assume the choice of the order of the preceeding block entrance was
+      // correct.
+      StackUnexplored.push_back(U);
+    } else {
+      LocIdentifier LocId = std::make_pair(
+          BE->getBlock()->getBlockID(), N->getStackFrame());
+      auto InsertInfo = Reachable.insert(LocId);
+
+      if (InsertInfo.second) {
+        StackUnexplored.push_back(U);
+      } else {
+        StackOthers.push_back(U);
+      }
+    }
+    MaxReachableSize.updateMax(Reachable.size());
+    MaxQueueSize.updateMax(StackUnexplored.size() + StackOthers.size());
+  }
+
+  WorkListUnit dequeue() override {
+    if (!StackUnexplored.empty()) {
+      WorkListUnit &U = StackUnexplored.back();
+      StackUnexplored.pop_back();
+      return U;
+    } else {
+      WorkListUnit &U = StackOthers.back();
+      StackOthers.pop_back();
+      return U;
+    }
+  }
+};
+
+std::unique_ptr<WorkList> WorkList::makeUnexploredFirst() {
+  return llvm::make_unique<UnexploredFirstStack>();
+}
+
 
//===----------------------------------------------------------------------===//
 // Core analysis engine.
 
//===----------------------------------------------------------------------===//
@@ -140,6 +202,8 @@ static std::unique_ptr<WorkList> generat
       return WorkList::makeBFS();
     case AnalyzerOptions::ExplorationStrategyKind::BFSBlockDFSContents:
       return WorkList::makeBFSBlockDFSContents();
+    case AnalyzerOptions::ExplorationStrategyKind::UnexploredFirst:
+      return WorkList::makeUnexploredFirst();
     default:
       llvm_unreachable("Unexpected case");
   }

Added: cfe/trunk/test/Analysis/exploration_order/prefer_unexplored.cc
URL: 
http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/exploration_order/prefer_unexplored.cc?rev=324956&view=auto
==============================================================================
--- cfe/trunk/test/Analysis/exploration_order/prefer_unexplored.cc (added)
+++ cfe/trunk/test/Analysis/exploration_order/prefer_unexplored.cc Mon Feb 12 
14:39:57 2018
@@ -0,0 +1,39 @@
+// RUN: %clang_analyze_cc1 -w -analyzer-checker=core -analyzer-config 
exploration_strategy=unexplored_first -analyzer-output=text -verify %s | 
FileCheck %s
+
+extern int coin();
+
+int foo() {
+    int *x = 0; // expected-note {{'x' initialized to a null pointer value}}
+    while (coin()) { // expected-note{{Loop condition is true}}
+        if (coin())  // expected-note {{Taking true branch}}
+            return *x; // expected-warning{{Dereference of null pointer 
(loaded from variable 'x')}}
+                       // expected-note@-1{{Dereference of null pointer 
(loaded from variable 'x')}}
+    }
+    return 0;
+}
+
+void bar() {
+    while(coin()) // expected-note{{Loop condition is true}}
+        if (coin()) // expected-note {{Assuming the condition is true}}
+            foo(); // expected-note{{Calling 'foo'}}
+}
+
+int foo2() {
+    int *x = 0; // expected-note {{'x' initialized to a null pointer value}}
+    while (coin()) { // expected-note{{Loop condition is true}}
+        if (coin())  // expected-note {{Taking false branch}}
+            return false;
+        else
+            return *x; // expected-warning{{Dereference of null pointer 
(loaded from variable 'x')}}
+                       // expected-note@-1{{Dereference of null pointer 
(loaded from variable 'x')}}
+    }
+    return 0;
+}
+
+void bar2() {
+    while(coin()) // expected-note{{Loop condition is true}}
+        if (coin()) // expected-note {{Assuming the condition is false}}
+          return false;
+        else
+            foo(); // expected-note{{Calling 'foo'}}
+}


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

Reply via email to