summaryrefslogtreecommitdiffstats
path: root/clang/lib/Analysis/GRSimpleVals.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/Analysis/GRSimpleVals.cpp')
-rw-r--r--clang/lib/Analysis/GRSimpleVals.cpp308
1 files changed, 192 insertions, 116 deletions
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();
OpenPOWER on IntegriCloud