forked from OSchip/llvm-project
[analyzer] Add generic preCall and postCall checks.
llvm-svn: 159562
This commit is contained in:
parent
f3c12ac3b1
commit
afe7c2c2bf
|
@ -150,6 +150,36 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
class PreCall {
|
||||
template <typename CHECKER>
|
||||
static void _checkCall(void *checker, const CallEvent &msg,
|
||||
CheckerContext &C) {
|
||||
((const CHECKER *)checker)->checkPreCall(msg, C);
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename CHECKER>
|
||||
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
||||
mgr._registerForPreCall(
|
||||
CheckerManager::CheckCallFunc(checker, _checkCall<CHECKER>));
|
||||
}
|
||||
};
|
||||
|
||||
class PostCall {
|
||||
template <typename CHECKER>
|
||||
static void _checkCall(void *checker, const CallEvent &msg,
|
||||
CheckerContext &C) {
|
||||
((const CHECKER *)checker)->checkPostCall(msg, C);
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename CHECKER>
|
||||
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
||||
mgr._registerForPostCall(
|
||||
CheckerManager::CheckCallFunc(checker, _checkCall<CHECKER>));
|
||||
}
|
||||
};
|
||||
|
||||
class Location {
|
||||
template <typename CHECKER>
|
||||
static void _checkLocation(void *checker,
|
||||
|
@ -372,16 +402,14 @@ template <typename CHECK1, typename CHECK2=check::_VoidCheck,
|
|||
typename CHECK11=check::_VoidCheck,typename CHECK12=check::_VoidCheck,
|
||||
typename CHECK13=check::_VoidCheck,typename CHECK14=check::_VoidCheck,
|
||||
typename CHECK15=check::_VoidCheck,typename CHECK16=check::_VoidCheck,
|
||||
typename CHECK17=check::_VoidCheck,typename CHECK18=check::_VoidCheck>
|
||||
typename CHECK17=check::_VoidCheck,typename CHECK18=check::_VoidCheck,
|
||||
typename CHECK19=check::_VoidCheck,typename CHECK20=check::_VoidCheck,
|
||||
typename CHECK21=check::_VoidCheck,typename CHECK22=check::_VoidCheck,
|
||||
typename CHECK23=check::_VoidCheck,typename CHECK24=check::_VoidCheck>
|
||||
class Checker;
|
||||
|
||||
template <>
|
||||
class Checker<check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
|
||||
check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
|
||||
check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
|
||||
check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
|
||||
check::_VoidCheck, check::_VoidCheck, check::_VoidCheck,
|
||||
check::_VoidCheck, check::_VoidCheck, check::_VoidCheck>
|
||||
class Checker<check::_VoidCheck>
|
||||
: public CheckerBase
|
||||
{
|
||||
virtual void anchor();
|
||||
|
@ -393,19 +421,22 @@ template <typename CHECK1, typename CHECK2, typename CHECK3, typename CHECK4,
|
|||
typename CHECK5, typename CHECK6, typename CHECK7, typename CHECK8,
|
||||
typename CHECK9, typename CHECK10,typename CHECK11,typename CHECK12,
|
||||
typename CHECK13,typename CHECK14,typename CHECK15,typename CHECK16,
|
||||
typename CHECK17,typename CHECK18>
|
||||
typename CHECK17,typename CHECK18,typename CHECK19,typename CHECK20,
|
||||
typename CHECK21,typename CHECK22,typename CHECK23,typename CHECK24>
|
||||
class Checker
|
||||
: public CHECK1,
|
||||
public Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7, CHECK8,
|
||||
CHECK9, CHECK10,CHECK11,CHECK12,CHECK13,CHECK14,CHECK15,
|
||||
CHECK16,CHECK17,CHECK18> {
|
||||
public Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7,
|
||||
CHECK8, CHECK9, CHECK10,CHECK11,CHECK12,CHECK13,
|
||||
CHECK14,CHECK15,CHECK16,CHECK17,CHECK18,CHECK19,
|
||||
CHECK20,CHECK21,CHECK22,CHECK23,CHECK24> {
|
||||
public:
|
||||
template <typename CHECKER>
|
||||
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
||||
CHECK1::_register(checker, mgr);
|
||||
Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7, CHECK8,
|
||||
CHECK9, CHECK10,CHECK11,CHECK12,CHECK13,CHECK14,CHECK15,
|
||||
CHECK16,CHECK17,CHECK18>::_register(checker, mgr);
|
||||
Checker<CHECK2, CHECK3, CHECK4, CHECK5, CHECK6, CHECK7,
|
||||
CHECK8, CHECK9, CHECK10,CHECK11,CHECK12,CHECK13,
|
||||
CHECK14,CHECK15,CHECK16,CHECK17,CHECK18,CHECK19,
|
||||
CHECK20,CHECK21,CHECK22,CHECK23,CHECK24>::_register(checker, mgr);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -221,6 +221,23 @@ public:
|
|||
const ExplodedNodeSet &Src,
|
||||
const ObjCMethodCall &msg, ExprEngine &Eng);
|
||||
|
||||
/// \brief Run checkers for pre-visiting obj-c messages.
|
||||
void runCheckersForPreCall(ExplodedNodeSet &Dst, const ExplodedNodeSet &Src,
|
||||
const CallEvent &Call, ExprEngine &Eng) {
|
||||
runCheckersForCallEvent(/*isPreVisit=*/true, Dst, Src, Call, Eng);
|
||||
}
|
||||
|
||||
/// \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);
|
||||
}
|
||||
|
||||
/// \brief Run checkers for visiting obj-c messages.
|
||||
void runCheckersForCallEvent(bool isPreVisit, ExplodedNodeSet &Dst,
|
||||
const ExplodedNodeSet &Src,
|
||||
const CallEvent &Call, ExprEngine &Eng);
|
||||
|
||||
/// \brief Run checkers for load/store of a location.
|
||||
void runCheckersForLocation(ExplodedNodeSet &Dst,
|
||||
const ExplodedNodeSet &Src,
|
||||
|
@ -339,6 +356,9 @@ public:
|
|||
|
||||
typedef CheckerFn<void (const ObjCMethodCall &, CheckerContext &)>
|
||||
CheckObjCMessageFunc;
|
||||
|
||||
typedef CheckerFn<void (const CallEvent &, CheckerContext &)>
|
||||
CheckCallFunc;
|
||||
|
||||
typedef CheckerFn<void (const SVal &location, bool isLoad,
|
||||
const Stmt *S,
|
||||
|
@ -397,6 +417,9 @@ public:
|
|||
void _registerForPreObjCMessage(CheckObjCMessageFunc checkfn);
|
||||
void _registerForPostObjCMessage(CheckObjCMessageFunc checkfn);
|
||||
|
||||
void _registerForPreCall(CheckCallFunc checkfn);
|
||||
void _registerForPostCall(CheckCallFunc checkfn);
|
||||
|
||||
void _registerForLocation(CheckLocationFunc checkfn);
|
||||
|
||||
void _registerForBind(CheckBindFunc checkfn);
|
||||
|
@ -518,6 +541,9 @@ private:
|
|||
std::vector<CheckObjCMessageFunc> PreObjCMessageCheckers;
|
||||
std::vector<CheckObjCMessageFunc> PostObjCMessageCheckers;
|
||||
|
||||
std::vector<CheckCallFunc> PreCallCheckers;
|
||||
std::vector<CheckCallFunc> PostCallCheckers;
|
||||
|
||||
std::vector<CheckLocationFunc> LocationCheckers;
|
||||
|
||||
std::vector<CheckBindFunc> BindCheckers;
|
||||
|
|
|
@ -37,6 +37,8 @@ class CheckerDocumentation : public Checker< check::PreStmt<DeclStmt>,
|
|||
check::PostStmt<CallExpr>,
|
||||
check::PreObjCMessage,
|
||||
check::PostObjCMessage,
|
||||
check::PreCall,
|
||||
check::PostCall,
|
||||
check::BranchCondition,
|
||||
check::Location,
|
||||
check::Bind,
|
||||
|
@ -72,15 +74,43 @@ public:
|
|||
/// which does not include the control flow statements such as IfStmt. The
|
||||
/// callback can be specialized to be called with any subclass of Stmt.
|
||||
///
|
||||
/// check::PostStmt<DeclStmt>
|
||||
/// check::PostStmt<CallExpr>
|
||||
void checkPostStmt(const CallExpr *DS, CheckerContext &C) const;
|
||||
|
||||
/// \brief Pre-visit the Objective C messages.
|
||||
/// \brief Pre-visit the Objective C message.
|
||||
///
|
||||
/// This will be called before the analyzer core processes the method call.
|
||||
/// This is called for any action which produces an Objective-C message send,
|
||||
/// including explicit message syntax and property access. See the subclasses
|
||||
/// of ObjCMethodCall for more details.
|
||||
///
|
||||
/// check::PreObjCMessage
|
||||
void checkPreObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const {}
|
||||
|
||||
/// \brief Post-visit the Objective C messages.
|
||||
/// \brief Post-visit the Objective C message.
|
||||
/// \sa checkPreObjCMessage()
|
||||
///
|
||||
/// check::PostObjCMessage
|
||||
void checkPostObjCMessage(const ObjCMethodCall &M, CheckerContext &C) const {}
|
||||
|
||||
/// \brief Pre-visit an abstract "call" event.
|
||||
///
|
||||
/// This is used for checkers that want to check arguments or attributed
|
||||
/// behavior for functions and methods no matter how they are being invoked.
|
||||
///
|
||||
/// Note that this includes ALL cross-body invocations, so if you want to
|
||||
/// limit your checks to, say, function calls, you can either test for that
|
||||
/// or fall back to the explicit callback (i.e. check::PreStmt).
|
||||
///
|
||||
/// check::PreCall
|
||||
void checkPreCall(const CallEvent &Call, CheckerContext &C) const {}
|
||||
|
||||
/// \brief Post-visit an abstract "call" event.
|
||||
/// \sa checkPreObjCMessage()
|
||||
///
|
||||
/// check::PostCall
|
||||
void checkPostCall(const CallEvent &Call, CheckerContext &C) const {}
|
||||
|
||||
/// \brief Pre-visit of the condition statement of a branch (such as IfStmt).
|
||||
void checkBranchCondition(const Stmt *Condition, CheckerContext &Ctx) const {}
|
||||
|
||||
|
|
|
@ -25,6 +25,8 @@ bool CheckerManager::hasPathSensitiveCheckers() const {
|
|||
return !StmtCheckers.empty() ||
|
||||
!PreObjCMessageCheckers.empty() ||
|
||||
!PostObjCMessageCheckers.empty() ||
|
||||
!PreCallCheckers.empty() ||
|
||||
!PostCallCheckers.empty() ||
|
||||
!LocationCheckers.empty() ||
|
||||
!BindCheckers.empty() ||
|
||||
!EndAnalysisCheckers.empty() ||
|
||||
|
@ -216,6 +218,54 @@ void CheckerManager::runCheckersForObjCMessage(bool isPreVisit,
|
|||
expandGraphWithCheckers(C, Dst, Src);
|
||||
}
|
||||
|
||||
namespace {
|
||||
// FIXME: This has all the same signatures as CheckObjCMessageContext.
|
||||
// Is there a way we can merge the two?
|
||||
struct CheckCallContext {
|
||||
typedef std::vector<CheckerManager::CheckCallFunc> CheckersTy;
|
||||
bool IsPreVisit;
|
||||
const CheckersTy &Checkers;
|
||||
const CallEvent &Call;
|
||||
ExprEngine &Eng;
|
||||
|
||||
CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
|
||||
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) { }
|
||||
|
||||
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);
|
||||
CheckerContext C(Bldr, Eng, Pred, L);
|
||||
|
||||
checkFn(Call, C);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// \brief Run checkers for visiting an abstract call event.
|
||||
void CheckerManager::runCheckersForCallEvent(bool isPreVisit,
|
||||
ExplodedNodeSet &Dst,
|
||||
const ExplodedNodeSet &Src,
|
||||
const CallEvent &Call,
|
||||
ExprEngine &Eng) {
|
||||
CheckCallContext C(isPreVisit,
|
||||
isPreVisit ? PreCallCheckers
|
||||
: PostCallCheckers,
|
||||
Call, Eng);
|
||||
expandGraphWithCheckers(C, Dst, Src);
|
||||
}
|
||||
|
||||
namespace {
|
||||
struct CheckLocationContext {
|
||||
typedef std::vector<CheckerManager::CheckLocationFunc> CheckersTy;
|
||||
|
@ -584,6 +634,13 @@ void CheckerManager::_registerForPostObjCMessage(CheckObjCMessageFunc checkfn) {
|
|||
PostObjCMessageCheckers.push_back(checkfn);
|
||||
}
|
||||
|
||||
void CheckerManager::_registerForPreCall(CheckCallFunc checkfn) {
|
||||
PreCallCheckers.push_back(checkfn);
|
||||
}
|
||||
void CheckerManager::_registerForPostCall(CheckCallFunc checkfn) {
|
||||
PostCallCheckers.push_back(checkfn);
|
||||
}
|
||||
|
||||
void CheckerManager::_registerForLocation(CheckLocationFunc checkfn) {
|
||||
LocationCheckers.push_back(checkfn);
|
||||
}
|
||||
|
|
|
@ -55,14 +55,19 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE,
|
|||
|
||||
ExplodedNodeSet DstPreVisit;
|
||||
getCheckerManager().runCheckersForPreStmt(DstPreVisit, Pred, CE, *this);
|
||||
ExplodedNodeSet DstPreCall;
|
||||
getCheckerManager().runCheckersForPreCall(DstPreCall, DstPreVisit,
|
||||
Call, *this);
|
||||
|
||||
ExplodedNodeSet DstInvalidated;
|
||||
for (ExplodedNodeSet::iterator I = DstPreVisit.begin(), E = DstPreVisit.end();
|
||||
for (ExplodedNodeSet::iterator I = DstPreCall.begin(), E = DstPreCall.end();
|
||||
I != E; ++I)
|
||||
defaultEvalCall(DstInvalidated, *I, Call);
|
||||
|
||||
getCheckerManager().runCheckersForPostStmt(destNodes, DstInvalidated,
|
||||
CE, *this);
|
||||
ExplodedNodeSet DstPostCall;
|
||||
getCheckerManager().runCheckersForPostCall(DstPostCall, DstInvalidated,
|
||||
Call, *this);
|
||||
getCheckerManager().runCheckersForPostStmt(destNodes, DstPostCall, CE, *this);
|
||||
}
|
||||
|
||||
void ExprEngine::VisitCXXDestructor(const CXXDestructorDecl *DD,
|
||||
|
|
|
@ -359,7 +359,20 @@ void ExprEngine::VisitCallExpr(const CallExpr *CE, ExplodedNode *Pred,
|
|||
|
||||
void ExprEngine::evalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
|
||||
const SimpleCall &Call) {
|
||||
getCheckerManager().runCheckersForEvalCall(Dst, Pred, Call, *this);
|
||||
// Run any pre-call checks using the generic call interface.
|
||||
ExplodedNodeSet dstPreVisit;
|
||||
getCheckerManager().runCheckersForPreCall(dstPreVisit, Pred, Call, *this);
|
||||
|
||||
// Actually evaluate the function call. We try each of the checkers
|
||||
// to see if the can evaluate the function call, and get a callback at
|
||||
// defaultEvalCall if all of them fail.
|
||||
ExplodedNodeSet dstCallEvaluated;
|
||||
getCheckerManager().runCheckersForEvalCall(dstCallEvaluated, dstPreVisit,
|
||||
Call, *this);
|
||||
|
||||
// Finally, run any post-call checks.
|
||||
getCheckerManager().runCheckersForPostCall(Dst, dstCallEvaluated,
|
||||
Call, *this);
|
||||
}
|
||||
|
||||
void ExprEngine::defaultEvalCall(ExplodedNodeSet &Dst, ExplodedNode *Pred,
|
||||
|
|
|
@ -146,15 +146,18 @@ void ExprEngine::VisitObjCMessage(const ObjCMethodCall &msg,
|
|||
|
||||
// Handle the previsits checks.
|
||||
ExplodedNodeSet dstPrevisit;
|
||||
getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred,
|
||||
getCheckerManager().runCheckersForPreObjCMessage(dstPrevisit, Pred,
|
||||
msg, *this);
|
||||
|
||||
ExplodedNodeSet dstGenericPrevisit;
|
||||
getCheckerManager().runCheckersForPreCall(dstGenericPrevisit, dstPrevisit,
|
||||
msg, *this);
|
||||
|
||||
// Proceed with evaluate the message expression.
|
||||
ExplodedNodeSet dstEval;
|
||||
StmtNodeBuilder Bldr(dstPrevisit, dstEval, *currentBuilderContext);
|
||||
StmtNodeBuilder Bldr(dstGenericPrevisit, dstEval, *currentBuilderContext);
|
||||
|
||||
for (ExplodedNodeSet::iterator DI = dstPrevisit.begin(),
|
||||
DE = dstPrevisit.end(); DI != DE; ++DI) {
|
||||
for (ExplodedNodeSet::iterator DI = dstGenericPrevisit.begin(),
|
||||
DE = dstGenericPrevisit.end(); DI != DE; ++DI) {
|
||||
|
||||
ExplodedNode *Pred = *DI;
|
||||
bool RaisesException = false;
|
||||
|
@ -235,9 +238,13 @@ void ExprEngine::VisitObjCMessage(const ObjCMethodCall &msg,
|
|||
}
|
||||
}
|
||||
|
||||
ExplodedNodeSet dstPostvisit;
|
||||
getCheckerManager().runCheckersForPostCall(dstPostvisit, dstEval, msg, *this);
|
||||
|
||||
// Finally, perform the post-condition check of the ObjCMessageExpr and store
|
||||
// the created nodes in 'Dst'.
|
||||
getCheckerManager().runCheckersForPostObjCMessage(Dst, dstEval, msg, *this);
|
||||
getCheckerManager().runCheckersForPostObjCMessage(Dst, dstPostvisit,
|
||||
msg, *this);
|
||||
}
|
||||
|
||||
void ExprEngine::evalObjCMessage(StmtNodeBuilder &Bldr,
|
||||
|
@ -280,7 +287,7 @@ void ExprEngine::evalObjCMessage(StmtNodeBuilder &Bldr,
|
|||
state = msg.invalidateRegions(BlockCount, state);
|
||||
|
||||
// And create the new node.
|
||||
Bldr.generateNode(msg.getOriginExpr(), Pred, state, GenSink);
|
||||
Bldr.generateNode(currentStmt, Pred, state, GenSink);
|
||||
assert(Bldr.hasGeneratedNodes());
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue