Moved registration of basic path-sensitive checks from GRSimpleVals.cpp to GRExprEngineInternalChecks.cpp.

llvm-svn: 53909
This commit is contained in:
Ted Kremenek 2008-07-22 16:21:24 +00:00
parent a380798988
commit 1f352db96a
8 changed files with 364 additions and 409 deletions

View File

@ -298,7 +298,8 @@ static void ActionWarnUninitVals(AnalysisManager& mgr) {
} }
static void ActionGRExprEngine(AnalysisManager& mgr, GRTransferFuncs* tf) { static void ActionGRExprEngine(AnalysisManager& mgr, GRTransferFuncs* tf,
bool StandardWarnings = true) {
llvm::OwningPtr<GRTransferFuncs> TF(tf); llvm::OwningPtr<GRTransferFuncs> TF(tf);
@ -314,6 +315,11 @@ static void ActionGRExprEngine(AnalysisManager& mgr, GRTransferFuncs* tf) {
GRExprEngine Eng(*mgr.getCFG(), *mgr.getCodeDecl(), mgr.getContext(), *L); GRExprEngine Eng(*mgr.getCFG(), *mgr.getCodeDecl(), mgr.getContext(), *L);
Eng.setTransferFunctions(tf); Eng.setTransferFunctions(tf);
if (StandardWarnings) {
Eng.RegisterInternalChecks();
RegisterAppleChecks(Eng);
}
// Execute the worklist algorithm. // Execute the worklist algorithm.
Eng.ExecuteWorkList(); Eng.ExecuteWorkList();
@ -330,10 +336,9 @@ static void ActionCheckerCFRefAux(AnalysisManager& mgr, bool GCEnabled,
GRTransferFuncs* TF = MakeCFRefCountTF(mgr.getContext(), GRTransferFuncs* TF = MakeCFRefCountTF(mgr.getContext(),
GCEnabled, GCEnabled,
StandardWarnings,
mgr.getLangOptions()); mgr.getLangOptions());
ActionGRExprEngine(mgr, TF); ActionGRExprEngine(mgr, TF, StandardWarnings);
} }
static void ActionCheckerCFRef(AnalysisManager& mgr) { static void ActionCheckerCFRef(AnalysisManager& mgr) {

View File

@ -30,6 +30,7 @@ class LiveVariables;
class BugReporter; class BugReporter;
class ObjCImplementationDecl; class ObjCImplementationDecl;
class LangOptions; class LangOptions;
class GRExprEngine;
void CheckDeadStores(LiveVariables& L, BugReporter& BR); void CheckDeadStores(LiveVariables& L, BugReporter& BR);
@ -38,7 +39,6 @@ void CheckUninitializedValues(CFG& cfg, ASTContext& Ctx, Diagnostic& Diags,
GRTransferFuncs* MakeGRSimpleValsTF(); GRTransferFuncs* MakeGRSimpleValsTF();
GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
bool StandardWarnings,
const LangOptions& lopts); const LangOptions& lopts);
void CheckObjCDealloc(ObjCImplementationDecl* D, const LangOptions& L, void CheckObjCDealloc(ObjCImplementationDecl* D, const LangOptions& L,
@ -46,6 +46,8 @@ void CheckObjCDealloc(ObjCImplementationDecl* D, const LangOptions& L,
void CheckObjCInstMethSignature(ObjCImplementationDecl* ID, BugReporter& BR); void CheckObjCInstMethSignature(ObjCImplementationDecl* ID, BugReporter& BR);
void RegisterAppleChecks(GRExprEngine& Eng);
} // end namespace clang } // end namespace clang
#endif #endif

View File

@ -220,6 +220,8 @@ public:
BugTypes.push_back(B); BugTypes.push_back(B);
} }
void RegisterInternalChecks();
void EmitWarnings(BugReporterData& BRData); void EmitWarnings(BugReporterData& BRData);
bool isRetStackAddr(const NodeTy* N) const { bool isRetStackAddr(const NodeTy* N) const {

View File

@ -17,9 +17,12 @@
#include "clang/Analysis/PathSensitive/ExplodedGraph.h" #include "clang/Analysis/PathSensitive/ExplodedGraph.h"
#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h" #include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/ValueState.h" #include "clang/Analysis/PathSensitive/ValueState.h"
#include "clang/Analysis/PathSensitive/BugReporter.h" #include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathDiagnostic.h" #include "clang/Analysis/PathDiagnostic.h"
#include "clang/Analysis/LocalCheckers.h"
#include "clang/AST/Expr.h" #include "clang/AST/Expr.h"
#include "clang/AST/ExprObjC.h" #include "clang/AST/ExprObjC.h"
#include "clang/AST/ASTContext.h" #include "clang/AST/ASTContext.h"
@ -547,3 +550,15 @@ clang::CreateAuditCFNumberCreate(ASTContext& Ctx,
return new AuditCFNumberCreate(Ctx, VMgr); return new AuditCFNumberCreate(Ctx, VMgr);
} }
//===----------------------------------------------------------------------===//
// Check registration.
void clang::RegisterAppleChecks(GRExprEngine& Eng) {
ASTContext& Ctx = Eng.getContext();
ValueStateManager* VMgr = &Eng.getStateManager();
Eng.AddCheck(CreateBasicObjCFoundationChecks(Ctx, VMgr),
Stmt::ObjCMessageExprClass);
Eng.AddCheck(CreateAuditCFNumberCreate(Ctx, VMgr), Stmt::CallExprClass);
}

View File

@ -1244,7 +1244,6 @@ private:
// Instance variables. // Instance variables.
RetainSummaryManager Summaries; RetainSummaryManager Summaries;
const bool EmitStandardWarnings;
const LangOptions& LOpts; const LangOptions& LOpts;
RefBFactoryTy RefBFactory; RefBFactoryTy RefBFactory;
@ -1293,10 +1292,8 @@ private:
public: public:
CFRefCount(ASTContext& Ctx, bool gcenabled, bool StandardWarnings, CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts)
const LangOptions& lopts)
: Summaries(Ctx, gcenabled), : Summaries(Ctx, gcenabled),
EmitStandardWarnings(StandardWarnings),
LOpts(lopts), LOpts(lopts),
RetainSelector(GetNullarySelector("retain", Ctx)), RetainSelector(GetNullarySelector("retain", Ctx)),
ReleaseSelector(GetNullarySelector("release", Ctx)), ReleaseSelector(GetNullarySelector("release", Ctx)),
@ -2223,7 +2220,6 @@ namespace {
} // end anonymous namespace } // end anonymous namespace
void CFRefCount::RegisterChecks(GRExprEngine& Eng) { void CFRefCount::RegisterChecks(GRExprEngine& Eng) {
if (EmitStandardWarnings) GRSimpleVals::RegisterChecks(Eng);
Eng.Register(new UseAfterRelease(*this)); Eng.Register(new UseAfterRelease(*this));
Eng.Register(new BadRelease(*this)); Eng.Register(new BadRelease(*this));
Eng.Register(new Leak(*this)); Eng.Register(new Leak(*this));
@ -2593,7 +2589,6 @@ bool Leak::isCached(BugReport& R) {
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
GRTransferFuncs* clang::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled, GRTransferFuncs* clang::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
bool StandardWarnings,
const LangOptions& lopts) { const LangOptions& lopts) {
return new CFRefCount(Ctx, GCEnabled, StandardWarnings, lopts); return new CFRefCount(Ctx, GCEnabled, lopts);
} }

View File

@ -0,0 +1,332 @@
//=-- GRExprEngineInternalChecks.cpp - Builtin GRExprEngine Checks---*- C++ -*-=
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines the BugType classes used by GRExprEngine to report
// bugs derived from builtin checks in the path-sensitive engine.
//
//===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "llvm/Support/Compiler.h"
using namespace clang;
//===----------------------------------------------------------------------===//
// Utility functions.
//===----------------------------------------------------------------------===//
template <typename ITERATOR> inline
ExplodedNode<ValueState>* GetNode(ITERATOR I) {
return *I;
}
template <> inline
ExplodedNode<ValueState>* GetNode(GRExprEngine::undef_arg_iterator I) {
return I->first;
}
//===----------------------------------------------------------------------===//
// Bug Descriptions.
//===----------------------------------------------------------------------===//
namespace {
class VISIBILITY_HIDDEN BuiltinBug : public BugTypeCacheLocation {
const char* name;
const char* desc;
public:
BuiltinBug(const char* n, const char* d) : name(n), desc(d) {}
virtual const char* getName() const { return name; }
virtual const char* getDescription() const { return desc; }
virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) = 0;
virtual void EmitWarnings(BugReporter& BR) {
EmitBuiltinWarnings(BR, cast<GRBugReporter>(BR).getEngine());
}
template <typename ITER>
void Emit(BugReporter& BR, ITER I, ITER E) {
for (; I != E; ++I) {
BugReport R(*this, GetNode(I));
BR.EmitWarning(R);
}
}
};
class VISIBILITY_HIDDEN NullDeref : public BuiltinBug {
public:
NullDeref() : BuiltinBug("null dereference",
"Dereference of null pointer.") {}
virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
Emit(BR, Eng.null_derefs_begin(), Eng.null_derefs_end());
}
};
class VISIBILITY_HIDDEN UndefinedDeref : public BuiltinBug {
public:
UndefinedDeref() : BuiltinBug("bad dereference",
"Dereference of undefined value.") {}
virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
Emit(BR, Eng.undef_derefs_begin(), Eng.undef_derefs_end());
}
};
class VISIBILITY_HIDDEN DivZero : public BuiltinBug {
public:
DivZero() : BuiltinBug("divide-by-zero",
"Division by zero/undefined value.") {}
virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
Emit(BR, Eng.explicit_bad_divides_begin(), Eng.explicit_bad_divides_end());
}
};
class VISIBILITY_HIDDEN UndefResult : public BuiltinBug {
public:
UndefResult() : BuiltinBug("undefined result",
"Result of operation is undefined.") {}
virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
Emit(BR, Eng.undef_results_begin(), Eng.undef_results_end());
}
};
class VISIBILITY_HIDDEN BadCall : public BuiltinBug {
public:
BadCall()
: BuiltinBug("invalid function call",
"Called function is a NULL or undefined function pointer value.") {}
virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
Emit(BR, Eng.bad_calls_begin(), Eng.bad_calls_end());
}
};
class VISIBILITY_HIDDEN BadArg : public BuiltinBug {
public:
BadArg() : BuiltinBug("bad argument",
"Pass-by-value argument in function is undefined.") {}
BadArg(const char* d) : BuiltinBug("bad argument", d) {}
virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
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(*this, I->first);
report.addRange(I->second->getSourceRange());
// Emit the warning.
BR.EmitWarning(report);
}
}
};
class VISIBILITY_HIDDEN BadMsgExprArg : public BadArg {
public:
BadMsgExprArg()
: BadArg("Pass-by-value argument in message expression is undefined.") {}
virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
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.
RangedBugReport report(*this, I->first);
report.addRange(I->second->getSourceRange());
// Emit the warning.
BR.EmitWarning(report);
}
}
};
class VISIBILITY_HIDDEN BadReceiver : public BuiltinBug {
public:
BadReceiver()
: BuiltinBug("bad receiver",
"Receiver in message expression is an uninitialized value.") {}
virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
for (GRExprEngine::UndefReceiversTy::iterator I=Eng.undef_receivers_begin(),
End = Eng.undef_receivers_end(); I!=End; ++I) {
// Generate a report for this bug.
RangedBugReport report(*this, *I);
ExplodedNode<ValueState>* N = *I;
Stmt *S = cast<PostStmt>(N->getLocation()).getStmt();
Expr* E = cast<ObjCMessageExpr>(S)->getReceiver();
assert (E && "Receiver cannot be NULL");
report.addRange(E->getSourceRange());
// Emit the warning.
BR.EmitWarning(report);
}
}
};
class VISIBILITY_HIDDEN RetStack : public BuiltinBug {
public:
RetStack() : BuiltinBug("return of stack address",
"Address of stack-allocated variable returned.") {}
virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
Emit(BR, Eng.ret_stackaddr_begin(), Eng.ret_stackaddr_end());
}
};
class VISIBILITY_HIDDEN UndefBranch : public BuiltinBug {
struct VISIBILITY_HIDDEN FindUndefExpr {
ValueStateManager& VM;
const ValueState* St;
FindUndefExpr(ValueStateManager& V, const ValueState* S) : VM(V), St(S) {}
Expr* FindExpr(Expr* Ex) {
if (!MatchesCriteria(Ex))
return 0;
for (Stmt::child_iterator I=Ex->child_begin(), E=Ex->child_end(); I!=E; ++I)
if (Expr* ExI = dyn_cast_or_null<Expr>(*I)) {
Expr* E2 = FindExpr(ExI);
if (E2) return E2;
}
return Ex;
}
bool MatchesCriteria(Expr* Ex) { return VM.GetRVal(St, Ex).isUndef(); }
};
public:
UndefBranch()
: BuiltinBug("uninitialized value",
"Branch condition evaluates to an uninitialized value.") {}
virtual void EmitBuiltinWarnings(BugReporter& BR, GRExprEngine& Eng) {
for (GRExprEngine::undef_branch_iterator I=Eng.undef_branches_begin(),
E=Eng.undef_branches_end(); I!=E; ++I) {
// What's going on here: we want to highlight the subexpression of the
// condition that is the most likely source of the "uninitialized
// branch condition." We do a recursive walk of the condition's
// subexpressions and roughly look for the most nested subexpression
// that binds to Undefined. We then highlight that expression's range.
BlockEdge B = cast<BlockEdge>((*I)->getLocation());
Expr* Ex = cast<Expr>(B.getSrc()->getTerminatorCondition());
assert (Ex && "Block must have a terminator.");
// Get the predecessor node and check if is a PostStmt with the Stmt
// being the terminator condition. We want to inspect the state
// of that node instead because it will contain main information about
// the subexpressions.
assert (!(*I)->pred_empty());
// Note: any predecessor will do. They should have identical state,
// since all the BlockEdge did was act as an error sink since the value
// had to already be undefined.
ExplodedNode<ValueState> *N = *(*I)->pred_begin();
ProgramPoint P = N->getLocation();
const ValueState* St = (*I)->getState();
if (PostStmt* PS = dyn_cast<PostStmt>(&P))
if (PS->getStmt() == Ex)
St = N->getState();
FindUndefExpr FindIt(Eng.getStateManager(), St);
Ex = FindIt.FindExpr(Ex);
RangedBugReport R(*this, *I);
R.addRange(Ex->getSourceRange());
BR.EmitWarning(R);
}
}
};
//===----------------------------------------------------------------------===//
// __attribute__(nonnull) checking
class VISIBILITY_HIDDEN CheckAttrNonNull : public GRSimpleAPICheck {
SimpleBugType BT;
std::list<RangedBugReport> Reports;
public:
CheckAttrNonNull() :
BT("'nonnull' argument passed null",
"Null pointer passed as an argument to a 'nonnull' parameter") {}
virtual bool Audit(ExplodedNode<ValueState>* N, ValueStateManager& VMgr) {
CallExpr* CE = cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt());
const ValueState* state = N->getState();
RVal X = VMgr.GetRVal(state, CE->getCallee());
if (!isa<lval::FuncVal>(X))
return false;
FunctionDecl* FD = dyn_cast<FunctionDecl>(cast<lval::FuncVal>(X).getDecl());
const NonNullAttr* Att = FD->getAttr<NonNullAttr>();
if (!Att)
return false;
// Iterate through the arguments of CE and check them for null.
unsigned idx = 0;
bool hasError = false;
for (CallExpr::arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E;
++I, ++idx) {
if (!VMgr.isEqual(state, *I, 0) || !Att->isNonNull(idx))
continue;
RangedBugReport R(BT, N);
R.addRange((*I)->getSourceRange());
Reports.push_back(R);
hasError = true;
}
return hasError;
}
virtual void EmitWarnings(BugReporter& BR) {
for (std::list<RangedBugReport>::iterator I=Reports.begin(),
E=Reports.end(); I!=E; ++I)
BR.EmitWarning(*I);
}
};
} // end anonymous namespace
//===----------------------------------------------------------------------===//
// Check registration.
void GRExprEngine::RegisterInternalChecks() {
Register(new NullDeref());
Register(new UndefinedDeref());
Register(new UndefBranch());
Register(new DivZero());
Register(new UndefResult());
Register(new BadCall());
Register(new RetStack());
Register(new BadArg());
Register(new BadMsgExprArg());
Register(new BadReceiver());
AddCheck(new CheckAttrNonNull(), Stmt::CallExprClass);
}

