summaryrefslogtreecommitdiffstats
path: root/clang/lib
diff options
context:
space:
mode:
authorTed Kremenek <kremenek@apple.com>2008-04-09 21:41:14 +0000
committerTed Kremenek <kremenek@apple.com>2008-04-09 21:41:14 +0000
commit7acc3a36ef4f938fc1ad65e0ef494b01f6892463 (patch)
treed9cbff78567b1273554265d23caa9417c1f8d329 /clang/lib
parentc8eeb752a32863c5982f27d4ea2678181adc106c (diff)
downloadbcm5719-llvm-7acc3a36ef4f938fc1ad65e0ef494b01f6892463.tar.gz
bcm5719-llvm-7acc3a36ef4f938fc1ad65e0ef494b01f6892463.zip
Major refactoring/cleanup of GRExprEngine, ExplodedGraph, and BugReporter.
Bugs are now reported using a combination of "BugType" (previously BugDescription) and Bug "BugReport" objects, which are fed to BugReporter (which generates PathDiagnostics). This provides a far more modular way of registering bug types and plugging in diagnostics. GRExprEngine now owns its copy of GRCoreEngine, and is not owned by the ExplodedGraph. ExplodedGraph is no longer templated on the "checker", but instead on the state contained in the nodes. llvm-svn: 49453
Diffstat (limited to 'clang/lib')
-rw-r--r--clang/lib/Analysis/BasicObjCFoundationChecks.cpp92
-rw-r--r--clang/lib/Analysis/BugReporter.cpp76
-rw-r--r--clang/lib/Analysis/CFRefCount.cpp12
-rw-r--r--clang/lib/Analysis/GRExprEngine.cpp62
-rw-r--r--clang/lib/Analysis/GRSimpleVals.cpp308
-rw-r--r--clang/lib/Analysis/GRSimpleVals.h2
6 files changed, 346 insertions, 206 deletions
diff --git a/clang/lib/Analysis/BasicObjCFoundationChecks.cpp b/clang/lib/Analysis/BasicObjCFoundationChecks.cpp
index 6149abefa37..154adcaa477 100644
--- a/clang/lib/Analysis/BasicObjCFoundationChecks.cpp
+++ b/clang/lib/Analysis/BasicObjCFoundationChecks.cpp
@@ -54,51 +54,61 @@ static const char* GetReceiverNameType(ObjCMessageExpr* ME) {
namespace {
-class VISIBILITY_HIDDEN NilArg : public BugDescription {
- std::string Msg;
- const char* s;
- SourceRange R;
+class VISIBILITY_HIDDEN NilArg : public BugType {
public:
- NilArg(ObjCMessageExpr* ME, unsigned Arg);
virtual ~NilArg() {}
virtual const char* getName() const {
return "nil argument";
}
- virtual const char* getDescription() const {
- return s;
- }
-
- virtual void getRanges(const SourceRange*& beg,
- const SourceRange*& end) const {
- beg = &R;
- end = beg+1;
- }
+ class Report : public BugReport {
+ std::string Msg;
+ const char* s;
+ SourceRange R;
+ public:
+ Report(NilArg& Desc, ObjCMessageExpr* ME, unsigned Arg) : BugReport(Desc) {
+
+ Expr* E = ME->getArg(Arg);
+ R = E->getSourceRange();
+
+ std::ostringstream os;
+
+ os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
+ << ME->getSelector().getName() << "' cannot be nil.";
+
+ Msg = os.str();
+ s = Msg.c_str();
+ }
+
+ virtual ~Report() {}
+
+ virtual PathDiagnosticPiece* getEndPath(ASTContext& Ctx,
+ ExplodedNode<ValueState> *N) const {
+
+ Stmt* S = cast<PostStmt>(N->getLocation()).getStmt();
+
+ if (!S)
+ return NULL;
+
+ FullSourceLoc L(S->getLocStart(), Ctx.getSourceManager());
+ PathDiagnosticPiece* P = new PathDiagnosticPiece(L, s);
+
+ P->addRange(R);
+
+ return P;
+ }
+ };
};
-
-NilArg::NilArg(ObjCMessageExpr* ME, unsigned Arg) : s(NULL) {
-
- Expr* E = ME->getArg(Arg);
- R = E->getSourceRange();
-
- std::ostringstream os;
-
- os << "Argument to '" << GetReceiverNameType(ME) << "' method '"
- << ME->getSelector().getName() << "' cannot be nil.";
-
- Msg = os.str();
- s = Msg.c_str();
-}
-
+
class VISIBILITY_HIDDEN BasicObjCFoundationChecks : public GRSimpleAPICheck {
-
+ NilArg Desc;
ASTContext &Ctx;
ValueStateManager* VMgr;
- typedef std::vector<std::pair<NodeTy*,BugDescription*> > ErrorsTy;
+ typedef std::vector<std::pair<NodeTy*,BugReport*> > ErrorsTy;
ErrorsTy Errors;
RVal GetRVal(ValueState* St, Expr* E) { return VMgr->GetRVal(St, E); }
@@ -122,18 +132,16 @@ public:
virtual bool Audit(ExplodedNode<ValueState>* N);
- virtual void ReportResults(Diagnostic& Diag, PathDiagnosticClient* PD,
- ASTContext& Ctx, BugReporter& BR,
- ExplodedGraph<GRExprEngine>& G);
+ virtual void EmitWarnings(BugReporter& BR);
private:
- void AddError(NodeTy* N, BugDescription* D) {
- Errors.push_back(std::make_pair(N, D));
+ void AddError(NodeTy* N, BugReport* R) {
+ Errors.push_back(std::make_pair(N, R));
}
void WarnNilArg(NodeTy* N, ObjCMessageExpr* ME, unsigned Arg) {
- AddError(N, new NilArg(ME, Arg));
+ AddError(N, new NilArg::Report(Desc, ME, Arg));
}
};
@@ -186,13 +194,11 @@ static inline bool isNil(RVal X) {
//===----------------------------------------------------------------------===//
-void BasicObjCFoundationChecks::ReportResults(Diagnostic& Diag,
- PathDiagnosticClient* PD,
- ASTContext& Ctx, BugReporter& BR,
- ExplodedGraph<GRExprEngine>& G) {
-
+void BasicObjCFoundationChecks::EmitWarnings(BugReporter& BR) {
+
for (ErrorsTy::iterator I=Errors.begin(), E=Errors.end(); I!=E; ++I)
- BR.EmitPathWarning(Diag, PD, Ctx, *I->second, G, I->first);
+
+ BR.EmitPathWarning(*I->second, I->first);
}
bool BasicObjCFoundationChecks::CheckNilArg(NodeTy* N, unsigned Arg) {
diff --git a/clang/lib/Analysis/BugReporter.cpp b/clang/lib/Analysis/BugReporter.cpp
index 66b1b04c9d0..c851696a301 100644
--- a/clang/lib/Analysis/BugReporter.cpp
+++ b/clang/lib/Analysis/BugReporter.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/BugReporter.h"
+#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Basic/SourceManager.h"
#include "clang/Basic/SourceLocation.h"
#include "clang/AST/ASTContext.h"
@@ -25,6 +26,9 @@
using namespace clang;
BugReporter::~BugReporter() {}
+BugType::~BugType() {}
+BugReport::~BugReport() {}
+ExplodedGraph<ValueState>& BugReporter::getGraph() { return Eng.getGraph(); }
static inline Stmt* GetStmt(const ProgramPoint& P) {
if (const PostStmt* PS = dyn_cast<PostStmt>(&P)) {
@@ -48,7 +52,7 @@ static inline Stmt* GetStmt(const CFGBlock* B) {
PathDiagnosticPiece*
-BugDescription::getEndPath(ASTContext& Ctx, ExplodedNode<ValueState> *N) const {
+BugReport::getEndPath(ASTContext& Ctx, ExplodedNode<ValueState> *N) const {
Stmt* S = GetStmt(N->getLocation());
@@ -56,7 +60,9 @@ BugDescription::getEndPath(ASTContext& Ctx, ExplodedNode<ValueState> *N) const {
return NULL;
FullSourceLoc L(S->getLocStart(), Ctx.getSourceManager());
- PathDiagnosticPiece* P = new PathDiagnosticPiece(L, getDescription());
+
+ PathDiagnosticPiece* P =
+ new PathDiagnosticPiece(L, getDescription());
const SourceRange *Beg, *End;
getRanges(Beg, End);
@@ -74,34 +80,38 @@ BugDescription::getEndPath(ASTContext& Ctx, ExplodedNode<ValueState> *N) const {
return P;
}
-void BugDescription::getRanges(const SourceRange*& beg,
- const SourceRange*& end) const {
+void BugReport::getRanges(const SourceRange*& beg,
+ const SourceRange*& end) const {
beg = NULL;
end = NULL;
}
-void BugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, ASTContext& Ctx,
- const BugDescription& B,
- ExplodedGraph<GRExprEngine>& G,
- ExplodedNode<ValueState>* N,
- BugReporterHelper** BegHelpers,
- BugReporterHelper** EndHelpers) {
-
- if (PathDiagnosticPiece* Piece = B.getEndPath(Ctx,N))
+PathDiagnosticPiece* BugReport::VisitNode(ExplodedNode<ValueState>* N,
+ ExplodedNode<ValueState>* PrevN,
+ ExplodedGraph<ValueState>& G,
+ ASTContext& Ctx) {
+ return NULL;
+}
+
+void BugReporter::GeneratePathDiagnostic(PathDiagnostic& PD,
+ BugReport& R,
+ ExplodedNode<ValueState>* N) {
+
+ if (PathDiagnosticPiece* Piece = R.getEndPath(Ctx,N))
PD.push_back(Piece);
else
return;
SourceManager& SMgr = Ctx.getSourceManager();
- llvm::OwningPtr<ExplodedGraph<GRExprEngine> > GTrim(G.Trim(&N, &N+1));
+ llvm::OwningPtr<ExplodedGraph<ValueState> > GTrim(getGraph().Trim(&N, &N+1));
// Find the sink in the trimmed graph.
// FIXME: Should we eventually have a sink iterator?
ExplodedNode<ValueState>* NewN = 0;
- for (ExplodedGraph<GRExprEngine>::node_iterator
+ for (ExplodedGraph<ValueState>::node_iterator
I = GTrim->nodes_begin(), E = GTrim->nodes_end(); I != E; ++I) {
if (I->isSink()) {
@@ -292,13 +302,8 @@ void BugReporter::GeneratePathDiagnostic(PathDiagnostic& PD, ASTContext& Ctx,
}
}
else
- for (BugReporterHelper** I = BegHelpers; I != EndHelpers; ++I) {
-
- PathDiagnosticPiece* piece = (*I)->VisitNode(N, NextNode, G, Ctx);
-
- if (piece)
- PD.push_front(piece);
- }
+ if (PathDiagnosticPiece* piece = R.VisitNode(N, NextNode, *GTrim, Ctx))
+ PD.push_front(piece);
}
}
@@ -318,39 +323,30 @@ bool BugReporter::IsCached(ExplodedNode<ValueState>* N) {
return false;
}
-void BugReporter::EmitPathWarning(Diagnostic& Diag,
- PathDiagnosticClient* PDC,
- ASTContext& Ctx,
- const BugDescription& B,
- ExplodedGraph<GRExprEngine>& G,
- ExplodedNode<ValueState>* N,
- BugReporterHelper** BegHelpers,
- BugReporterHelper** EndHelpers) {
+void BugReporter::EmitPathWarning(BugReport& R, ExplodedNode<ValueState>* N) {
- if (!PDC) {
- EmitWarning(Diag, Ctx, B, N);
+ if (!PD) {
+ EmitWarning(R, N);
return;
}
if (IsCached(N))
return;
- PathDiagnostic D(B.getName());
- GeneratePathDiagnostic(D, Ctx, B, G, N, BegHelpers, EndHelpers);
+ PathDiagnostic D(R.getName());
+ GeneratePathDiagnostic(D, R, N);
if (!D.empty())
- PDC->HandlePathDiagnostic(D);
+ PD->HandlePathDiagnostic(D);
}
-void BugReporter::EmitWarning(Diagnostic& Diag, ASTContext& Ctx,
- const BugDescription& B,
- ExplodedNode<ValueState>* N) {
+void BugReporter::EmitWarning(BugReport& R, ExplodedNode<ValueState>* N) {
if (IsCached(N))
return;
std::ostringstream os;
- os << "[CHECKER] " << B.getDescription();
+ os << "[CHECKER] " << R.getDescription();
unsigned ErrorDiag = Diag.getCustomDiagID(Diagnostic::Warning,
os.str().c_str());
@@ -362,8 +358,8 @@ void BugReporter::EmitWarning(Diagnostic& Diag, ASTContext& Ctx,
if (!S)
return;
- SourceRange R = S->getSourceRange();
+ SourceRange Range = S->getSourceRange();
Diag.Report(FullSourceLoc(S->getLocStart(), Ctx.getSourceManager()),
- ErrorDiag, NULL, 0, &R, 1);
+ ErrorDiag, NULL, 0, &Range, 1);
}
diff --git a/clang/lib/Analysis/CFRefCount.cpp b/clang/lib/Analysis/CFRefCount.cpp
index d73b771b52a..501a3f5a056 100644
--- a/clang/lib/Analysis/CFRefCount.cpp
+++ b/clang/lib/Analysis/CFRefCount.cpp
@@ -792,7 +792,7 @@ CFRefCount::RefBindings CFRefCount::Update(RefBindings B, SymbolID sym,
namespace {
-class VISIBILITY_HIDDEN UseAfterRelease : public BugDescription {
+class VISIBILITY_HIDDEN UseAfterRelease : public BugType {
public:
virtual const char* getName() const {
@@ -804,7 +804,7 @@ public:
}
};
-class VISIBILITY_HIDDEN BadRelease : public BugDescription {
+class VISIBILITY_HIDDEN BadRelease : public BugType {
public:
virtual const char* getName() const {
@@ -831,14 +831,12 @@ void CheckCFRefCount(CFG& cfg, Decl& CD, ASTContext& Ctx,
return;
// FIXME: Refactor some day so this becomes a single function invocation.
-
- GRCoreEngine<GRExprEngine> Eng(cfg, CD, Ctx);
- GRExprEngine* CS = &Eng.getCheckerState();
+ GRExprEngine Eng(cfg, CD, Ctx);
CFRefCount TF;
- CS->setTransferFunctions(TF);
+ Eng.setTransferFunctions(TF);
Eng.ExecuteWorkList();
- // Emit warnings.
+ // FIXME: Emit warnings.
}
diff --git a/clang/lib/Analysis/GRExprEngine.cpp b/clang/lib/Analysis/GRExprEngine.cpp
index 36bae45cff8..6d4217774d3 100644
--- a/clang/lib/Analysis/GRExprEngine.cpp
+++ b/clang/lib/Analysis/GRExprEngine.cpp
@@ -14,6 +14,7 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
+#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Basic/SourceManager.h"
#include "llvm/Support/Streams.h"
@@ -40,6 +41,67 @@ using llvm::cast;
using llvm::APSInt;
+GRExprEngine::GRExprEngine(CFG& cfg, Decl& CD, ASTContext& Ctx)
+ : CoreEngine(cfg, CD, Ctx, *this),
+ G(CoreEngine.getGraph()),
+ Liveness(G.getCFG()),
+ Builder(NULL),
+ StateMgr(G.getContext(), G.getAllocator()),
+ BasicVals(StateMgr.getBasicValueFactory()),
+ TF(NULL), // FIXME
+ SymMgr(StateMgr.getSymbolManager()),
+ StmtEntryNode(NULL), CleanedState(NULL), CurrentStmt(NULL) {
+
+ // Compute liveness information.
+ Liveness.runOnCFG(G.getCFG());
+ Liveness.runOnAllBlocks(G.getCFG(), NULL, true);
+}
+
+GRExprEngine::~GRExprEngine() {
+ for (BugTypeSet::iterator I = BugTypes.begin(), E = BugTypes.end(); I!=E; ++I)
+ delete *I;
+
+ for (SimpleChecksTy::iterator I = CallChecks.begin(), E = CallChecks.end();
+ I != E; ++I)
+ delete *I;
+
+ for (SimpleChecksTy::iterator I=MsgExprChecks.begin(), E=MsgExprChecks.end();
+ I != E; ++I)
+ delete *I;
+}
+
+void GRExprEngine::EmitWarnings(Diagnostic& Diag, PathDiagnosticClient* PD) {
+ for (bug_type_iterator I = bug_types_begin(), E = bug_types_end(); I!=E; ++I){
+ BugReporter BR(Diag, PD, getContext(), *this);
+ (*I)->EmitWarnings(BR);
+ }
+
+ for (SimpleChecksTy::iterator I = CallChecks.begin(), E = CallChecks.end();
+ I != E; ++I) {
+ BugReporter BR(Diag, PD, getContext(), *this);
+ (*I)->EmitWarnings(BR);
+ }
+
+ for (SimpleChecksTy::iterator I=MsgExprChecks.begin(), E=MsgExprChecks.end();
+ I != E; ++I) {
+ BugReporter BR(Diag, PD, getContext(), *this);
+ (*I)->EmitWarnings(BR);
+ }
+}
+
+void GRExprEngine::setTransferFunctions(GRTransferFuncs* tf) {
+ TF = tf;
+ TF->RegisterChecks(*this);
+}
+
+void GRExprEngine::AddCallCheck(GRSimpleAPICheck* A) {
+ CallChecks.push_back(A);
+}
+
+void GRExprEngine::AddObjCMessageExprCheck(GRSimpleAPICheck* A) {
+ MsgExprChecks.push_back(A);
+}
+
ValueState* GRExprEngine::getInitialState() {
// The LiveVariables information already has a compilation of all VarDecls
diff --git a/clang/lib/Analysis/GRSimpleVals.cpp b/clang/lib/Analysis/GRSimpleVals.cpp
index d7ee5606a8e..e7b456ff21c 100644
--- a/clang/lib/Analysis/GRSimpleVals.cpp
+++ b/clang/lib/Analysis/GRSimpleVals.cpp
@@ -25,239 +25,315 @@
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, const BugType& D,
+ ITER I, ITER E) {
+
+ for (; I != E; ++I) {
+ BugReport R(D);
+ BR.EmitPathWarning(R, GetNode(I));
+ }
+}
+
+//===----------------------------------------------------------------------===//
// Bug Descriptions.
//===----------------------------------------------------------------------===//
namespace {
-class VISIBILITY_HIDDEN NullDeref : public BugDescription {
+class VISIBILITY_HIDDEN NullDeref : public BugType {
public:
virtual const char* getName() const {
return "null dereference";
}
+
virtual const char* getDescription() const {
return "Dereference of null pointer.";
}
-};
-class VISIBILITY_HIDDEN UndefDeref : public BugDescription {
+ virtual void EmitWarnings(BugReporter& BR) {
+ GRExprEngine& Eng = BR.getEngine();
+ GenericEmitWarnings(BR, *this, Eng.null_derefs_begin(),
+ Eng.null_derefs_end());
+ }
+};
+
+class VISIBILITY_HIDDEN UndefDeref : public BugType {
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 = BR.getEngine();
+ GenericEmitWarnings(BR, *this, Eng.undef_derefs_begin(),
+ Eng.undef_derefs_end());
+ }
};
-class VISIBILITY_HIDDEN UndefBranch : public BugDescription {
+class VISIBILITY_HIDDEN UndefBranch : public BugType {
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) {
+ GRExprEngine& Eng = BR.getEngine();
+ GenericEmitWarnings(BR, *this, Eng.undef_branches_begin(),
+ Eng.undef_branches_end());
+ }
};
-
-class VISIBILITY_HIDDEN DivZero : public BugDescription {
+
+class VISIBILITY_HIDDEN DivZero : public BugType {
public:
virtual const char* getName() const {
return "divide-by-zero";
}
+
virtual const char* getDescription() const {
return "Division by zero/undefined value.";
}
-};
-class VISIBILITY_HIDDEN UndefResult : public BugDescription {
+ virtual void EmitWarnings(BugReporter& BR) {
+ GRExprEngine& Eng = BR.getEngine();
+ GenericEmitWarnings(BR, *this, Eng.explicit_bad_divides_begin(),
+ Eng.explicit_bad_divides_end());
+ }
+};
+
+class VISIBILITY_HIDDEN UndefResult : public BugType {
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 = BR.getEngine();
+ GenericEmitWarnings(BR, *this, Eng.undef_results_begin(),
+ Eng.undef_results_begin());
+ }
};
-class VISIBILITY_HIDDEN BadCall : public BugDescription {
+class VISIBILITY_HIDDEN BadCall : public BugType {
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 = BR.getEngine();
+ GenericEmitWarnings(BR, *this, Eng.bad_calls_begin(),
+ Eng.bad_calls_begin());
+ }
};
-class VISIBILITY_HIDDEN BadArg : public BugDescription {
- SourceRange R;
+
+class VISIBILITY_HIDDEN BadArg : public BugType {
+protected:
+
+ class Report : public BugReport {
+ const SourceRange R;
+ public:
+ Report(BugType& D, Expr* E) : BugReport(D), R(E->getSourceRange()) {}
+ virtual ~Report() {}
+
+ virtual void getRanges(const SourceRange*& B, const SourceRange*& E) const {
+ B = &R;
+ E = B+1;
+ }
+ };
+
public:
- BadArg(Expr *E) {
- R = E->getSourceRange();
- }
+
+ 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 getRanges(const SourceRange*& B, const SourceRange*& E) const {
- B = &R;
- E = B+1;
+ }
+
+ virtual void EmitWarnings(BugReporter& BR) {
+ GRExprEngine& Eng = 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.
+ Report report(*this, I->second);
+
+ // Emit the warning.
+ BR.EmitPathWarning(report, I->first);
+ }
+
}
};
-
+
class VISIBILITY_HIDDEN BadMsgExprArg : public BadArg {
public:
- BadMsgExprArg(Expr *E) : BadArg(E) {}
-
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 = BR.getEngine();
+
+ for (GRExprEngine::UndefArgsTy::iterator I=Eng.msg_expr_undef_arg_begin(),
+ E = Eng.msg_expr_undef_arg_begin(); I!=E; ++I) {
+
+ // Generate a report for this bug.
+ Report report(*this, I->second);
+
+ // Emit the warning.
+ BR.EmitPathWarning(report, I->first);
+ }
+
+ }
};
-class VISIBILITY_HIDDEN BadReceiver : public BugDescription {
- SourceRange R;
-public:
- BadReceiver(ExplodedNode<ValueState>* N) {
- Stmt *S = cast<PostStmt>(N->getLocation()).getStmt();
- Expr* E = cast<ObjCMessageExpr>(S)->getReceiver();
- assert (E && "Receiver cannot be NULL");
- R = E->getSourceRange();
- }
+class VISIBILITY_HIDDEN BadReceiver : public BugType {
+ class Report : public BugReport {
+ SourceRange R;
+ public:
+ Report(BugType& D, ExplodedNode<ValueState> *N) : BugReport(D) {
+ Stmt *S = cast<PostStmt>(N->getLocation()).getStmt();
+ Expr* E = cast<ObjCMessageExpr>(S)->getReceiver();
+ assert (E && "Receiver cannot be NULL");
+ R = E->getSourceRange();
+ }
+
+ virtual ~Report() {}
+
+ virtual void getRanges(const SourceRange*& B, const SourceRange*& E) const {
+ B = &R;
+ E = B+1;
+ }
+ };
+
+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 getRanges(const SourceRange*& B, const SourceRange*& E) const {
- B = &R;
- E = B+1;
+ virtual void EmitWarnings(BugReporter& BR) {
+ GRExprEngine& Eng = BR.getEngine();
+
+ for (GRExprEngine::UndefReceiversTy::iterator I=Eng.undef_receivers_begin(),
+ E = Eng.undef_receivers_end(); I!=E; ++I) {
+
+ // Generate a report for this bug.
+ Report report(*this, *I);
+
+ // Emit the warning.
+ BR.EmitPathWarning(report, *I);
+ }
}
};
-class VISIBILITY_HIDDEN RetStack : public BugDescription {
+class VISIBILITY_HIDDEN RetStack : public BugType {
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 = BR.getEngine();
+ GenericEmitWarnings(BR, *this, Eng.ret_stackaddr_begin(),
+ Eng.ret_stackaddr_begin());
+ }
};
} // end anonymous namespace
+
+void GRSimpleVals::RegisterChecks(GRExprEngine& Eng) {
+ 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());
-//===----------------------------------------------------------------------===//
-// Utility functions.
-//===----------------------------------------------------------------------===//
-
-template <typename ITERATOR> inline
-ExplodedNode<ValueState>* GetNode(ITERATOR I) {
- return *I;
-}
+ // Add extra checkers.
-template <> inline
-ExplodedNode<ValueState>* GetNode(GRExprEngine::undef_arg_iterator I) {
- return I->first;
+ GRSimpleAPICheck* FoundationCheck =
+ CreateBasicObjCFoundationChecks(Eng.getContext(), &Eng.getStateManager());
+
+ Eng.AddObjCMessageExprCheck(FoundationCheck);
}
//===----------------------------------------------------------------------===//
// Analysis Driver.
//===----------------------------------------------------------------------===//
-template <typename ITERATOR>
-void EmitWarning(Diagnostic& Diag, PathDiagnosticClient* PD,
- ASTContext& Ctx, BugReporter& BR,
- const BugDescription& Desc,
- ExplodedGraph<GRExprEngine>& G,
- ITERATOR I, ITERATOR E) {
-
- for (; I != E; ++I)
- BR.EmitPathWarning(Diag, PD, Ctx, Desc, G, GetNode(I));
-}
-
namespace clang {
unsigned RunGRSimpleVals(CFG& cfg, Decl& CD, ASTContext& Ctx,
Diagnostic& Diag, PathDiagnosticClient* PD,
bool Visualize, bool TrimGraph) {
-
- GRCoreEngine<GRExprEngine> Eng(cfg, CD, Ctx);
- GRExprEngine* CS = &Eng.getCheckerState();
+
+ // Construct the analysis engine.
+ GRExprEngine Eng(cfg, CD, Ctx);
// Set base transfer functions.
GRSimpleVals GRSV;
- CS->setTransferFunctions(GRSV);
-
- // Add extra checkers.
- llvm::OwningPtr<GRSimpleAPICheck> FoundationCheck(
- CreateBasicObjCFoundationChecks(Ctx, &CS->getStateManager()));
-
- CS->AddObjCMessageExprCheck(FoundationCheck.get());
+ Eng.setTransferFunctions(GRSV);
// Execute the worklist algorithm.
- Eng.ExecuteWorkList(120000);
-
- BugReporter BR;
- ExplodedGraph<GRExprEngine>& G = Eng.getGraph();
+ Eng.ExecuteWorkList();
- EmitWarning(Diag, PD, Ctx, BR, NullDeref(), G,
- CS->null_derefs_begin(), CS->null_derefs_end());
-
-
- EmitWarning(Diag, PD, Ctx, BR, UndefDeref(), G,
- CS->undef_derefs_begin(), CS->undef_derefs_end());
-
- EmitWarning(Diag, PD, Ctx, BR, UndefBranch(), G,
- CS->undef_branches_begin(), CS->undef_branches_end());
-
- EmitWarning(Diag, PD, Ctx, BR, DivZero(), G,
- CS->explicit_bad_divides_begin(), CS->explicit_bad_divides_end());
-
- EmitWarning(Diag, PD, Ctx, BR, UndefResult(), G,
- CS->undef_results_begin(), CS->undef_results_end());
-
- EmitWarning(Diag, PD, Ctx, BR, BadCall(), G,
- CS->bad_calls_begin(), CS->bad_calls_end());
-
- for (GRExprEngine::UndefArgsTy::iterator I = CS->undef_arg_begin(),
- E = CS->undef_arg_end(); I!=E; ++I) {
-
- BadArg Desc(I->second);
- BR.EmitPathWarning(Diag, PD, Ctx, Desc, G, I->first);
- }
-
- for (GRExprEngine::UndefArgsTy::iterator I = CS->msg_expr_undef_arg_begin(),
- E = CS->msg_expr_undef_arg_end(); I!=E; ++I) {
-
- BadMsgExprArg Desc(I->second);
- BR.EmitPathWarning(Diag, PD, Ctx, Desc, G, I->first);
- }
-
- for (GRExprEngine::UndefReceiversTy::iterator I = CS->undef_receivers_begin(),
- E = CS->undef_receivers_end(); I!=E; ++I) {
-
- BadReceiver Desc(*I);
- BR.EmitPathWarning(Diag, PD, Ctx, Desc, G, *I);
- }
-
- EmitWarning(Diag, PD, Ctx, BR, RetStack(), G,
- CS->ret_stackaddr_begin(), CS->ret_stackaddr_end());
-
+ // Display warnings.
+ Eng.EmitWarnings(Diag, PD);
- FoundationCheck.get()->ReportResults(Diag, PD, Ctx, BR, G);
#ifndef NDEBUG
- if (Visualize) CS->ViewGraph(TrimGraph);
+ if (Visualize) Eng.ViewGraph(TrimGraph);
#endif
return Eng.getGraph().size();
diff --git a/clang/lib/Analysis/GRSimpleVals.h b/clang/lib/Analysis/GRSimpleVals.h
index 74f7fd81ea7..cd6016bba28 100644
--- a/clang/lib/Analysis/GRSimpleVals.h
+++ b/clang/lib/Analysis/GRSimpleVals.h
@@ -29,6 +29,8 @@ public:
GRSimpleVals() {}
virtual ~GRSimpleVals() {}
+ virtual void RegisterChecks(GRExprEngine& Eng);
+
// Casts.
virtual RVal EvalCast(GRExprEngine& Engine, NonLVal V, QualType CastT);
OpenPOWER on IntegriCloud