aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/clang/Analysis/ProgramPoint.h84
-rw-r--r--include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h7
-rw-r--r--lib/StaticAnalyzer/Checkers/MallocChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp3
-rw-r--r--lib/StaticAnalyzer/Core/Calls.cpp19
-rw-r--r--lib/StaticAnalyzer/Core/CheckerManager.cpp10
-rw-r--r--lib/StaticAnalyzer/Core/ExplodedGraph.cpp5
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngine.cpp49
-rw-r--r--lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp22
9 files changed, 150 insertions, 52 deletions
diff --git a/include/clang/Analysis/ProgramPoint.h b/include/clang/Analysis/ProgramPoint.h
index 57e5fc1028..4dcf92e7f2 100644
--- a/include/clang/Analysis/ProgramPoint.h
+++ b/include/clang/Analysis/ProgramPoint.h
@@ -55,17 +55,21 @@ public:
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 @@ protected:
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 @@ protected:
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 @@ public:
}
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 @@ public:
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 @@ public:
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 @@ public:
}
};
+/// 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:
diff --git a/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h b/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h
index 332addce16..0d830c3ce9 100644
--- a/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h
+++ b/include/clang/StaticAnalyzer/Core/PathSensitive/Calls.h
@@ -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 @@ public:
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
diff --git a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
index 41cd80e01e..8c2e5295ee 100644
--- a/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/MallocChecker.cpp
@@ -1535,6 +1535,9 @@ MallocChecker::MallocBugVisitor::VisitNode(const ExplodedNode *N,
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)) {
diff --git a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
index d0618d0ddd..32f7706bd9 100644
--- a/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
+++ b/lib/StaticAnalyzer/Checkers/RetainCountChecker.cpp
@@ -1928,7 +1928,8 @@ PathDiagnosticPiece *CFRefReportVisitor::VisitNode(const ExplodedNode *N,
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;
diff --git a/lib/StaticAnalyzer/Core/Calls.cpp b/lib/StaticAnalyzer/Core/Calls.cpp
index 24c5ab12ab..7b86d44276 100644
--- a/lib/StaticAnalyzer/Core/Calls.cpp
+++ b/lib/StaticAnalyzer/Core/Calls.cpp
@@ -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 @@ ProgramStateRef CallEvent::invalidateRegions(unsigned BlockCount,
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);
}
diff --git a/lib/StaticAnalyzer/Core/CheckerManager.cpp b/lib/StaticAnalyzer/Core/CheckerManager.cpp
index 39a3621826..d0d212130a 100644
--- a/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/lib/StaticAnalyzer/Core/CheckerManager.cpp
@@ -237,15 +237,7 @@ namespace {
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);
diff --git a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
index aeb47a1316..5109912628 100644
--- a/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
+++ b/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
@@ -71,6 +71,7 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
// (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 @@ bool ExplodedGraph::shouldCollect(const ExplodedNode *node) {
// 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.
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 63aa28fa0a..a9387694ee 100644
--- a/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp
@@ -984,6 +984,7 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
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 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
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 @@ bool ExprEngine::replayWithoutInlining(ExplodedNode *N,
// 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 @@ struct DOTGraphTraits<ExplodedNode*> :
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 @@ struct DOTGraphTraits<ExplodedNode*> :
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;";
diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 6fb41930d3..bf55ceb5fd 100644
--- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
@@ -346,11 +346,11 @@ static ProgramStateRef getInlineFailedState(ExplodedNode *&N,
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::evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
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);