[cfe-commits] r160019 - in /cfe/trunk: include/clang/Analysis/ProgramPoint.h include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h lib/StaticAnalyzer/Checkers/MallocChecker.cpp lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp lib/StaticAnalyzer/Core/Calls.cpp lib/StaticAnalyzer/Core/CheckerManager.cpp lib/StaticAnalyzer/Core/ExplodedGraph.cpp lib/StaticAnalyzer/Core/ExprEngine.cpp lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp

Jordan Rose jordan_rose at apple.com
Tue Jul 10 15:07:43 PDT 2012


Author: jrose
Date: Tue Jul 10 17:07:42 2012
New Revision: 160019

URL: http://llvm.org/viewvc/llvm-project?rev=160019&view=rev
Log:
[analyzer] Add new PreImplicitCall and PostImplicitCall ProgramPoints.

These are currently unused, but are intended to be used in lieu of PreStmt
and PostStmt when the call is implicit (e.g. an automatic object destructor).

This also modifies the Data1 field of ProgramPoints to allow storing any
pointer-sized value, as opposed to only aligned pointers. This is necessary
to store SourceLocations.

There is currently no BugReporter support for these; they should be skipped
over in any diagnostic output.

This commit also tags checkers that currently rely on function calls only
occurring at StmtPoints.

Modified:
    cfe/trunk/include/clang/Analysis/ProgramPoint.h
    cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h
    cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
    cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
    cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp

Modified: cfe/trunk/include/clang/Analysis/ProgramPoint.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/ProgramPoint.h?rev=160019&r1=160018&r2=160019&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/ProgramPoint.h (original)
+++ cfe/trunk/include/clang/Analysis/ProgramPoint.h Tue Jul 10 17:07:42 2012
@@ -55,17 +55,21 @@
               CallExitEndKind,
               MinPostStmtKind = PostStmtKind,
               MaxPostStmtKind = CallExitEndKind,
+              PreImplicitCallKind,
+              PostImplicitCallKind,
+              MinImplicitCallKind = PreImplicitCallKind,
+              MaxImplicitCallKind = PostImplicitCallKind,
               EpsilonKind};
 
 private:
-  llvm::PointerIntPair<const void *, 2, unsigned> Data1;
+  const void *Data1;
   llvm::PointerIntPair<const void *, 2, unsigned> Data2;
 
   // The LocationContext could be NULL to allow ProgramPoint to be used in
   // context insensitive analysis.
   llvm::PointerIntPair<const LocationContext *, 2, unsigned> L;
 
-  const ProgramPointTag *Tag;
+  llvm::PointerIntPair<const ProgramPointTag *, 2, unsigned> Tag;
 
   ProgramPoint();
   
@@ -74,10 +78,10 @@
                Kind k,
                const LocationContext *l,
                const ProgramPointTag *tag = 0)
-    : Data1(P, ((unsigned) k) & 0x3),
-      Data2(0, (((unsigned) k) >> 2) & 0x3),
-      L(l, (((unsigned) k) >> 4) & 0x3),
-      Tag(tag) {
+    : Data1(P),
+      Data2(0, (((unsigned) k) >> 0) & 0x3),
+      L(l, (((unsigned) k) >> 2) & 0x3),
+      Tag(tag, (((unsigned) k) >> 4) & 0x3) {
         assert(getKind() == k);
         assert(getLocationContext() == l);
         assert(getData1() == P);
@@ -88,13 +92,13 @@
                Kind k,
                const LocationContext *l,
                const ProgramPointTag *tag = 0)
-    : Data1(P1, ((unsigned) k) & 0x3),
-      Data2(P2, (((unsigned) k) >> 2) & 0x3),
-      L(l, (((unsigned) k) >> 4) & 0x3),
-      Tag(tag) {}
+    : Data1(P1),
+      Data2(P2, (((unsigned) k) >> 0) & 0x3),
+      L(l, (((unsigned) k) >> 2) & 0x3),
+      Tag(tag, (((unsigned) k) >> 4) & 0x3) {}
 
 protected:
-  const void *getData1() const { return Data1.getPointer(); }
+  const void *getData1() const { return Data1; }
   const void *getData2() const { return Data2.getPointer(); }
   void setData2(const void *d) { Data2.setPointer(d); }
 
@@ -107,11 +111,11 @@
   }
 
   Kind getKind() const {
-    unsigned x = L.getInt();
+    unsigned x = Tag.getInt();
     x <<= 2;
-    x |= Data2.getInt();
+    x |= L.getInt();
     x <<= 2;
-    x |= Data1.getInt();
+    x |= Data2.getInt();
     return (Kind) x;
   }
 
