forked from OSchip/llvm-project
Remove Checker::CheckType() (and instead using CheckerVisitor::PreVisitDeclStmt()), and refactor VLASizeChecker to have only one Checker subclass (not two) and to not use the node builders directly (and instead use the newer CheckerContext).
llvm-svn: 86329
This commit is contained in:
parent
7ff831962a
commit
ae3361de2d
|
@ -148,13 +148,6 @@ public:
|
|||
virtual void PreVisitBind(CheckerContext &C,
|
||||
const Stmt *AssignE, const Stmt *StoreE,
|
||||
SVal location, SVal val) {}
|
||||
|
||||
virtual ExplodedNode *CheckType(QualType T, ExplodedNode *Pred,
|
||||
const GRState *state, Stmt *S,
|
||||
GRExprEngine &Eng) {
|
||||
return Pred;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
PREVISIT(BinaryOperator)
|
||||
PREVISIT(CallExpr)
|
||||
PREVISIT(DeclStmt)
|
||||
PREVISIT(ObjCMessageExpr)
|
||||
PREVISIT(ReturnStmt)
|
||||
|
||||
|
|
|
@ -195,6 +195,9 @@ public:
|
|||
//
|
||||
|
||||
const GRState *Assume(DefinedOrUnknownSVal cond, bool assumption) const;
|
||||
|
||||
std::pair<const GRState*, const GRState*>
|
||||
Assume(DefinedOrUnknownSVal cond) const;
|
||||
|
||||
const GRState *AssumeInBound(DefinedOrUnknownSVal idx,
|
||||
DefinedOrUnknownSVal upperBound,
|
||||
|
@ -583,6 +586,15 @@ inline const GRState *GRState::Assume(DefinedOrUnknownSVal Cond,
|
|||
return getStateManager().ConstraintMgr->Assume(this, cast<DefinedSVal>(Cond),
|
||||
Assumption);
|
||||
}
|
||||
|
||||
inline std::pair<const GRState*, const GRState*>
|
||||
GRState::Assume(DefinedOrUnknownSVal Cond) const {
|
||||
if (Cond.isUnknown())
|
||||
return std::make_pair(this, this);
|
||||
|
||||
return getStateManager().ConstraintMgr->AssumeDual(this,
|
||||
cast<DefinedSVal>(Cond));
|
||||
}
|
||||
|
||||
inline const GRState *GRState::AssumeInBound(DefinedOrUnknownSVal Idx,
|
||||
DefinedOrUnknownSVal UpperBound,
|
||||
|
|
|
@ -2107,23 +2107,12 @@ void GRExprEngine::VisitDeclStmt(DeclStmt *DS, ExplodedNode *Pred,
|
|||
else
|
||||
Tmp.Add(Pred);
|
||||
|
||||
for (ExplodedNodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
|
||||
ExplodedNodeSet Tmp2;
|
||||
CheckerVisit(DS, Tmp2, Tmp, true);
|
||||
|
||||
for (ExplodedNodeSet::iterator I=Tmp2.begin(), E=Tmp2.end(); I!=E; ++I) {
|
||||
ExplodedNode *N = *I;
|
||||
const GRState *state;
|
||||
|
||||
for (CheckersOrdered::iterator CI = Checkers.begin(), CE = Checkers.end();
|
||||
CI != CE; ++CI) {
|
||||
state = GetState(N);
|
||||
N = CI->second->CheckType(getContext().getCanonicalType(VD->getType()),
|
||||
N, state, DS, *this);
|
||||
if (!N)
|
||||
break;
|
||||
}
|
||||
|
||||
if (!N)
|
||||
continue;
|
||||
|
||||
state = GetState(N);
|
||||
const GRState *state = GetState(N);
|
||||
|
||||
// Decls without InitExpr are not initialized explicitly.
|
||||
const LocationContext *LC = N->getLocationContext();
|
||||
|
|
|
@ -7,124 +7,90 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// This defines two VLASizeCheckers, a builtin check in GRExprEngine that
|
||||
// This defines VLASizeChecker, a builtin check in GRExprEngine that
|
||||
// performs checks for declaration of VLA of undefined or zero size.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "GRExprEngineInternalChecks.h"
|
||||
#include "clang/Analysis/PathSensitive/Checker.h"
|
||||
#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
|
||||
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
|
||||
#include "clang/Analysis/PathSensitive/BugReporter.h"
|
||||
|
||||
using namespace clang;
|
||||
|
||||
namespace {
|
||||
class VISIBILITY_HIDDEN UndefSizedVLAChecker : public Checker {
|
||||
BugType *BT;
|
||||
class VISIBILITY_HIDDEN VLASizeChecker : public CheckerVisitor<VLASizeChecker> {
|
||||
BugType *BT_zero;
|
||||
BugType *BT_undef;
|
||||
|
||||
public:
|
||||
UndefSizedVLAChecker() : BT(0) {}
|
||||
static void *getTag();
|
||||
ExplodedNode *CheckType(QualType T, ExplodedNode *Pred,
|
||||
const GRState *state, Stmt *S, GRExprEngine &Eng);
|
||||
};
|
||||
|
||||
class VISIBILITY_HIDDEN ZeroSizedVLAChecker : public Checker {
|
||||
BugType *BT;
|
||||
|
||||
public:
|
||||
ZeroSizedVLAChecker() : BT(0) {}
|
||||
static void *getTag();
|
||||
ExplodedNode *CheckType(QualType T, ExplodedNode *Pred,
|
||||
const GRState *state, Stmt *S, GRExprEngine &Eng);
|
||||
VLASizeChecker() : BT_zero(0), BT_undef(0) {}
|
||||
static void *getTag() { static int tag = 0; return &tag; }
|
||||
void PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS);
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
void clang::RegisterVLASizeChecker(GRExprEngine &Eng) {
|
||||
Eng.registerCheck(new UndefSizedVLAChecker());
|
||||
Eng.registerCheck(new ZeroSizedVLAChecker());
|
||||
Eng.registerCheck(new VLASizeChecker());
|
||||
}
|
||||
|
||||
void *UndefSizedVLAChecker::getTag() {
|
||||
static int x = 0;
|
||||
return &x;
|
||||
}
|
||||
void VLASizeChecker::PreVisitDeclStmt(CheckerContext &C, const DeclStmt *DS) {
|
||||
if (!DS->isSingleDecl())
|
||||
return;
|
||||
|
||||
const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
|
||||
if (!VD)
|
||||
return;
|
||||
|
||||
const VariableArrayType *VLA = VD->getType()->getAs<VariableArrayType>();
|
||||
if (!VLA)
|
||||
return;
|
||||
|
||||
ExplodedNode *UndefSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred,
|
||||
const GRState *state,
|
||||
Stmt *S, GRExprEngine &Eng) {
|
||||
GRStmtNodeBuilder &Builder = Eng.getBuilder();
|
||||
BugReporter &BR = Eng.getBugReporter();
|
||||
// FIXME: Handle multi-dimensional VLAs.
|
||||
const Expr* SE = VLA->getSizeExpr();
|
||||
const GRState *state = C.getState();
|
||||
SVal sizeV = state->getSVal(SE);
|
||||
|
||||
if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) {
|
||||
// FIXME: Handle multi-dimensional VLAs.
|
||||
Expr* SE = VLA->getSizeExpr();
|
||||
SVal Size_untested = state->getSVal(SE);
|
||||
if (sizeV.isUndef()) {
|
||||
// Generate an error node.
|
||||
ExplodedNode *N = C.GenerateNode(DS, true);
|
||||
if (!N)
|
||||
return;
|
||||
|
||||
if (!BT_undef)
|
||||
BT_undef = new BuiltinBug("Declared variable-length array (VLA) uses a "
|
||||
"garbage value as its size");
|
||||
|
||||
if (Size_untested.isUndef()) {
|
||||
if (ExplodedNode* N = Builder.generateNode(S, state, Pred)) {
|
||||
N->markAsSink();
|
||||
if (!BT)
|
||||
BT = new BuiltinBug("Declared variable-length array (VLA) uses a "
|
||||
"garbage value as its size");
|
||||
|
||||
EnhancedBugReport *R =
|
||||
new EnhancedBugReport(*BT, BT->getName().c_str(), N);
|
||||
R->addRange(SE->getSourceRange());
|
||||
R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
|
||||
BR.EmitReport(R);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
EnhancedBugReport *report =
|
||||
new EnhancedBugReport(*BT_undef, BT_undef->getName().c_str(), N);
|
||||
report->addRange(SE->getSourceRange());
|
||||
report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
|
||||
C.EmitReport(report);
|
||||
return;
|
||||
}
|
||||
return Pred;
|
||||
}
|
||||
|
||||
// Check if the size is zero.
|
||||
DefinedOrUnknownSVal sizeD = cast<DefinedOrUnknownSVal>(sizeV);
|
||||
|
||||
void *ZeroSizedVLAChecker::getTag() {
|
||||
static int x;
|
||||
return &x;
|
||||
}
|
||||
const GRState *stateNotZero, *stateZero;
|
||||
llvm::tie(stateNotZero, stateZero) = state->Assume(sizeD);
|
||||
|
||||
ExplodedNode *ZeroSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred,
|
||||
const GRState *state, Stmt *S,
|
||||
GRExprEngine &Eng) {
|
||||
GRStmtNodeBuilder &Builder = Eng.getBuilder();
|
||||
BugReporter &BR = Eng.getBugReporter();
|
||||
if (stateZero && !stateNotZero) {
|
||||
ExplodedNode* N = C.GenerateNode(DS, stateZero, true);
|
||||
if (!BT_zero)
|
||||
BT_zero = new BuiltinBug("Declared variable-length array (VLA) has zero "
|
||||
"size");
|
||||
|
||||
if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) {
|
||||
// FIXME: Handle multi-dimensional VLAs.
|
||||
Expr* SE = VLA->getSizeExpr();
|
||||
SVal Size_untested = state->getSVal(SE);
|
||||
|
||||
DefinedOrUnknownSVal *Size = dyn_cast<DefinedOrUnknownSVal>(&Size_untested);
|
||||
// Undefined size is checked in another checker.
|
||||
if (!Size)
|
||||
return Pred;
|
||||
|
||||
const GRState *zeroState = state->Assume(*Size, false);
|
||||
state = state->Assume(*Size, true);
|
||||
|
||||
if (zeroState && !state) {
|
||||
if (ExplodedNode* N = Builder.generateNode(S, zeroState, Pred)) {
|
||||
N->markAsSink();
|
||||
if (!BT)
|
||||
BT = new BugType("Declared variable-length array (VLA) has zero size",
|
||||
"Logic error");
|
||||
|
||||
EnhancedBugReport *R =
|
||||
new EnhancedBugReport(*BT, BT->getName().c_str(), N);
|
||||
R->addRange(SE->getSourceRange());
|
||||
R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
|
||||
BR.EmitReport(R);
|
||||
}
|
||||
}
|
||||
if (!state)
|
||||
return 0;
|
||||
|
||||
return Builder.generateNode(S, state, Pred);
|
||||
EnhancedBugReport *report =
|
||||
new EnhancedBugReport(*BT_zero, BT_zero->getName().c_str(), N);
|
||||
report->addRange(SE->getSourceRange());
|
||||
report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
|
||||
C.EmitReport(report);
|
||||
return;
|
||||
}
|
||||
else
|
||||
return Pred;
|
||||
|
||||
// From this point on, assume that the size is not zero.
|
||||
if (state != stateNotZero)
|
||||
C.addTransition(C.GenerateNode(DS, stateNotZero));
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue