]> granicus.if.org Git - clang/commitdiff
[analyser] Stats checker: do not mark a node as exhausted if we will
authorAnna Zaks <ganna@apple.com>
Wed, 28 Mar 2012 17:05:50 +0000 (17:05 +0000)
committerAnna Zaks <ganna@apple.com>
Wed, 28 Mar 2012 17:05:50 +0000 (17:05 +0000)
retry without inlining.

(+ other minor cleanups)

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@153581 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/StaticAnalyzer/Core/PathSensitive/CoreEngine.h
include/clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h
include/clang/StaticAnalyzer/Core/PathSensitive/SubEngine.h
lib/StaticAnalyzer/Core/CoreEngine.cpp
lib/StaticAnalyzer/Core/ExprEngine.cpp

index a9a4ae423095b453c1525a76c2a02f842376ac15..85d92ff5f7bc6af6c4855edba7ad48ef528cd3c9 100644 (file)
@@ -42,6 +42,7 @@ class NodeBuilder;
 class CoreEngine {
   friend struct NodeBuilderContext;
   friend class NodeBuilder;
+  friend class ExprEngine;
   friend class CommonNodeBuilder;
   friend class IndirectGotoNodeBuilder;
   friend class SwitchNodeBuilder;
@@ -124,7 +125,8 @@ public:
   ///  steps.  Returns true if there is still simulation state on the worklist.
   bool ExecuteWorkList(const LocationContext *L, unsigned Steps,
                        ProgramStateRef InitState);
-  void ExecuteWorkListWithInitialState(const LocationContext *L,
+  /// Returns true if there is still simulation state on the worklist.
+  bool ExecuteWorkListWithInitialState(const LocationContext *L,
                                        unsigned Steps,
                                        ProgramStateRef InitState, 
                                        ExplodedNodeSet &Dst);
index 2c144109b222790c41a2586e478b556806b2b832..c0c6ef3fb4605db214a67c277f8d12ebf5a068f9 100644 (file)
@@ -95,17 +95,19 @@ public:
 
   ~ExprEngine();
 
-  void ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) {
-    Engine.ExecuteWorkList(L, Steps, 0);
+  /// Returns true if there is still simulation state on the worklist.
+  bool ExecuteWorkList(const LocationContext *L, unsigned Steps = 150000) {
+    return Engine.ExecuteWorkList(L, Steps, 0);
   }
 
   /// Execute the work list with an initial state. Nodes that reaches the exit
   /// of the function are added into the Dst set, which represent the exit
-  /// state of the function call.
-  void ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps,
+  /// state of the function call. Returns true if there is still simulation
+  /// state on the worklist.
+  bool ExecuteWorkListWithInitialState(const LocationContext *L, unsigned Steps,
                                        ProgramStateRef InitState, 
                                        ExplodedNodeSet &Dst) {
-    Engine.ExecuteWorkListWithInitialState(L, Steps, InitState, Dst);
+    return Engine.ExecuteWorkListWithInitialState(L, Steps, InitState, Dst);
   }
 
   /// getContext - Return the ASTContext associated with this analysis.
@@ -168,7 +170,8 @@ public:
                             ExplodedNode *Pred, ExplodedNodeSet &Dst);
 
   /// Called by CoreEngine when processing the entrance of a CFGBlock.
-  virtual void processCFGBlockEntrance(NodeBuilderWithSinks &nodeBuilder);
+  virtual void processCFGBlockEntrance(const BlockEdge &L,
+                                       NodeBuilderWithSinks &nodeBuilder);
   
   /// ProcessBranch - Called by CoreEngine.  Used to generate successor
   ///  nodes by processing the 'effects' of a branch condition.
index 0fb04b83250be6f1f417e39e5575ac41c4afbd90..baf57d49060c2ba65d516531fd5c3f92b75d0485 100644 (file)
@@ -59,7 +59,8 @@ public:
   /// Called by CoreEngine when it starts processing a CFGBlock.  The
   /// SubEngine is expected to populate dstNodes with new nodes representing
   /// updated analysis state, or generate no nodes at all if it doesn't.
-  virtual void processCFGBlockEntrance(NodeBuilderWithSinks &nodeBuilder) = 0;
+  virtual void processCFGBlockEntrance(const BlockEdge &L,
+                                       NodeBuilderWithSinks &nodeBuilder) = 0;
 
   /// Called by CoreEngine.  Used to generate successor
   ///  nodes by processing the 'effects' of a branch condition.
index f303c7af3a05586c3a0e8d753227095638a78ac2..de94f0f2ddc60a1ca70e1c12ca82846f00eece2a 100644 (file)
@@ -263,15 +263,16 @@ void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc,
   }
 }
 
