Cleanup internal checks bug reporting, allowing intermediate diagnostics to be generated for bad argument warnings, bad branches, etc.

llvm-svn: 71838
This commit is contained in:
Ted Kremenek 2009-05-15 05:25:09 +00:00
parent c9cbd86cfa
commit 608a6176a1
1 changed files with 134 additions and 71 deletions

View File

@ -39,8 +39,15 @@ ExplodedNode<GRState>* GetNode(GRExprEngine::undef_arg_iterator I) {
// Forward declarations for bug reporter visitors.
//===----------------------------------------------------------------------===//
static const Stmt *GetDerefExpr(const ExplodedNode<GRState> *N);
static const Stmt *GetReceiverExpr(const ExplodedNode<GRState> *N);
static const Stmt *GetDenomExpr(const ExplodedNode<GRState> *N);
static const Stmt *GetCalleeExpr(const ExplodedNode<GRState> *N);
static const Stmt *GetRetValExpr(const ExplodedNode<GRState> *N);
static void registerTrackNullOrUndefValue(BugReporterContext& BRC,
const ExplodedNode<GRState>* N);
const Stmt *ValExpr,
const ExplodedNode<GRState>* N);
//===----------------------------------------------------------------------===//
// Bug Descriptions.
@ -54,6 +61,10 @@ public:
ExplodedNode<GRState> *n)
: RangedBugReport(bt, desc, n) {}
BuiltinBugReport(BugType& bt, const char *shortDesc, const char *desc,
ExplodedNode<GRState> *n)
: RangedBugReport(bt, shortDesc, desc, n) {}
void registerInitialVisitors(BugReporterContext& BRC,
const ExplodedNode<GRState>* N);
};
@ -104,7 +115,7 @@ public:
void registerInitialVisitors(BugReporterContext& BRC,
const ExplodedNode<GRState>* N,
BuiltinBugReport *R) {
registerTrackNullOrUndefValue(BRC, N);
registerTrackNullOrUndefValue(BRC, GetDerefExpr(N), N);
}
};
@ -136,7 +147,7 @@ public:
void registerInitialVisitors(BugReporterContext& BRC,
const ExplodedNode<GRState>* N,
BuiltinBugReport *R) {
registerTrackNullOrUndefValue(BRC, N);
registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N);
}
};
@ -170,7 +181,7 @@ public:
void registerInitialVisitors(BugReporterContext& BRC,
const ExplodedNode<GRState>* N,
BuiltinBugReport *R) {
registerTrackNullOrUndefValue(BRC, N);
registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N);
}
};
@ -186,7 +197,7 @@ public:
void registerInitialVisitors(BugReporterContext& BRC,
const ExplodedNode<GRState>* N,
BuiltinBugReport *R) {
registerTrackNullOrUndefValue(BRC, N);
registerTrackNullOrUndefValue(BRC, GetDerefExpr(N), N);
}
};
@ -199,6 +210,12 @@ public:
void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
Emit(BR, Eng.explicit_bad_divides_begin(), Eng.explicit_bad_divides_end());
}
void registerInitialVisitors(BugReporterContext& BRC,
const ExplodedNode<GRState>* N,
BuiltinBugReport *R) {
registerTrackNullOrUndefValue(BRC, GetDenomExpr(N), N);
}
};
class VISIBILITY_HIDDEN UndefResult : public BuiltinBug {
@ -220,10 +237,31 @@ public:
void FlushReportsImpl(BugReporter& BR, GRExprEngine& Eng) {
Emit(BR, Eng.bad_calls_begin(), Eng.bad_calls_end());
}
void registerInitialVisitors(BugReporterContext& BRC,
const ExplodedNode<GRState>* N,
BuiltinBugReport *R) {
registerTrackNullOrUndefValue(BRC, GetCalleeExpr(N), N);
}
};
class VISIBILITY_HIDDEN ArgReport : public BuiltinBugReport {
const Stmt *Arg;
public:
ArgReport(BugType& bt, const char* desc, ExplodedNode<GRState> *n,
const Stmt *arg)
: BuiltinBugReport(bt, desc, n), Arg(arg) {}
ArgReport(BugType& bt, const char *shortDesc, const char *desc,
ExplodedNode<GRState> *n, const Stmt *arg)
: BuiltinBugReport(bt, shortDesc, desc, n), Arg(arg) {}
const Stmt *getArg() const { return Arg; }
};
class VISIBILITY_HIDDEN BadArg : public BuiltinBug {
public:
public:
BadArg(GRExprEngine* eng) : BuiltinBug(eng,"Uninitialized argument",
"Pass-by-value argument in function call is undefined.") {}
@ -234,12 +272,19 @@ public:
for (GRExprEngine::UndefArgsTy::iterator I = Eng.undef_arg_begin(),
E = Eng.undef_arg_end(); I!=E; ++I) {
// Generate a report for this bug.
RangedBugReport *report = new RangedBugReport(*this, desc.c_str(),
I->first);
ArgReport *report = new ArgReport(*this, desc.c_str(), I->first,
I->second);
report->addRange(I->second->getSourceRange());
BR.EmitReport(report);
}
}
void registerInitialVisitors(BugReporterContext& BRC,
const ExplodedNode<GRState>* N,
BuiltinBugReport *R) {
registerTrackNullOrUndefValue(BRC, static_cast<ArgReport*>(R)->getArg(),
N);
}
};
class VISIBILITY_HIDDEN BadMsgExprArg : public BadArg {
@ -251,12 +296,12 @@ public:
for (GRExprEngine::UndefArgsTy::iterator I=Eng.msg_expr_undef_arg_begin(),
E = Eng.msg_expr_undef_arg_end(); I!=E; ++I) {
// Generate a report for this bug.
BuiltinBugReport *report = new BuiltinBugReport(*this, desc.c_str(),
I->first);
ArgReport *report = new ArgReport(*this, desc.c_str(), I->first,
I->second);
report->addRange(I->second->getSourceRange());
BR.EmitReport(report);
}
}
}
};
class VISIBILITY_HIDDEN BadReceiver : public BuiltinBug {
@ -279,12 +324,12 @@ public:
BR.EmitReport(report);
}
}
void registerInitialVisitors(BugReporterContext& BRC,
const ExplodedNode<GRState>* N,
BuiltinBugReport *R) {
registerTrackNullOrUndefValue(BRC, N);
}
registerTrackNullOrUndefValue(BRC, GetReceiverExpr(N), N);
}
};
class VISIBILITY_HIDDEN RetStack : public BuiltinBug {
@ -358,8 +403,8 @@ public:
void registerInitialVisitors(BugReporterContext& BRC,
const ExplodedNode<GRState>* N,
BuiltinBugReport *R) {
registerTrackNullOrUndefValue(BRC, N);
}
registerTrackNullOrUndefValue(BRC, GetRetValExpr(N), N);
}
};
class VISIBILITY_HIDDEN UndefBranch : public BuiltinBug {
@ -423,11 +468,18 @@ public:
FindUndefExpr FindIt(Eng.getStateManager(), St);
Ex = FindIt.FindExpr(Ex);
RangedBugReport *R = new RangedBugReport(*this, desc.c_str(), *I);
ArgReport *R = new ArgReport(*this, desc.c_str(), *I, Ex);
R->addRange(Ex->getSourceRange());
BR.EmitReport(R);
}
}
void registerInitialVisitors(BugReporterContext& BRC,
const ExplodedNode<GRState>* N,
BuiltinBugReport *R) {
registerTrackNullOrUndefValue(BRC, static_cast<ArgReport*>(R)->getArg(),
N);
}
};
class VISIBILITY_HIDDEN OutOfBoundMemoryAccess : public BuiltinBug {
@ -481,13 +533,20 @@ public:
<< (isUndefined ? "garbage value for array size"
: "has zero elements (undefined behavior)");
RangedBugReport *report = new RangedBugReport(*this,
os_short.str().c_str(),
os.str().c_str(), N);
ArgReport *report = new ArgReport(*this, os_short.str().c_str(),
os.str().c_str(), N, SizeExpr);
report->addRange(SizeExpr->getSourceRange());
BR.EmitReport(report);
}
}
void registerInitialVisitors(BugReporterContext& BRC,
const ExplodedNode<GRState>* N,
BuiltinBugReport *R) {
registerTrackNullOrUndefValue(BRC, static_cast<ArgReport*>(R)->getArg(),
N);
}
};
//===----------------------------------------------------------------------===//
@ -549,6 +608,47 @@ public:
// Definitions for bug reporter visitors.
//===----------------------------------------------------------------------===//
static const Stmt *GetDerefExpr(const ExplodedNode<GRState> *N) {
// Pattern match for a few useful cases (do something smarter later):
// a[0], p->f, *p
const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
if (const UnaryOperator *U = dyn_cast<UnaryOperator>(S)) {
if (U->getOpcode() == UnaryOperator::Deref)
return U->getSubExpr()->IgnoreParenCasts();
}
else if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) {
return ME->getBase()->IgnoreParenCasts();
}
else if (const ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(S)) {
// Retrieve the base for arrays since BasicStoreManager doesn't know how
// to reason about them.
return AE->getBase();
}
return NULL;
}
static const Stmt *GetReceiverExpr(const ExplodedNode<GRState> *N) {
const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
return cast<ObjCMessageExpr>(S)->getReceiver();
}
static const Stmt *GetDenomExpr(const ExplodedNode<GRState> *N) {
const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
return cast<BinaryOperator>(S)->getRHS();
}
static const Stmt *GetCalleeExpr(const ExplodedNode<GRState> *N) {
const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
return cast<CallExpr>(S)->getCallee();
}
static const Stmt *GetRetValExpr(const ExplodedNode<GRState> *N) {
const Stmt *S = N->getLocationAs<PostStmt>()->getStmt();
return cast<ReturnStmt>(S)->getRetValue();
}
namespace {
class VISIBILITY_HIDDEN FindLastStoreBRVisitor : public BugReporterVisitor {
const MemRegion *R;
@ -624,6 +724,9 @@ public:
if (!b)
os << "initialized to a null pointer value";
}
else if (isa<nonloc::ConcreteInt>(V)) {
os << "initialized to " << cast<nonloc::ConcreteInt>(V).getValue();
}
else if (V.isUndef()) {
if (isa<VarRegion>(R)) {
const VarDecl *VD = cast<VarDecl>(DS->getSingleDecl());
@ -635,7 +738,7 @@ public:
}
}
}
if (os.str().empty()) {
if (isa<loc::ConcreteInt>(V)) {
bool b = false;
@ -734,7 +837,7 @@ public:
if (isa<Loc>(Constraint)) {
os << "Assuming pointer value is ";
os << (Assumption ? "non-NULL" : "NULL");
os << (Assumption ? "non-null" : "null");
}
if (os.str().empty())
@ -771,65 +874,29 @@ static void registerTrackConstraint(BugReporterContext& BRC, SVal Constraint,
}
static void registerTrackNullOrUndefValue(BugReporterContext& BRC,
const ExplodedNode<GRState>* N) {
const Stmt *S,
const ExplodedNode<GRState>* N) {
ProgramPoint P = N->getLocation();
PostStmt *PS = dyn_cast<PostStmt>(&P);
if (!PS)
if (!S)
return;
Stmt *S = PS->getStmt();
GRStateManager &StateMgr = BRC.getStateManager();
const GRState *state = N->getState();
const GRState *state = N->getState();
// Pattern match for a few useful cases (do something smarter later):
// a[0], p->f, *p
const DeclRefExpr *DR = 0;
if (const UnaryOperator *U = dyn_cast<UnaryOperator>(S)) {
if (U->getOpcode() == UnaryOperator::Deref)
DR = dyn_cast<DeclRefExpr>(U->getSubExpr()->IgnoreParenCasts());
}
else if (const MemberExpr *ME = dyn_cast<MemberExpr>(S)) {
DR = dyn_cast<DeclRefExpr>(ME->getBase()->IgnoreParenCasts());
}
else if (const ObjCMessageExpr *MSE = dyn_cast<ObjCMessageExpr>(S)) {
// FIXME: We should probably distinguish between cases where we had
// a nil receiver and null dereferences.
const Expr *Receiver = MSE->getReceiver();
if (Receiver) {
DR = dyn_cast<DeclRefExpr>(Receiver->IgnoreParenCasts());
}
}
else if (const ReturnStmt *RS = dyn_cast<ReturnStmt>(S)) {
if (const Expr *Ret = RS->getRetValue())
DR = dyn_cast<DeclRefExpr>(Ret->IgnoreParenCasts());
}
else if (const Expr *Ex = dyn_cast<Expr>(S)) {
// Keep this case last.
DR = dyn_cast<DeclRefExpr>(Ex->IgnoreParenCasts());
}
if (DR) {
if (const DeclRefExpr *DR = dyn_cast<DeclRefExpr>(S)) {
if (const VarDecl *VD = dyn_cast<VarDecl>(DR->getDecl())) {
const VarRegion *R =
StateMgr.getRegionManager().getVarRegion(VD);
// What did we load?
SVal V = StateMgr.GetSVal(state, R);
SVal V = StateMgr.GetSVal(state, S);
if (isa<loc::ConcreteInt>(V) || V.isUndef()) {
if (isa<loc::ConcreteInt>(V) || isa<nonloc::ConcreteInt>(V)
|| V.isUndef()) {
registerFindLastStore(BRC, R, V);
}
}
}
// Retrieve the base for arrays since BasicStoreManager doesn't know how
// to reason about them.
if (ArraySubscriptExpr *AE = dyn_cast<ArraySubscriptExpr>(S)) {
S = AE->getBase();
}
SVal V = StateMgr.GetSValAsScalarOrLoc(state, S);
@ -849,10 +916,6 @@ static void registerTrackNullOrUndefValue(BugReporterContext& BRC,
registerTrackConstraint(BRC, loc::MemRegionVal(R), false);
}
}
// Was it a hard integer?
// if (isa<nonloc::ConcreteInt>(V))
// registerTrackValue(BRC, S, V, N);
}
//===----------------------------------------------------------------------===//