diff options
author | Ted Kremenek <kremenek@apple.com> | 2008-09-18 23:09:54 +0000 |
---|---|---|
committer | Ted Kremenek <kremenek@apple.com> | 2008-09-18 23:09:54 +0000 |
commit | 7360fda1efd88fd28ca2882579676dbd8569c181 (patch) | |
tree | 923c21a0fa78f3ce6a44f56489f01e5e8c29adaf /lib/Analysis | |
parent | 644f5fc35c9d093b2ae1e8f43cf5a70680b5945a (diff) |
Implement second part of PR 2600: NSError** parameter may be null, and should be checked before being dereferenced.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@56318 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Analysis')
-rw-r--r-- | lib/Analysis/BasicValueFactory.cpp | 5 | ||||
-rw-r--r-- | lib/Analysis/CheckNSError.cpp | 48 | ||||
-rw-r--r-- | lib/Analysis/GRExprEngine.cpp | 7 | ||||
-rw-r--r-- | lib/Analysis/GRState.cpp | 6 |
4 files changed, 65 insertions, 1 deletions
diff --git a/lib/Analysis/BasicValueFactory.cpp b/lib/Analysis/BasicValueFactory.cpp index 8d737a9472..a9bb2cec4b 100644 --- a/lib/Analysis/BasicValueFactory.cpp +++ b/lib/Analysis/BasicValueFactory.cpp @@ -247,3 +247,8 @@ BasicValueFactory::getPersistentRValPair(const RVal& V1, const RVal& V2) { return P->getValue(); } +const RVal* BasicValueFactory::getPersistentRVal(RVal X) { + return &getPersistentRValWithData(X, 0).first; +} + + diff --git a/lib/Analysis/CheckNSError.cpp b/lib/Analysis/CheckNSError.cpp index 4c7f2cf25d..d39fa0a86a 100644 --- a/lib/Analysis/CheckNSError.cpp +++ b/lib/Analysis/CheckNSError.cpp @@ -37,9 +37,16 @@ class VISIBILITY_HIDDEN NSErrorCheck : public BugTypeCacheLocation { bool CheckArgument(QualType ArgTy, IdentifierInfo* NSErrorII); + void CheckParamDeref(VarDecl* V, GRStateRef state, GRExprEngine& Eng, + GRBugReporter& BR); + + const char* desc; public: + NSErrorCheck() : desc(0) {} + void EmitWarnings(BugReporter& BR) { EmitGRWarnings(cast<GRBugReporter>(BR));} const char* getName() const { return "NSError** null dereference"; } + const char* getDescription() const { return desc; } }; } // end anonymous namespace @@ -77,6 +84,14 @@ void NSErrorCheck::EmitGRWarnings(GRBugReporter& BR) { CodeDecl.getLocation()); } + + // Scan the NSError** parameters for an implicit null dereference. + for (llvm::SmallVectorImpl<VarDecl*>::iterator I=Params.begin(), + E=Params.end(); I!=E; ++I) + for (GRExprEngine::GraphTy::roots_iterator RI=G.roots_begin(), + RE=G.roots_end(); RI!=RE; ++RI) + CheckParamDeref(*I, GRStateRef((*RI)->getState(), Eng.getStateManager()), + Eng, BR); } void NSErrorCheck::CheckSignature(ObjCMethodDecl& M, QualType& ResultTy, @@ -104,3 +119,36 @@ bool NSErrorCheck::CheckArgument(QualType ArgTy, IdentifierInfo* NSErrorII) { if (!IT) return false; return IT->getDecl()->getIdentifier() == NSErrorII; } + +void NSErrorCheck::CheckParamDeref(VarDecl* Param, GRStateRef rootState, + GRExprEngine& Eng, GRBugReporter& BR) { + + RVal ParamRVal = rootState.GetRVal(lval::DeclVal(Param)); + + // FIXME: For now assume that ParamRVal is symbolic. We need to generalize + // this later. + lval::SymbolVal* SV = dyn_cast<lval::SymbolVal>(&ParamRVal); + if (!SV) return; + + // Iterate over the implicit-null dereferences. + for (GRExprEngine::null_deref_iterator I=Eng.implicit_null_derefs_begin(), + E=Eng.implicit_null_derefs_end(); I!=E; ++I) { + + GRStateRef state = GRStateRef((*I)->getState(), Eng.getStateManager()); + const RVal* X = state.get<GRState::NullDerefTag>(); + const lval::SymbolVal* SVX = dyn_cast_or_null<lval::SymbolVal>(X); + if (!SVX || SVX->getSymbol() != SV->getSymbol()) continue; + + // Emit an error. + BugReport R(*this, *I); + + std::string msg; + llvm::raw_string_ostream os(msg); + os << "Potential null dereference. According to coding standards in " + "'Creating and Returning NSError Objects' the parameter '" + << Param->getName() << "' may be null."; + desc = os.str().c_str(); + + BR.EmitWarning(R); + } +} diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index aa5ab6af7f..8d6fea7f7c 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -1010,10 +1010,15 @@ const GRState* GRExprEngine::EvalLocation(Expr* Ex, NodeTy* Pred, // "Assume" that the pointer is NULL. bool isFeasibleNull = false; - const GRState* StNull = Assume(St, LV, false, isFeasibleNull); + GRStateRef StNull = GRStateRef(Assume(St, LV, false, isFeasibleNull), + getStateManager()); if (isFeasibleNull) { + // Use the Generic Data Map to mark in the state what lval was null. + const RVal* PersistentLV = getBasicVals().getPersistentRVal(LV); + StNull = StNull.set<GRState::NullDerefTag>(PersistentLV); + // We don't use "MakeNode" here because the node will be a sink // and we have no intention of processing it later. diff --git a/lib/Analysis/GRState.cpp b/lib/Analysis/GRState.cpp index 4bef72c6c5..67bff39fc8 100644 --- a/lib/Analysis/GRState.cpp +++ b/lib/Analysis/GRState.cpp @@ -261,3 +261,9 @@ bool GRStateManager::isEqual(const GRState* state, Expr* Ex, bool GRStateManager::isEqual(const GRState* state, Expr* Ex, uint64_t x) { return isEqual(state, Ex, BasicVals.getValue(x, Ex->getType())); } + +//===----------------------------------------------------------------------===// +// Persistent values for indexing into the Generic Data Map. + +int GRState::NullDerefTag::TagInt = 0; + |