forked from OSchip/llvm-project
[analyzer] Migrate ChrootChecker to CheckerV2.
llvm-svn: 126324
This commit is contained in:
parent
5d2144602f
commit
da02a25ae6
|
@ -23,6 +23,7 @@
|
|||
namespace clang {
|
||||
class Decl;
|
||||
class Stmt;
|
||||
class CallExpr;
|
||||
|
||||
namespace ento {
|
||||
class ExprEngine;
|
||||
|
@ -31,10 +32,17 @@ namespace ento {
|
|||
class CheckerContext;
|
||||
class ObjCMessage;
|
||||
class SVal;
|
||||
class ExplodedNode;
|
||||
class ExplodedNodeSet;
|
||||
class ExplodedGraph;
|
||||
class GRState;
|
||||
|
||||
class GraphExpander {
|
||||
public:
|
||||
virtual ~GraphExpander();
|
||||
virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) = 0;
|
||||
};
|
||||
|
||||
struct VoidCheckerFnParm {};
|
||||
template <typename P1=VoidCheckerFnParm, typename P2=VoidCheckerFnParm,
|
||||
typename P3=VoidCheckerFnParm, typename P4=VoidCheckerFnParm>
|
||||
|
@ -177,6 +185,12 @@ public:
|
|||
void runCheckersForEndAnalysis(ExplodedGraph &G, BugReporter &BR,
|
||||
ExprEngine &Eng);
|
||||
|
||||
/// \brief Run checkers for evaluating a call.
|
||||
void runCheckersForEvalCall(ExplodedNodeSet &Dst,
|
||||
const ExplodedNodeSet &Src,
|
||||
const CallExpr *CE, ExprEngine &Eng,
|
||||
GraphExpander *defaultEval = 0);
|
||||
|
||||
// FIXME: Temporary until checker running is moved completely into
|
||||
// CheckerManager.
|
||||
void registerCheckersToEngine(ExprEngine &eng);
|
||||
|
@ -220,6 +234,19 @@ public:
|
|||
|
||||
void _registerForEndAnalysis(CheckEndAnalysisFunc checkfn);
|
||||
|
||||
class EvalCallFunc {
|
||||
typedef bool (*Func)(void *, const CallExpr *, CheckerContext &);
|
||||
Func Fn;
|
||||
public:
|
||||
void *Checker;
|
||||
EvalCallFunc(void *checker, Func fn) : Fn(fn), Checker(checker) { }
|
||||
bool operator()(const CallExpr *CE, CheckerContext &C) {
|
||||
return Fn(Checker, CE, C);
|
||||
}
|
||||
};
|
||||
|
||||
void _registerForEvalCall(EvalCallFunc checkfn);
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Implementation details.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -287,6 +314,8 @@ private:
|
|||
std::vector<CheckLocationFunc> LocationCheckers;
|
||||
|
||||
std::vector<CheckEndAnalysisFunc> EndAnalysisCheckers;
|
||||
|
||||
std::vector<EvalCallFunc> EvalCallCheckers;
|
||||
};
|
||||
|
||||
} // end ento namespace
|
||||
|
|
|
@ -162,6 +162,24 @@ public:
|
|||
|
||||
} // end check namespace
|
||||
|
||||
namespace eval {
|
||||
|
||||
class Call {
|
||||
template <typename CHECKER>
|
||||
static bool _evalCall(void *checker, const CallExpr *CE, CheckerContext &C) {
|
||||
return ((const CHECKER *)checker)->evalCall(CE, C);
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename CHECKER>
|
||||
static void _register(CHECKER *checker, CheckerManager &mgr) {
|
||||
mgr._registerForEvalCall(
|
||||
CheckerManager::EvalCallFunc(checker, _evalCall<CHECKER>));
|
||||
}
|
||||
};
|
||||
|
||||
} // end eval namespace
|
||||
|
||||
template <typename CHECK1, typename CHECK2=check::_VoidCheck,
|
||||
typename CHECK3=check::_VoidCheck, typename CHECK4=check::_VoidCheck,
|
||||
typename CHECK5=check::_VoidCheck, typename CHECK6=check::_VoidCheck,
|
||||
|
|
|
@ -12,9 +12,10 @@
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ClangSACheckers.h"
|
||||
#include "clang/StaticAnalyzer/Core/CheckerV2.h"
|
||||
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
|
||||
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/CheckerVisitor.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/GRStateTrait.h"
|
||||
#include "clang/StaticAnalyzer/Core/PathSensitive/SymbolManager.h"
|
||||
|
@ -37,38 +38,30 @@ bool isRootChanged(intptr_t k) { return k == ROOT_CHANGED; }
|
|||
// ROOT_CHANGED<--chdir(..)-- JAIL_ENTERED<--chdir(..)--
|
||||
// | |
|
||||
// bug<--foo()-- JAIL_ENTERED<--foo()--
|
||||
class ChrootChecker : public CheckerVisitor<ChrootChecker> {
|
||||
IdentifierInfo *II_chroot, *II_chdir;
|
||||
class ChrootChecker : public CheckerV2<eval::Call, check::PreStmt<CallExpr> > {
|
||||
mutable IdentifierInfo *II_chroot, *II_chdir;
|
||||
// This bug refers to possibly break out of a chroot() jail.
|
||||
BuiltinBug *BT_BreakJail;
|
||||
mutable llvm::OwningPtr<BuiltinBug> BT_BreakJail;
|
||||
|
||||
public:
|
||||
ChrootChecker() : II_chroot(0), II_chdir(0), BT_BreakJail(0) {}
|
||||
ChrootChecker() : II_chroot(0), II_chdir(0) {}
|
||||
|
||||
static void *getTag() {
|
||||
static int x;
|
||||
return &x;
|
||||
}
|
||||
|
||||
virtual bool evalCallExpr(CheckerContext &C, const CallExpr *CE);
|
||||
virtual void PreVisitCallExpr(CheckerContext &C, const CallExpr *CE);
|
||||
bool evalCall(const CallExpr *CE, CheckerContext &C) const;
|
||||
void checkPreStmt(const CallExpr *CE, CheckerContext &C) const;
|
||||
|
||||
private:
|
||||
void Chroot(CheckerContext &C, const CallExpr *CE);
|
||||
void Chdir(CheckerContext &C, const CallExpr *CE);
|
||||
void Chroot(CheckerContext &C, const CallExpr *CE) const;
|
||||
void Chdir(CheckerContext &C, const CallExpr *CE) const;
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
static void RegisterChrootChecker(ExprEngine &Eng) {
|
||||
Eng.registerCheck(new ChrootChecker());
|
||||
}
|
||||
|
||||
void ento::registerChrootChecker(CheckerManager &mgr) {
|
||||
mgr.addCheckerRegisterFunction(RegisterChrootChecker);
|
||||
}
|
||||
|
||||
bool ChrootChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
|
||||
bool ChrootChecker::evalCall(const CallExpr *CE, CheckerContext &C) const {
|
||||
const GRState *state = C.getState();
|
||||
const Expr *Callee = CE->getCallee();
|
||||
SVal L = state->getSVal(Callee);
|
||||
|
@ -94,7 +87,7 @@ bool ChrootChecker::evalCallExpr(CheckerContext &C, const CallExpr *CE) {
|
|||
return false;
|
||||
}
|
||||
|
||||
void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) {
|
||||
void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) const {
|
||||
const GRState *state = C.getState();
|
||||
GRStateManager &Mgr = state->getStateManager();
|
||||
|
||||
|
@ -104,7 +97,7 @@ void ChrootChecker::Chroot(CheckerContext &C, const CallExpr *CE) {
|
|||
C.addTransition(state);
|
||||
}
|
||||
|
||||
void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) {
|
||||
void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) const {
|
||||
const GRState *state = C.getState();
|
||||
GRStateManager &Mgr = state->getStateManager();
|
||||
|
||||
|
@ -131,7 +124,7 @@ void ChrootChecker::Chdir(CheckerContext &C, const CallExpr *CE) {
|
|||
}
|
||||
|
||||
// Check the jail state before any function call except chroot and chdir().
|
||||
void ChrootChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
|
||||
void ChrootChecker::checkPreStmt(const CallExpr *CE, CheckerContext &C) const {
|
||||
const GRState *state = C.getState();
|
||||
const Expr *Callee = CE->getCallee();
|
||||
SVal L = state->getSVal(Callee);
|
||||
|
@ -155,9 +148,9 @@ void ChrootChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
|
|||
if (isRootChanged((intptr_t) *k))
|
||||
if (ExplodedNode *N = C.generateNode()) {
|
||||
if (!BT_BreakJail)
|
||||
BT_BreakJail = new BuiltinBug("Break out of jail",
|
||||
BT_BreakJail.reset(new BuiltinBug("Break out of jail",
|
||||
"No call of chdir(\"/\") immediately "
|
||||
"after chroot");
|
||||
"after chroot"));
|
||||
BugReport *R = new BugReport(*BT_BreakJail,
|
||||
BT_BreakJail->getDescription(), N);
|
||||
C.EmitReport(R);
|
||||
|
@ -165,3 +158,7 @@ void ChrootChecker::PreVisitCallExpr(CheckerContext &C, const CallExpr *CE) {
|
|||
|
||||
return;
|
||||
}
|
||||
|
||||
void ento::registerChrootChecker(CheckerManager &mgr) {
|
||||
mgr.registerChecker<ChrootChecker>();
|
||||
}
|
||||
|
|
|
@ -238,11 +238,25 @@ bool ExprEngine::CheckerEvalCall(const CallExpr *CE,
|
|||
DstTmp.clear();
|
||||
}
|
||||
|
||||
if (evaluated)
|
||||
if (evaluated) {
|
||||
Dst.insert(DstTmp);
|
||||
else
|
||||
Dst.insert(Pred);
|
||||
return evaluated;
|
||||
}
|
||||
|
||||
class DefaultEval : public GraphExpander {
|
||||
bool &Evaluated;
|
||||
public:
|
||||
DefaultEval(bool &evaluated) : Evaluated(evaluated) { }
|
||||
virtual void expandGraph(ExplodedNodeSet &Dst, ExplodedNode *Pred) {
|
||||
Evaluated = false;
|
||||
Dst.insert(Pred);
|
||||
}
|
||||
};
|
||||
|
||||
evaluated = true;
|
||||
DefaultEval defaultEval(evaluated);
|
||||
getCheckerManager().runCheckersForEvalCall(Dst, Pred, CE, *this,
|
||||
&defaultEval);
|
||||
return evaluated;
|
||||
}
|
||||
|
||||
|
|
|
@ -66,7 +66,9 @@ static void runPathSensitiveCheckers(CHECK_CTX checkCtx,
|
|||
ExplodedNodeSet &Dst,
|
||||
ExplodedNodeSet &Src) {
|
||||
|
||||
if (checkCtx.Checkers.empty()) {
|
||||
typename CHECK_CTX::CheckersTy::const_iterator
|
||||
I = checkCtx.checkers_begin(), E = checkCtx.checkers_end();
|
||||
if (I == E) {
|
||||
Dst.insert(Src);
|
||||
return;
|
||||
}
|
||||
|
@ -74,8 +76,7 @@ static void runPathSensitiveCheckers(CHECK_CTX checkCtx,
|
|||
ExplodedNodeSet Tmp;
|
||||
ExplodedNodeSet *PrevSet = &Src;
|
||||
|
||||
for (typename CHECK_CTX::CheckersTy::const_iterator
|
||||
I= checkCtx.Checkers.begin(), E= checkCtx.Checkers.end(); I!=E; ++I) {
|
||||
for (; I != E; ++I) {
|
||||
ExplodedNodeSet *CurrSet = 0;
|
||||
if (I+1 == E)
|
||||
CurrSet = &Dst;
|
||||
|
@ -101,6 +102,9 @@ namespace {
|
|||
const Stmt *S;
|
||||
ExprEngine &Eng;
|
||||
|
||||
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)
|
||||
: IsPreVisit(isPreVisit), Checkers(checkers), S(s), Eng(eng) { }
|
||||
|
@ -135,6 +139,9 @@ namespace {
|
|||
const ObjCMessage &Msg;
|
||||
ExprEngine &Eng;
|
||||
|
||||
CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
|
||||
CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
|
||||
|
||||
CheckObjCMessageContext(bool isPreVisit, const CheckersTy &checkers,
|
||||
const ObjCMessage &msg, ExprEngine &eng)
|
||||
: IsPreVisit(isPreVisit), Checkers(checkers), Msg(msg), Eng(eng) { }
|
||||
|
@ -173,6 +180,9 @@ namespace {
|
|||
const GRState *State;
|
||||
ExprEngine &Eng;
|
||||
|
||||
CheckersTy::const_iterator checkers_begin() { return Checkers.begin(); }
|
||||
CheckersTy::const_iterator checkers_end() { return Checkers.end(); }
|
||||
|
||||
CheckLocationContext(const CheckersTy &checkers,
|
||||
SVal loc, bool isLoad, const Stmt *s,
|
||||
const GRState *state, ExprEngine &eng)
|
||||
|
@ -207,6 +217,50 @@ void CheckerManager::runCheckersForEndAnalysis(ExplodedGraph &G,
|
|||
EndAnalysisCheckers[i](G, BR, Eng);
|
||||
}
|
||||
|
||||
/// \brief Run checkers for evaluating a call.
|
||||
/// Only one checker will evaluate the call.
|
||||
void CheckerManager::runCheckersForEvalCall(ExplodedNodeSet &Dst,
|
||||
const ExplodedNodeSet &Src,
|
||||
const CallExpr *CE,
|
||||
ExprEngine &Eng,
|
||||
GraphExpander *defaultEval) {
|
||||
if (EvalCallCheckers.empty() && defaultEval == 0) {
|
||||
Dst.insert(Src);
|
||||
return;
|
||||
}
|
||||
|
||||
for (ExplodedNodeSet::iterator
|
||||
NI = Src.begin(), NE = Src.end(); NI != NE; ++NI) {
|
||||
|
||||
ExplodedNode *Pred = *NI;
|
||||
bool anyEvaluated = false;
|
||||
for (std::vector<EvalCallFunc>::iterator
|
||||
EI = EvalCallCheckers.begin(), EE = EvalCallCheckers.end();
|
||||
EI != EE; ++EI) {
|
||||
ExplodedNodeSet checkDst;
|
||||
CheckerContext C(checkDst, Eng.getBuilder(), Eng, Pred, EI->Checker,
|
||||
ProgramPoint::PostStmtKind, 0, CE);
|
||||
bool evaluated = (*EI)(CE, C);
|
||||
assert(!(evaluated && anyEvaluated)
|
||||
&& "There are more than one checkers evaluating the call");
|
||||
if (evaluated) {
|
||||
anyEvaluated = true;
|
||||
Dst.insert(checkDst);
|
||||
#ifdef NDEBUG
|
||||
break; // on release don't check that no other checker also evals.
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
if (!anyEvaluated) {
|
||||
if (defaultEval)
|
||||
defaultEval->expandGraph(Dst, Pred);
|
||||
else
|
||||
Dst.insert(Pred);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CheckerManager::registerCheckersToEngine(ExprEngine &eng) {
|
||||
for (unsigned i = 0, e = Funcs.size(); i != e; ++i)
|
||||
Funcs[i](eng);
|
||||
|
@ -256,6 +310,10 @@ void CheckerManager::_registerForEndAnalysis(CheckEndAnalysisFunc checkfn) {
|
|||
EndAnalysisCheckers.push_back(checkfn);
|
||||
}
|
||||
|
||||
void CheckerManager::_registerForEvalCall(EvalCallFunc checkfn) {
|
||||
EvalCallCheckers.push_back(checkfn);
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Implementation details.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
@ -290,3 +348,6 @@ CheckerManager::~CheckerManager() {
|
|||
|
||||
// Anchor for the vtable.
|
||||
CheckerProvider::~CheckerProvider() { }
|
||||
|
||||
// Anchor for the vtable.
|
||||
GraphExpander::~GraphExpander() { }
|
||||
|
|
Loading…
Reference in New Issue