From 78d46242e3351484c2b773f5610beba5d316914b Mon Sep 17 00:00:00 2001 From: Ted Kremenek Date: Tue, 22 Jul 2008 16:21:24 +0000 Subject: [PATCH] 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 --- Driver/AnalysisConsumer.cpp | 15 +- include/clang/Analysis/LocalCheckers.h | 4 +- .../Analysis/PathSensitive/GRExprEngine.h | 2 + lib/Analysis/BasicObjCFoundationChecks.cpp | 15 + lib/Analysis/CFRefCount.cpp | 9 +- lib/Analysis/GRExprEngineInternalChecks.cpp | 332 +++++++++++++++ lib/Analysis/GRSimpleVals.cpp | 394 ------------------ lib/Analysis/GRSimpleVals.h | 2 - 8 files changed, 364 insertions(+), 409 deletions(-) create mode 100644 lib/Analysis/GRExprEngineInternalChecks.cpp diff --git a/Driver/AnalysisConsumer.cpp b/Driver/AnalysisConsumer.cpp index 45e0918ce0..deb7a85006 100644 --- a/Driver/AnalysisConsumer.cpp +++ b/Driver/AnalysisConsumer.cpp @@ -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 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(); @@ -326,14 +332,13 @@ static void ActionGRExprEngine(AnalysisManager& mgr, GRTransferFuncs* tf) { } static void ActionCheckerCFRefAux(AnalysisManager& mgr, bool GCEnabled, - bool StandardWarnings) { - + bool StandardWarnings) { + GRTransferFuncs* TF = MakeCFRefCountTF(mgr.getContext(), GCEnabled, - StandardWarnings, mgr.getLangOptions()); - ActionGRExprEngine(mgr, TF); + ActionGRExprEngine(mgr, TF, StandardWarnings); } static void ActionCheckerCFRef(AnalysisManager& mgr) { diff --git a/include/clang/Analysis/LocalCheckers.h b/include/clang/Analysis/LocalCheckers.h index a8669d30a7..8da144ebce 100644 --- a/include/clang/Analysis/LocalCheckers.h +++ b/include/clang/Analysis/LocalCheckers.h @@ -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 diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h index 0a0516e602..e9a36af295 100644 --- a/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -220,6 +220,8 @@ public: BugTypes.push_back(B); } + void RegisterInternalChecks(); + void EmitWarnings(BugReporterData& BRData); bool isRetStackAddr(const NodeTy* N) const { diff --git a/lib/Analysis/BasicObjCFoundationChecks.cpp b/lib/Analysis/BasicObjCFoundationChecks.cpp index 37cfc280b8..7009e38425 100644 --- a/lib/Analysis/BasicObjCFoundationChecks.cpp +++ b/lib/Analysis/BasicObjCFoundationChecks.cpp @@ -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); +} diff --git a/lib/Analysis/CFRefCount.cpp b/lib/Analysis/CFRefCount.cpp index bd9ac40f98..edcddd22a5 100644 --- a/lib/Analysis/CFRefCount.cpp +++ b/lib/Analysis/CFRefCount.cpp @@ -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); } diff --git a/lib/Analysis/GRExprEngineInternalChecks.cpp b/lib/Analysis/GRExprEngineInternalChecks.cpp new file mode 100644 index 0000000000..c1128ccd1c --- /dev/null +++ b/lib/Analysis/GRExprEngineInternalChecks.cpp @@ -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 inline +ExplodedNode* GetNode(ITERATOR I) { + return *I; +} + +template <> inline +ExplodedNode* 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(BR).getEngine()); + } + + template + 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* N = *I; + Stmt *S = cast(N->getLocation()).getStmt(); + Expr* E = cast(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(*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((*I)->getLocation()); + Expr* Ex = cast(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 *N = *(*I)->pred_begin(); + ProgramPoint P = N->getLocation(); + + const ValueState* St = (*I)->getState(); + + if (PostStmt* PS = dyn_cast(&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 Reports; + +public: + CheckAttrNonNull() : + BT("'nonnull' argument passed null", + "Null pointer passed as an argument to a 'nonnull' parameter") {} + + virtual bool Audit(ExplodedNode* N, ValueStateManager& VMgr) { + CallExpr* CE = cast(cast(N->getLocation()).getStmt()); + const ValueState* state = N->getState(); + + RVal X = VMgr.GetRVal(state, CE->getCallee()); + + if (!isa(X)) + return false; + + FunctionDecl* FD = dyn_cast(cast(X).getDecl()); + const NonNullAttr* Att = FD->getAttr(); + + 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::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); +} diff --git a/lib/Analysis/GRSimpleVals.cpp b/lib/Analysis/GRSimpleVals.cpp index 38327cbad5..3952520064 100644 --- a/lib/Analysis/GRSimpleVals.cpp +++ b/lib/Analysis/GRSimpleVals.cpp @@ -26,400 +26,6 @@ using namespace clang; -//===----------------------------------------------------------------------===// -// Utility functions. -//===----------------------------------------------------------------------===// - -template inline -ExplodedNode* GetNode(ITERATOR I) { - return *I; -} - -template <> inline -ExplodedNode* GetNode(GRExprEngine::undef_arg_iterator I) { - return I->first; -} - -template -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(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(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(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(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(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(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(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(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* N = *I; - Stmt *S = cast(N->getLocation()).getStmt(); - Expr* E = cast(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(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(*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(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((*I)->getLocation()); - Expr* Ex = cast(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 *N = *(*I)->pred_begin(); - ProgramPoint P = N->getLocation(); - - const ValueState* St = (*I)->getState(); - - if (PostStmt* PS = dyn_cast(&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 Reports; - -public: - CheckAttrNonNull() : - BT("'nonnull' argument passed null", - "Null pointer passed as an argument to a 'nonnull' parameter") {} - - - virtual bool Audit(ExplodedNode* N, ValueStateManager& VMgr) { - CallExpr* CE = cast(cast(N->getLocation()).getStmt()); - const ValueState* state = N->getState(); - - RVal X = VMgr.GetRVal(state, CE->getCallee()); - - if (!isa(X)) - return false; - - FunctionDecl* FD = dyn_cast(cast(X).getDecl()); - const NonNullAttr* Att = FD->getAttr(); - - 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::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. //===----------------------------------------------------------------------===// diff --git a/lib/Analysis/GRSimpleVals.h b/lib/Analysis/GRSimpleVals.h index ac07f8b324..8ad4958345 100644 --- a/lib/Analysis/GRSimpleVals.h +++ b/lib/Analysis/GRSimpleVals.h @@ -35,8 +35,6 @@ public: GRSimpleVals() {} virtual ~GRSimpleVals() {} - virtual void RegisterChecks(GRExprEngine& Eng); - // Casts. virtual RVal EvalCast(GRExprEngine& Engine, NonLVal V, QualType CastT); -- 2.40.0