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:
Ted Kremenek 2009-11-07 03:56:57 +00:00
parent 7ff831962a
commit ae3361de2d
5 changed files with 77 additions and 116 deletions

View File

@ -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

View File

@ -13,6 +13,7 @@
PREVISIT(BinaryOperator)
PREVISIT(CallExpr)
PREVISIT(DeclStmt)
PREVISIT(ObjCMessageExpr)
PREVISIT(ReturnStmt)

View File

@ -196,6 +196,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,
bool assumption) const;
@ -584,6 +587,15 @@ inline const GRState *GRState::Assume(DefinedOrUnknownSVal 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,
bool Assumption) const {

View File

@ -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();

View File

@ -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;
ExplodedNode *UndefSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred,
const GRState *state,
Stmt *S, GRExprEngine &Eng) {
GRStmtNodeBuilder &Builder = Eng.getBuilder();
BugReporter &BR = Eng.getBugReporter();
const VarDecl *VD = dyn_cast<VarDecl>(DS->getSingleDecl());
if (!VD)
return;
const VariableArrayType *VLA = VD->getType()->getAs<VariableArrayType>();
if (!VLA)
return;
if (VariableArrayType* VLA = dyn_cast<VariableArrayType>(T)) {
// FIXME: Handle multi-dimensional VLAs.
Expr* SE = VLA->getSizeExpr();
SVal Size_untested = state->getSVal(SE);
const Expr* SE = VLA->getSizeExpr();
const GRState *state = C.getState();
SVal sizeV = state->getSVal(SE);
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 "
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");
EnhancedBugReport *R =
new EnhancedBugReport(*BT, BT->getName().c_str(), N);
R->addRange(SE->getSourceRange());
R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue, SE);
BR.EmitReport(R);
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 0;
// Check if the size is zero.
DefinedOrUnknownSVal sizeD = cast<DefinedOrUnknownSVal>(sizeV);
const GRState *stateNotZero, *stateZero;
llvm::tie(stateNotZero, stateZero) = state->Assume(sizeD);
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");
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;
}
}
return Pred;
// From this point on, assume that the size is not zero.
if (state != stateNotZero)
C.addTransition(C.GenerateNode(DS, stateNotZero));
}
void *ZeroSizedVLAChecker::getTag() {
static int x;
return &x;
}
ExplodedNode *ZeroSizedVLAChecker::CheckType(QualType T, ExplodedNode *Pred,
const GRState *state, Stmt *S,
GRExprEngine &Eng) {
GRStmtNodeBuilder &Builder = Eng.getBuilder();
BugReporter &BR = Eng.getBugReporter();
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);
}
else
return Pred;
}