void runCheckersForPostObjCMessage(ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
const ObjCMethodCall &msg,
- ExprEngine &Eng) {
- runCheckersForObjCMessage(/*isPreVisit=*/false, Dst, Src, msg, Eng);
+ ExprEngine &Eng,
+ bool wasInlined = false) {
+ runCheckersForObjCMessage(/*isPreVisit=*/false, Dst, Src, msg, Eng,
+ wasInlined);
}
/// \brief Run checkers for visiting obj-c messages.
void runCheckersForObjCMessage(bool isPreVisit,
ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
- const ObjCMethodCall &msg, ExprEngine &Eng);
+ const ObjCMethodCall &msg, ExprEngine &Eng,
+ bool wasInlined = false);
/// \brief Run checkers for pre-visiting obj-c messages.
void runCheckersForPreCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
/// \brief Run checkers for post-visiting obj-c messages.
void runCheckersForPostCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
- const CallEvent &Call, ExprEngine &Eng) {
- runCheckersForCallEvent(/*isPreVisit=*/false, Dst, Src, Call, Eng);
+ const CallEvent &Call, ExprEngine &Eng,
+ bool wasInlined = false) {
+ runCheckersForCallEvent(/*isPreVisit=*/false, Dst, Src, Call, Eng,
+ wasInlined);
}
/// \brief Run checkers for visiting obj-c messages.
void runCheckersForCallEvent(bool isPreVisit, ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
- const CallEvent &Call, ExprEngine &Eng);
+ const CallEvent &Call, ExprEngine &Eng,
+ bool wasInlined = false);
/// \brief Run checkers for load/store of a location.
void runCheckersForLocation(ExplodedNodeSet &Dst,
CallEventRef<T> cloneWithState(ProgramStateRef State) const {
return this->getPtr()->template cloneWithState<T>(State);
}
+
+ // Allow implicit conversions to a superclass type, since CallEventRef
+ // behaves like a pointer-to-const.
+ template <typename SuperT>
+ operator CallEventRef<SuperT> () const {
+ return this->getPtr();
+ }
};
/// \brief Represents an abstract call to a function or method along a
public:
CallEventManager(llvm::BumpPtrAllocator &alloc) : Alloc(alloc) {}
+
+ CallEventRef<>
+ getCaller(const StackFrameContext *CalleeCtx, ProgramStateRef State);
+
+
CallEventRef<SimpleCall>
getSimpleCall(const CallExpr *E, ProgramStateRef State,
const LocationContext *LCtx);
} // end namespace ento
} // end namespace clang
+namespace llvm {
+ // Support isa<>, cast<>, and dyn_cast<> for CallEventRef.
+ template<class T> struct simplify_type< clang::ento::CallEventRef<T> > {
+ typedef const T *SimpleType;
+
+ static SimpleType
+ getSimplifiedValue(const clang::ento::CallEventRef<T>& Val) {
+ return Val.getPtr();
+ }
+ };
+}
+
#endif
// something we can't reason about.
return create<FunctionCall>(CE, State, LCtx);
}
+
+
+CallEventRef<>
+CallEventManager::getCaller(const StackFrameContext *CalleeCtx,
+ ProgramStateRef State) {
+ const LocationContext *ParentCtx = CalleeCtx->getParent();
+ const LocationContext *CallerCtx = ParentCtx->getCurrentStackFrame();
+ assert(CallerCtx && "This should not be used for top-level stack frames");
+
+ const Stmt *CallSite = CalleeCtx->getCallSite();
+
+ if (CallSite) {
+ if (const CallExpr *CE = dyn_cast<CallExpr>(CallSite))
+ return getSimpleCall(CE, State, CallerCtx);
+
+ switch (CallSite->getStmtClass()) {
+ case Stmt::CXXConstructExprClass: {
+ SValBuilder &SVB = State->getStateManager().getSValBuilder();
+ const CXXMethodDecl *Ctor = cast<CXXMethodDecl>(CalleeCtx->getDecl());
+ Loc ThisPtr = SVB.getCXXThis(Ctor, CalleeCtx);
+ SVal ThisVal = State->getSVal(ThisPtr);
+
+ return getCXXConstructorCall(cast<CXXConstructExpr>(CallSite),
+ ThisVal.getAsRegion(), State, CallerCtx);
+ }
+ case Stmt::CXXNewExprClass:
+ return getCXXAllocatorCall(cast<CXXNewExpr>(CallSite), State, CallerCtx);
+ case Stmt::ObjCMessageExprClass:
+ return getObjCMethodCall(cast<ObjCMessageExpr>(CallSite),
+ State, CallerCtx);
+ default:
+ llvm_unreachable("This is not an inlineable statement.");
+ }
+ }
+
+ // Fall back to the CFG. The only thing we haven't handled yet is
+ // destructors, though this could change in the future.
+ const CFGBlock *B = CalleeCtx->getCallSiteBlock();
+ CFGElement E = (*B)[CalleeCtx->getIndex()];
+ assert(isa<CFGImplicitDtor>(E) && "All other CFG elements should have exprs");
+ assert(!isa<CFGTemporaryDtor>(E) && "We don't handle temporaries yet");
+
+ SValBuilder &SVB = State->getStateManager().getSValBuilder();
+ const CXXDestructorDecl *Dtor = cast<CXXDestructorDecl>(CalleeCtx->getDecl());
+ Loc ThisPtr = SVB.getCXXThis(Dtor, CalleeCtx);
+ SVal ThisVal = State->getSVal(ThisPtr);
+
+ const Stmt *Trigger;
+ if (const CFGAutomaticObjDtor *AutoDtor = dyn_cast<CFGAutomaticObjDtor>(&E))
+ Trigger = AutoDtor->getTriggerStmt();
+ else
+ Trigger = Dtor->getBody();
+
+ return getCXXDestructorCall(Dtor, Trigger, ThisVal.getAsRegion(),
+ State, CallerCtx);
+}
+
const CheckersTy &Checkers;
const Stmt *S;
ExprEngine &Eng;
- bool wasInlined;
+ bool WasInlined;
CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
CheckStmtContext(bool isPreVisit, const CheckersTy &checkers,
const Stmt *s, ExprEngine &eng, bool wasInlined = false)
: IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng),
- wasInlined(wasInlined) {}
+ WasInlined(wasInlined) {}
void runChecker(CheckerManager::CheckStmtFunc checkFn,
NodeBuilder &Bldr, ExplodedNode *Pred) {
ProgramPoint::PostStmtKind;
const ProgramPoint &L = ProgramPoint::getProgramPoint(S, K,
Pred->getLocationContext(), checkFn.Checker);
- CheckerContext C(Bldr, Eng, Pred, L, wasInlined);
+ CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
checkFn(S, C);
}
};
const ExplodedNodeSet &Src,
const Stmt *S,
ExprEngine &Eng,
- bool wasInlined) {
+ bool WasInlined) {
CheckStmtContext C(isPreVisit, *getCachedStmtCheckersFor(S, isPreVisit),
- S, Eng, wasInlined);
+ S, Eng, WasInlined);
expandGraphWithCheckers(C, Dst, Src);
}
namespace {
struct CheckObjCMessageContext {
typedef std::vector<CheckerManager::CheckObjCMessageFunc> CheckersTy;
- bool IsPreVisit;
+ bool IsPreVisit, WasInlined;
const CheckersTy &Checkers;
const ObjCMethodCall &Msg;
ExprEngine &Eng;
CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
CheckObjCMessageContext(bool isPreVisit, const CheckersTy &checkers,
- const ObjCMethodCall &msg, ExprEngine &eng)
- : IsPreVisit(isPreVisit), Checkers(checkers), Msg(msg), Eng(eng) { }
+ const ObjCMethodCall &msg, ExprEngine &eng,
+ bool wasInlined)
+ : IsPreVisit(isPreVisit), WasInlined(wasInlined), Checkers(checkers),
+ Msg(msg), Eng(eng) { }
void runChecker(CheckerManager::CheckObjCMessageFunc checkFn,
NodeBuilder &Bldr, ExplodedNode *Pred) {
const ProgramPoint &L = Msg.getProgramPoint(IsPreVisit,checkFn.Checker);
- CheckerContext C(Bldr, Eng, Pred, L);
+ CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
checkFn(*Msg.cloneWithState<ObjCMethodCall>(Pred->getState()), C);
}
ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
const ObjCMethodCall &msg,
- ExprEngine &Eng) {
+ ExprEngine &Eng,
+ bool WasInlined) {
CheckObjCMessageContext C(isPreVisit,
isPreVisit ? PreObjCMessageCheckers
: PostObjCMessageCheckers,
- msg, Eng);
+ msg, Eng, WasInlined);
expandGraphWithCheckers(C, Dst, Src);
}
// Is there a way we can merge the two?
struct CheckCallContext {
typedef std::vector<CheckerManager::CheckCallFunc> CheckersTy;
- bool IsPreVisit;
+ bool IsPreVisit, WasInlined;
const CheckersTy &Checkers;
const CallEvent &Call;
ExprEngine &Eng;
CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
CheckCallContext(bool isPreVisit, const CheckersTy &checkers,
- const CallEvent &call, ExprEngine &eng)
- : IsPreVisit(isPreVisit), Checkers(checkers), Call(call), Eng(eng) { }
+ const CallEvent &call, ExprEngine &eng,
+ bool wasInlined)
+ : IsPreVisit(isPreVisit), WasInlined(wasInlined), Checkers(checkers),
+ Call(call), Eng(eng) { }
void runChecker(CheckerManager::CheckCallFunc checkFn,
NodeBuilder &Bldr, ExplodedNode *Pred) {
const ProgramPoint &L = Call.getProgramPoint(IsPreVisit,checkFn.Checker);
- CheckerContext C(Bldr, Eng, Pred, L);
+ CheckerContext C(Bldr, Eng, Pred, L, WasInlined);
checkFn(*Call.cloneWithState(Pred->getState()), C);
}
ExplodedNodeSet &Dst,
const ExplodedNodeSet &Src,
const CallEvent &Call,
- ExprEngine &Eng) {
+ ExprEngine &Eng,
+ bool WasInlined) {
CheckCallContext C(isPreVisit,
isPreVisit ? PreCallCheckers
: PostCallCheckers,
- Call, Eng);
+ Call, Eng, WasInlined);
expandGraphWithCheckers(C, Dst, Src);
}
if (const ReturnStmt *RS = dyn_cast_or_null<ReturnStmt>(LastSt)) {
const LocationContext *LCtx = CEBNode->getLocationContext();
SVal V = state->getSVal(RS, LCtx);
- state = state->BindExpr(CE, calleeCtx->getParent(), V);
+ state = state->BindExpr(CE, callerCtx, V);
}
// Bind the constructed object value to CXXConstructExpr.
SVal ThisV = state->getSVal(This);
// Always bind the region to the CXXConstructExpr.
- state = state->BindExpr(CCE, calleeCtx->getParent(), ThisV);
+ state = state->BindExpr(CCE, callerCtx, ThisV);
}
}
// Step 5: Perform the post-condition check of the CallExpr and enqueue the
// result onto the work list.
// CEENode -> Dst -> WorkList
- ExplodedNodeSet Dst;
NodeBuilderContext Ctx(Engine, calleeCtx->getCallSiteBlock(), CEENode);
SaveAndRestore<const NodeBuilderContext*> NBCSave(currentBuilderContext,
&Ctx);
SaveAndRestore<unsigned> CBISave(currentStmtIdx, calleeCtx->getIndex());
- // FIXME: This needs to call PostCall.
- // FIXME: If/when we inline Objective-C messages, this also needs to call
- // PostObjCMessage.
- if (CE)
- getCheckerManager().runCheckersForPostStmt(Dst, CEENode, CE, *this, true);
- else
- Dst.Add(CEENode);
+ CallEventManager &CEMgr = getStateManager().getCallEventManager();
+ CallEventRef<> Call = CEMgr.getCaller(calleeCtx, CEEState);
+
+ ExplodedNodeSet DstPostCall;
+ getCheckerManager().runCheckersForPostCall(DstPostCall, CEENode, *Call,
+ *this, true);
+
+ ExplodedNodeSet Dst;
+ if (isa<ObjCMethodCall>(Call)) {
+ getCheckerManager().runCheckersForPostObjCMessage(Dst, DstPostCall,
+ cast<ObjCMethodCall>(*Call),
+ *this, true);
+ } else if (CE) {
+ getCheckerManager().runCheckersForPostStmt(Dst, DstPostCall, CE,
+ *this, true);
+ } else {
+ Dst.insert(DstPostCall);
+ }
// Enqueue the next element in the block.
for (ExplodedNodeSet::iterator PSI = Dst.begin(), PSE = Dst.end();