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) {
#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;
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.
//===----------------------------------------------------------------------===//
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.
//===----------------------------------------------------------------------===//
return WorkList::makeBFS();
case AnalyzerOptions::ExplorationStrategyKind::BFSBlockDFSContents:
return WorkList::makeBFSBlockDFSContents();
+ case AnalyzerOptions::ExplorationStrategyKind::UnexploredFirst:
+ return WorkList::makeUnexploredFirst();
default:
llvm_unreachable("Unexpected case");
}
--- /dev/null
+// 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'}}
+}