]> granicus.if.org Git - clang/commitdiff
[StaticAnalyzer] Handle LoopExit CFGElement in the analyzer
authorPeter Szecsi <szepet95@gmail.com>
Mon, 21 Aug 2017 16:10:19 +0000 (16:10 +0000)
committerPeter Szecsi <szepet95@gmail.com>
Mon, 21 Aug 2017 16:10:19 +0000 (16:10 +0000)
This patch adds handling of the LoopExit CFGElements to the StaticAnalyzer.
This is reached by introducing a new ProgramPoint.
Tests will be added in a following commit.

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

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

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

index be5adfb29423c5563068f34e09f59614e1a2192e..94fef65a2a3aae2c946c673b8c3c58e6ad812ce4 100644 (file)
@@ -83,6 +83,7 @@ public:
               PostImplicitCallKind,
               MinImplicitCallKind = PreImplicitCallKind,
               MaxImplicitCallKind = PostImplicitCallKind,
+              LoopExitKind,
               EpsilonKind};
 
 private:
@@ -654,6 +655,29 @@ private:
   }
 };
 
+/// Represents a point when we exit a loop.
+/// When this ProgramPoint is encountered we can be sure that the symbolic
+/// execution of the corresponding LoopStmt is finished on the given path.
+/// Note: It is possible to encounter a LoopExit element when we haven't even
+/// encountered the loop itself. At the current state not all loop exits will
+/// result in a LoopExit program point.
+class LoopExit : public ProgramPoint {
+public:
+    LoopExit(const Stmt *LoopStmt, const LocationContext *LC)
+            : ProgramPoint(LoopStmt, nullptr, LoopExitKind, LC) {}
+
+    const Stmt *getLoopStmt() const {
+      return static_cast<const Stmt *>(getData1());
+    }
+
+private:
+    friend class ProgramPoint;
+    LoopExit() {}
+    static bool isKind(const ProgramPoint &Location) {
+      return Location.getKind() == LoopExitKind;
+    }
+};
+
 /// This is a meta program point, which should be skipped by all the diagnostic
 /// reasoning etc.
 class EpsilonPoint : public ProgramPoint {
index 067d70610868964fd253700e0c103d28e357f9ce..ecff5c6623d96cad6223134f188004f62cc71523 100644 (file)
@@ -196,6 +196,8 @@ public:
 
   void ProcessStmt(const CFGStmt S, ExplodedNode *Pred);
 
+  void ProcessLoopExit(const Stmt* S, ExplodedNode *Pred);
+
   void ProcessInitializer(const CFGInitializer I, ExplodedNode *Pred);
 
   void ProcessImplicitDtor(const CFGImplicitDtor D, ExplodedNode *Pred);
index 4e2866c56f0eed42e865dfd36522af66285fe420..e2e9ddf5048ebe2511ac4326fa237978a5cc28da 100644 (file)
@@ -274,7 +274,8 @@ void CoreEngine::dispatchWorkItem(ExplodedNode* Pred, ProgramPoint Loc,
       assert(Loc.getAs<PostStmt>() ||
              Loc.getAs<PostInitializer>() ||
              Loc.getAs<PostImplicitCall>() ||
-             Loc.getAs<CallExitEnd>());
+             Loc.getAs<CallExitEnd>() ||
+             Loc.getAs<LoopExit>());
       HandlePostStmt(WU.getBlock(), WU.getIndex(), Pred);
       break;
   }
@@ -566,7 +567,8 @@ void CoreEngine::enqueueStmtNode(ExplodedNode *N,
 
   // Do not create extra nodes. Move to the next CFG element.
   if (N->getLocation().getAs<PostInitializer>() ||
-      N->getLocation().getAs<PostImplicitCall>()) {
+      N->getLocation().getAs<PostImplicitCall>()||
+      N->getLocation().getAs<LoopExit>()) {
     WList->enqueue(N, Block, Idx+1);
     return;
   }
index 547978ad43c7d8d6ad0978314ab30f1b7c8ed056..43b067b6d2bede41bd3778ad38bef247350f3a11 100644 (file)
@@ -364,8 +364,10 @@ void ExprEngine::processCFGElement(const CFGElement E, ExplodedNode *Pred,
     case CFGElement::TemporaryDtor:
       ProcessImplicitDtor(E.castAs<CFGImplicitDtor>(), Pred);
       return;
-    case CFGElement::LifetimeEnds:
     case CFGElement::LoopExit:
+      ProcessLoopExit(E.castAs<CFGLoopExit>().getLoopStmt(), Pred);
+      return;
+    case CFGElement::LifetimeEnds:
       return;
   }
 }
@@ -510,6 +512,21 @@ void ExprEngine::ProcessStmt(const CFGStmt S,
   Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
 }
 
+void ExprEngine::ProcessLoopExit(const Stmt* S, ExplodedNode *Pred) {
+  PrettyStackTraceLoc CrashInfo(getContext().getSourceManager(),
+                                S->getLocStart(),
+                                "Error evaluating end of the loop");
+  ExplodedNodeSet Dst;
+  Dst.Add(Pred);
+  NodeBuilder Bldr(Pred, Dst, *currBldrCtx);
+
+  LoopExit PP(S, Pred->getLocationContext());
+  Bldr.generateNode(PP, Pred->getState(), Pred);
+
+  // Enqueue the new nodes onto the work list.
+  Engine.enqueue(Dst, currBldrCtx->getBlock(), currStmtIdx);
+}
+
 void ExprEngine::ProcessInitializer(const CFGInitializer Init,
                                     ExplodedNode *Pred) {
   const CXXCtorInitializer *BMI = Init.getInitializer();
@@ -2689,6 +2706,12 @@ struct DOTGraphTraits<ExplodedNode*> :
         Out << "Epsilon Point";
         break;
 
+      case ProgramPoint::LoopExitKind: {
+        LoopExit LE = Loc.castAs<LoopExit>();
+        Out << "LoopExit: " << LE.getLoopStmt()->getStmtClassName();
+        break;
+      }
+
       case ProgramPoint::PreImplicitCallKind: {
         ImplicitCallPoint PC = Loc.castAs<ImplicitCallPoint>();
         Out << "PreCall: ";