-void CoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L, 
+bool CoreEngine::ExecuteWorkListWithInitialState(const LocationContext *L,
                                                  unsigned Steps,
                                                  ProgramStateRef InitState, 
                                                  ExplodedNodeSet &Dst) {
-  ExecuteWorkList(L, Steps, InitState);
+  bool DidNotFinish = ExecuteWorkList(L, Steps, InitState);
   for (ExplodedGraph::eop_iterator I = G->eop_begin(), 
                                    E = G->eop_end(); I != E; ++I) {
     Dst.Add(*I);
   }
+  return DidNotFinish;
 }
 
 void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
@@ -296,7 +297,7 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
   ExplodedNodeSet dstNodes;
   BlockEntrance BE(Blk, Pred->getLocationContext());
   NodeBuilderWithSinks nodeBuilder(Pred, dstNodes, BuilderCtx, BE);
-  SubEng.processCFGBlockEntrance(nodeBuilder);
+  SubEng.processCFGBlockEntrance(L, nodeBuilder);
 
   // Auto-generate a node.
   if (!nodeBuilder.hasGeneratedNodes()) {
@@ -305,13 +306,6 @@ void CoreEngine::HandleBlockEdge(const BlockEdge &L, ExplodedNode *Pred) {
 
   // Enqueue nodes onto the worklist.
   enqueue(dstNodes);
-
-  // Make sink nodes as exhausted.
-  const SmallVectorImpl<ExplodedNode*> &Sinks =  nodeBuilder.getSinks();
-  for (SmallVectorImpl<ExplodedNode*>::const_iterator
-         I =Sinks.begin(), E = Sinks.end(); I != E; ++I) {
-    blocksExhausted.push_back(std::make_pair(L, *I));
-  }
 }
 
 void CoreEngine::HandleBlockEntrance(const BlockEntrance &L,
index c47b7f4eb53e0ccd5d7153d52aa6d612fd47acff..a53ffd4eb5c45ffdccdf5694aa65b3b958b72ee1 100644 (file)
@@ -53,11 +53,6 @@ STATISTIC(NumMaxBlockCountReachedInInlined,
 STATISTIC(NumTimesRetriedWithoutInlining,
             "The # of times we re-evaluated a call without inlining");
 
-STATISTIC(NumNotNew,
-            "Cached out");
-STATISTIC(NumNull,
-            "Null node");
-
 //===----------------------------------------------------------------------===//
 // Utility functions.
 //===----------------------------------------------------------------------===//
@@ -1005,10 +1000,8 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
     break;
   }
 
-  if (!BeforeProcessingCall) {
-    NumNull++;
+  if (!BeforeProcessingCall)
     return false;
-  }
 
   // TODO: Clean up the unneeded nodes.
 
@@ -1024,10 +1017,11 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
   // Make the new node a successor of BeforeProcessingCall.
   bool IsNew = false;
   ExplodedNode *NewNode = G.getNode(NewNodeLoc, NewNodeState, false, &IsNew);
-  if (!IsNew) {
-    NumNotNew++;
-    return false;
-  }
+  // We cached out at this point. Caching out is common due to us backtracking
+  // from the inlined function, which might spawn several paths.
+  if (!IsNew)
+    return true;
+
   NewNode->addPredecessor(BeforeProcessingCall, G);
 
   // Add the new node to the work list.
@@ -1038,14 +1032,16 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
 }
 
 /// Block entrance.  (Update counters).
-void ExprEngine::processCFGBlockEntrance(NodeBuilderWithSinks &nodeBuilder) {
+void ExprEngine::processCFGBlockEntrance(const BlockEdge &L,
+                                         NodeBuilderWithSinks &nodeBuilder) {
   
   // FIXME: Refactor this into a checker.
   ExplodedNode *pred = nodeBuilder.getContext().getPred();
   
   if (nodeBuilder.getContext().getCurrentBlockCount() >= AMgr.getMaxVisit()) {
     static SimpleProgramPointTag tag("ExprEngine : Block count exceeded");
-    nodeBuilder.generateNode(pred->getState(), pred, &tag, true);
+    const ExplodedNode *Sink =
+                   nodeBuilder.generateNode(pred->getState(), pred, &tag, true);
 
     // Check if we stopped at the top level function or not.
     // Root node should have the location context of the top most function.
@@ -1057,10 +1053,14 @@ void ExprEngine::processCFGBlockEntrance(NodeBuilderWithSinks &nodeBuilder) {
       // no-inlining policy in the state and enqueuing the new work item on
       // the list. Replay should almost never fail. Use the stats to catch it
       // if it does.
-      if (!(AMgr.RetryExhausted && replayWithoutInlining(pred, CalleeLC)))
-        NumMaxBlockCountReachedInInlined++;
+      if ((AMgr.RetryExhausted && replayWithoutInlining(pred, CalleeLC)))
+        return;
+      NumMaxBlockCountReachedInInlined++;
     } else
       NumMaxBlockCountReached++;
+
+    // Make sink nodes as exhausted(for stats) only if retry failed.
+    Engine.blocksExhausted.push_back(std::make_pair(L, Sink));
   }
 }