summaryrefslogtreecommitdiffstats
path: root/clang/lib/StaticAnalyzer/Core
diff options
context:
space:
mode:
authorJordan Rose <jordan_rose@apple.com>2012-07-10 22:07:42 +0000
committerJordan Rose <jordan_rose@apple.com>2012-07-10 22:07:42 +0000
commit681cce9908500cad97cc3ce5c4a786e237399a9b (patch)
tree6ad486a4a557212a2b1f57dabaf2fb35ca76b63b /clang/lib/StaticAnalyzer/Core
parent868830f727accb3a886b446c341e5370a8799690 (diff)
downloadbcm5719-llvm-681cce9908500cad97cc3ce5c4a786e237399a9b.tar.gz
bcm5719-llvm-681cce9908500cad97cc3ce5c4a786e237399a9b.zip
[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. llvm-svn: 160019
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core')
-rw-r--r--clang/lib/StaticAnalyzer/Core/Calls.cpp19
-rw-r--r--clang/lib/StaticAnalyzer/Core/CheckerManager.cpp10
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp5
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngine.cpp49
-rw-r--r--clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp22
5 files changed, 70 insertions, 35 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/Calls.cpp b/clang/lib/StaticAnalyzer/Core/Calls.cpp
index 24c5ab12ab1..7b86d442765 100644
--- a/clang/lib/StaticAnalyzer/Core/Calls.cpp
+++ b/clang/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/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp b/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
index 39a36218267..d0d212130ac 100644
--- a/clang/lib/StaticAnalyzer/Core/CheckerManager.cpp
+++ b/clang/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/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp b/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
index aeb47a13164..51099126282 100644
--- a/clang/lib/StaticAnalyzer/Core/ExplodedGraph.cpp
+++ b/clang/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/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
index 63aa28fa0aa..a9387694eec 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp
+++ b/clang/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/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
index 6fb41930d35..bf55ceb5fd4 100644
--- a/clang/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp
+++ b/clang/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);
OpenPOWER on IntegriCloud