зеркало из https://github.com/microsoft/clang-1.git
Moved registration of basic path-sensitive checks from GRSimpleVals.cpp to GRExprEngineInternalChecks.cpp.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@53909 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Родитель
e3ae82accd
Коммит
78d46242e3
|
@ -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);
|
||||
|
@ -314,6 +315,11 @@ static void ActionGRExprEngine(AnalysisManager& mgr, GRTransferFuncs* tf) {
|
|||
GRExprEngine Eng(*mgr.getCFG(), *mgr.getCodeDecl(), mgr.getContext(), *L);
|
||||
Eng.setTransferFunctions(tf);
|
||||
|
||||
if (StandardWarnings) {
|
||||
Eng.RegisterInternalChecks();
|
||||
RegisterAppleChecks(Eng);
|
||||
}
|
||||
|
||||
// Execute the worklist algorithm.
|
||||
Eng.ExecuteWorkList();
|
||||
|
||||
|
@ -330,10 +336,9 @@ static void ActionCheckerCFRefAux(AnalysisManager& mgr, bool GCEnabled,
|
|||
|
||||
GRTransferFuncs* TF = MakeCFRefCountTF(mgr.getContext(),
|
||||
GCEnabled,
|
||||
StandardWarnings,
|
||||
mgr.getLangOptions());
|
||||
|
||||
ActionGRExprEngine(mgr, TF);
|
||||
ActionGRExprEngine(mgr, TF, StandardWarnings);
|
||||
}
|
||||
|
||||
static void ActionCheckerCFRef(AnalysisManager& mgr) {
|
||||
|
|
|
@ -30,6 +30,7 @@ class LiveVariables;
|
|||
class BugReporter;
|
||||
class ObjCImplementationDecl;
|
||||
class LangOptions;
|
||||
class GRExprEngine;
|
||||
|
||||
void CheckDeadStores(LiveVariables& L, BugReporter& BR);
|
||||
|
||||
|
@ -38,7 +39,6 @@ void CheckUninitializedValues(CFG& cfg, ASTContext& Ctx, Diagnostic& Diags,
|
|||
|
||||
GRTransferFuncs* MakeGRSimpleValsTF();
|
||||
GRTransferFuncs* MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
|
||||
bool StandardWarnings,
|
||||
const LangOptions& lopts);
|
||||
|
||||
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 RegisterAppleChecks(GRExprEngine& Eng);
|
||||
|
||||
} // end namespace clang
|
||||
|
||||
#endif
|
||||
|
|
|
@ -220,6 +220,8 @@ public:
|
|||
BugTypes.push_back(B);
|
||||
}
|
||||
|
||||
void RegisterInternalChecks();
|
||||
|
||||
void EmitWarnings(BugReporterData& BRData);
|
||||
|
||||
bool isRetStackAddr(const NodeTy* N) const {
|
||||
|
|
|
@ -17,9 +17,12 @@
|
|||
|
||||
#include "clang/Analysis/PathSensitive/ExplodedGraph.h"
|
||||
#include "clang/Analysis/PathSensitive/GRSimpleAPICheck.h"
|
||||
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
|
||||
#include "clang/Analysis/PathSensitive/ValueState.h"
|
||||
#include "clang/Analysis/PathSensitive/BugReporter.h"
|
||||
#include "clang/Analysis/PathDiagnostic.h"
|
||||
#include "clang/Analysis/LocalCheckers.h"
|
||||
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "clang/AST/ExprObjC.h"
|
||||
#include "clang/AST/ASTContext.h"
|
||||
|
@ -547,3 +550,15 @@ clang::CreateAuditCFNumberCreate(ASTContext& Ctx,
|
|||
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);
|
||||
}
|
||||
|
|
|
@ -1244,7 +1244,6 @@ private:
|
|||
// Instance variables.
|
||||
|
||||
RetainSummaryManager Summaries;
|
||||
const bool EmitStandardWarnings;
|
||||
const LangOptions& LOpts;
|
||||
RefBFactoryTy RefBFactory;
|
||||
|
||||
|
@ -1293,10 +1292,8 @@ private:
|
|||
|
||||
public:
|
||||
|
||||
CFRefCount(ASTContext& Ctx, bool gcenabled, bool StandardWarnings,
|
||||
const LangOptions& lopts)
|
||||
CFRefCount(ASTContext& Ctx, bool gcenabled, const LangOptions& lopts)
|
||||
: Summaries(Ctx, gcenabled),
|
||||
EmitStandardWarnings(StandardWarnings),
|
||||
LOpts(lopts),
|
||||
RetainSelector(GetNullarySelector("retain", Ctx)),
|
||||
ReleaseSelector(GetNullarySelector("release", Ctx)),
|
||||
|
@ -2223,7 +2220,6 @@ namespace {
|
|||
} // end anonymous namespace
|
||||
|
||||
void CFRefCount::RegisterChecks(GRExprEngine& Eng) {
|
||||
if (EmitStandardWarnings) GRSimpleVals::RegisterChecks(Eng);
|
||||
Eng.Register(new UseAfterRelease(*this));
|
||||
Eng.Register(new BadRelease(*this));
|
||||
Eng.Register(new Leak(*this));
|
||||
|
@ -2593,7 +2589,6 @@ bool Leak::isCached(BugReport& R) {
|
|||
//===----------------------------------------------------------------------===//
|
||||
|
||||
GRTransferFuncs* clang::MakeCFRefCountTF(ASTContext& Ctx, bool GCEnabled,
|
||||
bool StandardWarnings,
|
||||
const LangOptions& lopts) {
|
||||
return new CFRefCount(Ctx, GCEnabled, StandardWarnings, lopts);
|
||||
return new CFRefCount(Ctx, GCEnabled, lopts);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -26,400 +26,6 @@
|
|||
|
||||
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.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
|
|
@ -35,8 +35,6 @@ public:
|
|||
GRSimpleVals() {}
|
||||
virtual ~GRSimpleVals() {}
|
||||
|
||||
virtual void RegisterChecks(GRExprEngine& Eng);
|
||||
|
||||
// Casts.
|
||||
|
||||
virtual RVal EvalCast(GRExprEngine& Engine, NonLVal V, QualType CastT);
|
||||
|
|
Загрузка…
Ссылка в новой задаче