diff options
Diffstat (limited to 'clang/lib/Analysis/GRSimpleVals.cpp')
-rw-r--r-- | clang/lib/Analysis/GRSimpleVals.cpp | 308 |
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(); |