@@ -123,7 +127,7 @@
             K == PreStmtPurgeDeadSymbolsKind);
   }
 
-  const ProgramPointTag *getTag() const { return Tag; }
+  const ProgramPointTag *getTag() const { return Tag.getPointer(); }
 
   const LocationContext *getLocationContext() const {
     return L.getPointer();
@@ -157,7 +161,7 @@
     ID.AddPointer(getData1());
     ID.AddPointer(getData2());
     ID.AddPointer(getLocationContext());
-    ID.AddPointer(Tag);
+    ID.AddPointer(getTag());
   }
 
   static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K,
@@ -408,6 +412,54 @@
   }
 };
 
+/// Represents an implicit call event.
+///
+/// The nearest statement is provided for diagnostic purposes.
+class ImplicitCallPoint : public ProgramPoint {
+public:
+  ImplicitCallPoint(const Decl *D, SourceLocation Loc, Kind K,
+                    const LocationContext *L, const ProgramPointTag *Tag)
+    : ProgramPoint(Loc.getPtrEncoding(), D, K, L, Tag) {}
+
+  const Decl *getDecl() const { return static_cast<const Decl *>(getData2()); }
+  SourceLocation getLocation() const {
+    return SourceLocation::getFromPtrEncoding(getData1());
+  }
+
+  static bool classof(const ProgramPoint *Location) {
+    return Location->getKind() >= MinImplicitCallKind &&
+           Location->getKind() <= MaxImplicitCallKind;
+  }
+};
+
+/// Represents a program point just before an implicit call event.
+///
+/// Explicit calls will appear as PreStmt program points.
+class PreImplicitCall : public ImplicitCallPoint {
+public:
+  PreImplicitCall(const Decl *D, SourceLocation Loc,
+                  const LocationContext *L, const ProgramPointTag *Tag = 0)
+    : ImplicitCallPoint(D, Loc, PreImplicitCallKind, L, Tag) {}
+
+  static bool classof(const ProgramPoint *Location) {
+    return Location->getKind() == PreImplicitCallKind;
+  }
+};
+
+/// Represents a program point just after an implicit call event.
+///
+/// Explicit calls will appear as PostStmt program points.
+class PostImplicitCall : public ImplicitCallPoint {
+public:
+  PostImplicitCall(const Decl *D, SourceLocation Loc,
+                   const LocationContext *L, const ProgramPointTag *Tag = 0)
+    : ImplicitCallPoint(D, Loc, PostImplicitCallKind, L, Tag) {}
+
+  static bool classof(const ProgramPoint *Location) {
+    return Location->getKind() == PostImplicitCallKind;
+  }
+};
+
 /// Represents a point when we begin processing an inlined call.
 class CallEnter : public StmtPoint {
 public:

Modified: cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h?rev=160019&r1=160018&r2=160019&view=diff
==============================================================================
--- cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h (original)
+++ cfe/trunk/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h Tue Jul 10 17:07:42 2012
@@ -24,6 +24,9 @@
 #include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
 
 namespace clang {
+class ProgramPoint;
+class ProgramPointTag;
+
 namespace ento {
 
 enum CallEventKind {
@@ -155,6 +158,10 @@
     return hasNonZeroCallbackArg();
   }
 
+  /// \brief Returns an appropriate ProgramPoint for this call.
+  ProgramPoint getProgramPoint(bool IsPreVisit,
+                               const ProgramPointTag *Tag = 0) const;
+
   /// \brief Returns a new state with all argument regions invalidated.
   ///
   /// This accepts an alternate state in case some processing has already

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp?rev=160019&r1=160018&r2=160019&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/MallocChecker.cpp Tue Jul 10 17:07:42 2012
@@ -1535,6 +1535,9 @@
   if (!S)
     return 0;
 
+  // FIXME: We will eventually need to handle non-statement-based events
+  // (__attribute__((cleanup))).
+
   // Find out if this is an interesting point and what is the kind.
   if (Mode == Normal) {
     if (isAllocated(RS, RSPrev, S)) {

Modified: cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp?rev=160019&r1=160018&r2=160019&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp Tue Jul 10 17:07:42 2012
@@ -1928,7 +1928,8 @@
                                                    const ExplodedNode *PrevN,
                                                    BugReporterContext &BRC,
                                                    BugReport &BR) {
-
+  // FIXME: We will eventually need to handle non-statement-based events
+  // (__attribute__((cleanup))).
   if (!isa<StmtPoint>(N->getLocation()))
     return NULL;
 

Modified: cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp?rev=160019&r1=160018&r2=160019&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/Calls.cpp Tue Jul 10 17:07:42 2012
@@ -14,6 +14,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "clang/StaticAnalyzer/Core/PathSensitive/Calls.h"
+#include "clang/Analysis/ProgramPoint.h"
 #include "llvm/ADT/SmallSet.h"
 #include "llvm/ADT/StringExtras.h"
 
@@ -195,6 +196,24 @@
                                    BlockCount, LCtx, /*Symbols=*/0, this);
 }
 
+ProgramPoint CallEvent::getProgramPoint(bool IsPreVisit,
+                                        const ProgramPointTag *Tag) const {
+  if (const Expr *E = getOriginExpr()) {
+    if (IsPreVisit)
+      return PreStmt(E, LCtx, Tag);
+    return PostStmt(E, LCtx, Tag);
+  }
+
+  const Decl *D = getDecl();
+  assert(D && "Cannot get a program point without a statement or decl");  
+
+  SourceLocation Loc = getSourceRange().getBegin();
+  if (IsPreVisit)
+    return PreImplicitCall(D, Loc, LCtx, Tag);
+  return PostImplicitCall(D, Loc, LCtx, Tag);
+}
+
+
 bool CallEvent::mayBeInlined(const Stmt *S) {
   return isa<CallExpr>(S);
 }

Modified: cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp?rev=160019&r1=160018&r2=160019&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/CheckerManager.cpp Tue Jul 10 17:07:42 2012
@@ -237,15 +237,7 @@
 
     void runChecker(CheckerManager::CheckCallFunc checkFn,
                     NodeBuilder &Bldr, ExplodedNode *Pred) {
-      // FIXME: This will be wrong as soon as we handle any calls without
-      // associated statements.
-      ProgramPoint::Kind K = IsPreVisit ? ProgramPoint::PreStmtKind
-                                        : ProgramPoint::PostStmtKind;
-      assert(Call.getOriginExpr() && "Calls without stmts not yet handled");
-      const ProgramPoint &L =
-        ProgramPoint::getProgramPoint(Call.getOriginExpr(),
-                                      K, Pred->getLocationContext(),
-                                      checkFn.Checker);
+      const ProgramPoint &L = Call.getProgramPoint(IsPreVisit, checkFn.Checker);
       CheckerContext C(Bldr, Eng, Pred, L);
 
       checkFn(Call, C);

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExplodedGraph.cpp?rev=160019&r1=160018&r2=160019&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExplodedGraph.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExplodedGraph.cpp Tue Jul 10 17:07:42 2012
@@ -71,6 +71,7 @@
   // (8) The PostStmt is for a non-consumed Stmt or Expr.
   // (9) The successor is not a CallExpr StmtPoint (so that we would be able to
   //     find it when retrying a call with no inlining).
+  // FIXME: It may be safe to reclaim PreCall and PostCall nodes as well.
 
   // Conditions 1 and 2.
   if (node->pred_size() != 1 || node->succ_size() != 1)
@@ -86,9 +87,7 @@
 
   // Condition 3.
   ProgramPoint progPoint = node->getLocation();
-  if (!isa<PostStmt>(progPoint) ||
-      (isa<CallEnter>(progPoint) ||
-       isa<CallExitBegin>(progPoint) || isa<CallExitEnd>(progPoint)))
+  if (!isa<PostStmt>(progPoint))
     return false;
 
   // Condition 4.

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp?rev=160019&r1=160018&r2=160019&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngine.cpp Tue Jul 10 17:07:42 2012
@@ -984,6 +984,7 @@
   const StackFrameContext *CallerSF = CalleeSF->getParent()->getCurrentStackFrame();
   assert(CalleeSF && CallerSF);
   ExplodedNode *BeforeProcessingCall = 0;
+  const Stmt *CE = CalleeSF->getCallSite();
 
   // Find the first node before we started processing the call expression.
   while (N) {
@@ -995,11 +996,13 @@
     if (L.getLocationContext()->getCurrentStackFrame() != CallerSF)
       continue;
     // We reached the caller. Find the node right before we started
-    // processing the CallExpr.
+    // processing the call.
     if (L.isPurgeKind())
       continue;
+    if (isa<PreImplicitCall>(&L))
+      continue;
     if (const StmtPoint *SP = dyn_cast<StmtPoint>(&L))
-      if (SP->getStmt() == CalleeSF->getCallSite())
+      if (SP->getStmt() == CE)
         continue;
     break;
   }
@@ -1010,7 +1013,7 @@
   // TODO: Clean up the unneeded nodes.
 
   // Build an Epsilon node from which we will restart the analyzes.
-  const Stmt *CE = CalleeSF->getCallSite();
+  // Note that CE is permitted to be NULL!
   ProgramPoint NewNodeLoc =
                EpsilonPoint(BeforeProcessingCall->getLocationContext(), CE);
   // Add the special flag to GDM to signal retrying with no inlining.
@@ -1872,6 +1875,16 @@
     return "";
   }
 
+  static void printLocation(llvm::raw_ostream &Out, SourceLocation SLoc) {
+    if (SLoc.isFileID()) {
+      Out << "\\lline="
+        << GraphPrintSourceManager->getExpansionLineNumber(SLoc)
+        << " col="
+        << GraphPrintSourceManager->getExpansionColumnNumber(SLoc)
+        << "\\l";
+    }
+  }
+
   static std::string getNodeLabel(const ExplodedNode *N, void*){
 
     std::string sbuf;
@@ -1921,22 +1934,34 @@
         Out << "Epsilon Point";
         break;
 
+      case ProgramPoint::PreImplicitCallKind: {
+        ImplicitCallPoint *PC = cast<ImplicitCallPoint>(&Loc);
+        Out << "PreCall: ";
+
+        // FIXME: Get proper printing options.
+        PC->getDecl()->print(Out, LangOptions());
+        printLocation(Out, PC->getLocation());
+        break;
+      }
+
+      case ProgramPoint::PostImplicitCallKind: {
+        ImplicitCallPoint *PC = cast<ImplicitCallPoint>(&Loc);
+        Out << "PostCall: ";
+
+        // FIXME: Get proper printing options.
+        PC->getDecl()->print(Out, LangOptions());
+        printLocation(Out, PC->getLocation());
+        break;
+      }
+
       default: {
         if (StmtPoint *L = dyn_cast<StmtPoint>(&Loc)) {
           const Stmt *S = L->getStmt();
-          SourceLocation SLoc = S->getLocStart();
 
           Out << S->getStmtClassName() << ' ' << (void*) S << ' ';
           LangOptions LO; // FIXME.
           S->printPretty(Out, 0, PrintingPolicy(LO));
-
-          if (SLoc.isFileID()) {
-            Out << "\\lline="
-              << GraphPrintSourceManager->getExpansionLineNumber(SLoc)
-              << " col="
-              << GraphPrintSourceManager->getExpansionColumnNumber(SLoc)
-              << "\\l";
-          }
+          printLocation(Out, S->getLocStart());
 
           if (isa<PreStmt>(Loc))
             Out << "\\lPreStmt\\l;";

Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?rev=160019&r1=160018&r2=160019&view=diff
==============================================================================
--- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (original)
+++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Tue Jul 10 17:07:42 2012
@@ -346,11 +346,11 @@
   void *ReplayState = N->getState()->get<ReplayWithoutInlining>();
   if (!ReplayState)
     return 0;
-  const Stmt *ReplayCallE = reinterpret_cast<const Stmt *>(ReplayState);
-  if (CallE == ReplayCallE) {
-    return N->getState()->remove<ReplayWithoutInlining>();
-  }
-  return 0;
+
+  assert(ReplayState == (const void*)CallE && "Backtracked to the wrong call.");
+  (void)CallE;
+
+  return N->getState()->remove<ReplayWithoutInlining>();
 }
 
 void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred,
@@ -421,13 +421,13 @@
 void ExprEngine::defaultEvalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
                                  const CallEvent &Call) {
   // Try to inline the call.
-  ProgramStateRef state = 0;
+  // The origin expression here is just used as a kind of checksum;
+  // for CallEvents that do not have origin expressions, this should still be
+  // safe.
   const Expr *E = Call.getOriginExpr();
-  if (E) {
-    state = getInlineFailedState(Pred, E);
-    if (state == 0 && inlineCall(Dst, Call, Pred))
-      return;
-  }
+  ProgramStateRef state = getInlineFailedState(Pred, E);
+  if (state == 0 && inlineCall(Dst, Call, Pred))
+    return;
 
   // If we can't inline it, handle the return value and invalidate the regions.
   StmtNodeBuilder Bldr(Pred, Dst, *currentBuilderContext);





More information about the cfe-commits mailing list