View File

@ -26,400 +26,6 @@
using namespace clang; using namespace clang;
//===----------------------------------------------------------------------===//
// Utility functions.
//===----------------------------------------------------------------------===//
template <typename ITERATOR> inline
ExplodedNode<ValueState>* GetNode(ITERATOR I) {
return *I;
}
template <> inline
ExplodedNode<ValueState>* GetNode(GRExprEngine::undef_arg_iterator I) {
return I->first;
}
template <typename ITER>
void GenericEmitWarnings(BugReporter& BR, BugType& D, ITER I, ITER E) {
for (; I != E; ++I) {
BugReport R(D, GetNode(I));
BR.EmitWarning(R);
}
}
//===----------------------------------------------------------------------===//
// Bug Descriptions.
//===----------------------------------------------------------------------===//
namespace {
class VISIBILITY_HIDDEN NullDeref : public BugTypeCacheLocation {
public:
virtual const char* getName() const {
return "null dereference";
}
virtual const char* getDescription() const {
return "Dereference of null pointer.";
}
virtual void EmitWarnings(BugReporter& BR) {
GRExprEngine& Eng = cast<GRBugReporter>(BR).getEngine();
GenericEmitWarnings(BR, *this, Eng.null_derefs_begin(),
Eng.null_derefs_end());
}
};
class VISIBILITY_HIDDEN UndefDeref : public BugTypeCacheLocation {
public:
virtual const char* getName() const {
return "bad dereference";
}
virtual const char* getDescription() const {
return "Dereference of undefined value.";
}
virtual void EmitWarnings(BugReporter& BR) {
GRExprEngine& Eng = cast<GRBugReporter>(BR).getEngine();
GenericEmitWarnings(BR, *this, Eng.undef_derefs_begin(),
Eng.undef_derefs_end());
}
};
class VISIBILITY_HIDDEN UndefBranch : public BugTypeCacheLocation {
public:
virtual const char* getName() const {
return "uninitialized value";
}
virtual const char* getDescription() const {
return "Branch condition evaluates to an uninitialized value.";
}
virtual void EmitWarnings(BugReporter& BR);
};
class VISIBILITY_HIDDEN DivZero : public BugTypeCacheLocation {
public:
virtual const char* getName() const {
return "divide-by-zero";
}
virtual const char* getDescription() const {
return "Division by zero/undefined value.";
}
virtual void EmitWarnings(BugReporter& BR) {
GRExprEngine& Eng = cast<GRBugReporter>(BR).getEngine();
GenericEmitWarnings(BR, *this, Eng.explicit_bad_divides_begin(),
Eng.explicit_bad_divides_end());
}
};
class VISIBILITY_HIDDEN UndefResult : public BugTypeCacheLocation {
public:
virtual const char* getName() const {
return "undefined result";
}
virtual const char* getDescription() const {
return "Result of operation is undefined.";
}
virtual void EmitWarnings(BugReporter& BR) {
GRExprEngine& Eng = cast<GRBugReporter>(BR).getEngine();
GenericEmitWarnings(BR, *this, Eng.undef_results_begin(),
Eng.undef_results_end());
}
};
class VISIBILITY_HIDDEN BadCall : public BugTypeCacheLocation {
public:
virtual const char* getName() const {
return "invalid function call";
}
virtual const char* getDescription() const {
return "Called function is a NULL or undefined function pointer value.";
}
virtual void EmitWarnings(BugReporter& BR) {
GRExprEngine& Eng = cast<GRBugReporter>(BR).getEngine();
GenericEmitWarnings(BR, *this, Eng.bad_calls_begin(),
Eng.bad_calls_end());
}
};
class VISIBILITY_HIDDEN BadArg : public BugTypeCacheLocation {
public:
virtual ~BadArg() {}
virtual const char* getName() const {
return "bad argument";
}
virtual const char* getDescription() const {
return "Pass-by-value argument in function is undefined.";
}
virtual void EmitWarnings(BugReporter& BR) {
GRExprEngine& Eng = cast<GRBugReporter>(BR).getEngine();
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(*this, I->first);
report.addRange(I->second->getSourceRange());
// Emit the warning.
BR.EmitWarning(report);
}
}
};
class VISIBILITY_HIDDEN BadMsgExprArg : public BadArg {
public:
virtual const char* getName() const {
return "bad argument";
}
virtual const char* getDescription() const {
return "Pass-by-value argument in message expression is undefined.";
}
virtual void EmitWarnings(BugReporter& BR) {
GRExprEngine& Eng = cast<GRBugReporter>(BR).getEngine();
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.
RangedBugReport report(*this, I->first);
report.addRange(I->second->getSourceRange());
// Emit the warning.
BR.EmitWarning(report);
}
}
};
class VISIBILITY_HIDDEN BadReceiver : public BugTypeCacheLocation {
public:
virtual const char* getName() const {
return "bad receiver";
}
virtual const char* getDescription() const {
return "Receiver in message expression is an uninitialized value.";
}
virtual void EmitWarnings(BugReporter& BR) {
GRExprEngine& Eng = cast<GRBugReporter>(BR).getEngine();
for (GRExprEngine::UndefReceiversTy::iterator I=Eng.undef_receivers_begin(),
End = Eng.undef_receivers_end(); I!=End; ++I) {
// Generate a report for this bug.
RangedBugReport report(*this, *I);
ExplodedNode<ValueState>* N = *I;
Stmt *S = cast<PostStmt>(N->getLocation()).getStmt();
Expr* E = cast<ObjCMessageExpr>(S)->getReceiver();
assert (E && "Receiver cannot be NULL");
report.addRange(E->getSourceRange());
// Emit the warning.
BR.EmitWarning(report);
}
}
};
class VISIBILITY_HIDDEN RetStack : public BugTypeCacheLocation {
public:
virtual const char* getName() const {
return "return of stack address";
}
virtual const char* getDescription() const {
return "Address of stack-allocated variable returned.";
}
virtual void EmitWarnings(BugReporter& BR) {
GRExprEngine& Eng = cast<GRBugReporter>(BR).getEngine();
GenericEmitWarnings(BR, *this, Eng.ret_stackaddr_begin(),
Eng.ret_stackaddr_end());
}
};
} // end anonymous namespace
namespace {
struct VISIBILITY_HIDDEN FindUndefExpr {
ValueStateManager& VM;
const ValueState* St;
FindUndefExpr(ValueStateManager& V, const ValueState* S) : VM(V), St(S) {}
Expr* FindExpr(Expr* Ex) {
if (!MatchesCriteria(Ex))
return 0;
for (Stmt::child_iterator I=Ex->child_begin(), E=Ex->child_end(); I!=E; ++I)
if (Expr* ExI = dyn_cast_or_null<Expr>(*I)) {
Expr* E2 = FindExpr(ExI);
if (E2) return E2;
}
return Ex;
}
bool MatchesCriteria(Expr* Ex) { return VM.GetRVal(St, Ex).isUndef(); }
};
} // end anonymous namespace
void UndefBranch::EmitWarnings(BugReporter& BR) {
GRExprEngine& Eng = cast<GRBugReporter>(BR).getEngine();
for (GRExprEngine::undef_branch_iterator I=Eng.undef_branches_begin(),
E=Eng.undef_branches_end(); I!=E; ++I) {
// What's going on here: we want to highlight the subexpression of the
// condition that is the most likely source of the "uninitialized
// branch condition." We do a recursive walk of the condition's
// subexpressions and roughly look for the most nested subexpression
// that binds to Undefined. We then highlight that expression's range.
BlockEdge B = cast<BlockEdge>((*I)->getLocation());
Expr* Ex = cast<Expr>(B.getSrc()->getTerminatorCondition());
assert (Ex && "Block must have a terminator.");
// Get the predecessor node and check if is a PostStmt with the Stmt
// being the terminator condition. We want to inspect the state
// of that node instead because it will contain main information about
// the subexpressions.
assert (!(*I)->pred_empty());
// Note: any predecessor will do. They should have identical state,
// since all the BlockEdge did was act as an error sink since the value
// had to already be undefined.
ExplodedNode<ValueState> *N = *(*I)->pred_begin();
ProgramPoint P = N->getLocation();
const ValueState* St = (*I)->getState();
if (PostStmt* PS = dyn_cast<PostStmt>(&P))
if (PS->getStmt() == Ex)
St = N->getState();
FindUndefExpr FindIt(Eng.getStateManager(), St);
Ex = FindIt.FindExpr(Ex);
RangedBugReport R(*this, *I);
R.addRange(Ex->getSourceRange());
BR.EmitWarning(R);
}
}
//===----------------------------------------------------------------------===//
// __attribute__(nonnull) checking
class VISIBILITY_HIDDEN CheckAttrNonNull : public GRSimpleAPICheck {
SimpleBugType BT;
std::list<RangedBugReport> Reports;
public:
CheckAttrNonNull() :
BT("'nonnull' argument passed null",
"Null pointer passed as an argument to a 'nonnull' parameter") {}
virtual bool Audit(ExplodedNode<ValueState>* N, ValueStateManager& VMgr) {
CallExpr* CE = cast<CallExpr>(cast<PostStmt>(N->getLocation()).getStmt());
const ValueState* state = N->getState();
RVal X = VMgr.GetRVal(state, CE->getCallee());
if (!isa<lval::FuncVal>(X))
return false;
FunctionDecl* FD = dyn_cast<FunctionDecl>(cast<lval::FuncVal>(X).getDecl());
const NonNullAttr* Att = FD->getAttr<NonNullAttr>();
if (!Att)
return false;
// Iterate through the arguments of CE and check them for null.
unsigned idx = 0;
bool hasError = false;
for (CallExpr::arg_iterator I=CE->arg_begin(), E=CE->arg_end(); I!=E;
++I, ++idx) {
if (!VMgr.isEqual(state, *I, 0) || !Att->isNonNull(idx))
continue;
RangedBugReport R(BT, N);
R.addRange((*I)->getSourceRange());
Reports.push_back(R);
hasError = true;
}
return hasError;
}
virtual void EmitWarnings(BugReporter& BR) {
for (std::list<RangedBugReport>::iterator I=Reports.begin(),
E=Reports.end(); I!=E; ++I)
BR.EmitWarning(*I);
}
};
//===----------------------------------------------------------------------===//
// Check registration.
void GRSimpleVals::RegisterChecks(GRExprEngine& Eng) {
// Path-sensitive checks.
Eng.Register(new NullDeref());
Eng.Register(new UndefDeref());
Eng.Register(new UndefBranch());
Eng.Register(new DivZero());
Eng.Register(new UndefResult());
Eng.Register(new BadCall());
Eng.Register(new RetStack());
Eng.Register(new BadArg());
Eng.Register(new BadMsgExprArg());
Eng.Register(new BadReceiver());
// Add extra checkers.
ASTContext& Ctx = Eng.getContext();
ValueStateManager* VMgr = &Eng.getStateManager();
GRSimpleAPICheck* Check = CreateBasicObjCFoundationChecks(Ctx, VMgr);
Eng.AddCheck(Check, Stmt::ObjCMessageExprClass);
Check = CreateAuditCFNumberCreate(Ctx, VMgr);
Eng.AddCheck(Check, Stmt::CallExprClass);
Eng.AddCheck(new CheckAttrNonNull(), Stmt::CallExprClass);
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Transfer Function creation for External clients. // Transfer Function creation for External clients.
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//

View File

@ -35,8 +35,6 @@ public:
GRSimpleVals() {} GRSimpleVals() {}
virtual ~GRSimpleVals() {} virtual ~GRSimpleVals() {}
virtual void RegisterChecks(GRExprEngine& Eng);
// Casts. // Casts.
virtual RVal EvalCast(GRExprEngine& Engine, NonLVal V, QualType CastT); virtual RVal EvalCast(GRExprEngine& Engine, NonLVal V, QualType CastT);