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();
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);
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); }
}
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;
}
K == PreStmtPurgeDeadSymbolsKind);
}
- const ProgramPointTag *getTag() const { return Tag; }
+ const ProgramPointTag *getTag() const { return Tag.getPointer(); }
const LocationContext *getLocationContext() const {
return L.getPointer();
ID.AddPointer(getData1());
ID.AddPointer(getData2());
ID.AddPointer(getLocationContext());
- ID.AddPointer(Tag);
+ ID.AddPointer(getTag());
}
static ProgramPoint getProgramPoint(const Stmt *S, ProgramPoint::Kind K,
}
};
+/// 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:
#include "clang/StaticAnalyzer/Core/PathSensitive/SVals.h"
namespace clang {
+class ProgramPoint;
+class ProgramPointTag;
+
namespace ento {
enum CallEventKind {
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
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)) {
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;
//===----------------------------------------------------------------------===//
#include "clang/StaticAnalyzer/Core/PathSensitive/Calls.h"
+#include "clang/Analysis/ProgramPoint.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/StringExtras.h"
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);
}
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);
// (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)
// 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.
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) {
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;
}
// 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.
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;
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;";
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,
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);