diff --git a/clang/include/clang/Analysis/PathSensitive/BasicValueFactory.h b/clang/include/clang/Analysis/PathSensitive/BasicValueFactory.h index c3729ed53e2a..29957a7996f9 100644 --- a/clang/include/clang/Analysis/PathSensitive/BasicValueFactory.h +++ b/clang/include/clang/Analysis/PathSensitive/BasicValueFactory.h @@ -77,6 +77,8 @@ public: const std::pair& getPersistentRValPair(const RVal& V1, const RVal& V2); + + const RVal* getPersistentRVal(RVal X); }; } // end clang namespace diff --git a/clang/include/clang/Analysis/PathSensitive/GRExprEngine.h b/clang/include/clang/Analysis/PathSensitive/GRExprEngine.h index d08e442e35c7..1a288c24afcb 100644 --- a/clang/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/clang/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -293,6 +293,13 @@ public: null_deref_iterator null_derefs_begin() { return ExplicitNullDeref.begin(); } null_deref_iterator null_derefs_end() { return ExplicitNullDeref.end(); } + null_deref_iterator implicit_null_derefs_begin() { + return ImplicitNullDeref.begin(); + } + null_deref_iterator implicit_null_derefs_end() { + return ImplicitNullDeref.end(); + } + typedef BadDerefTy::iterator undef_deref_iterator; undef_deref_iterator undef_derefs_begin() { return UndefDeref.begin(); } undef_deref_iterator undef_derefs_end() { return UndefDeref.end(); } diff --git a/clang/include/clang/Analysis/PathSensitive/GRState.h b/clang/include/clang/Analysis/PathSensitive/GRState.h index 993977984ff6..fd81a86946fa 100644 --- a/clang/include/clang/Analysis/PathSensitive/GRState.h +++ b/clang/include/clang/Analysis/PathSensitive/GRState.h @@ -43,12 +43,25 @@ namespace clang { class GRStateManager; class GRTransferFuncs; + +//===----------------------------------------------------------------------===// +// GRStateTrait - Traits used by the Generic Data Map of a GRState. +//===----------------------------------------------------------------------===// +template struct GRStatePartialTrait; + +template struct GRStateTrait { + typedef typename T::data_type data_type; + static inline void* GDMIndex() { return &T::TagInt; } + static inline void* MakeVoidPtr(data_type D) { return (void*) D; } + static inline data_type MakeData(void* const* P) { + return P ? (data_type) *P : (data_type) 0; + } +}; + //===----------------------------------------------------------------------===// // GRState- An ImmutableMap type Stmt*/Decl*/Symbols to RVals. //===----------------------------------------------------------------------===// - -template struct GRStateTrait; /// GRState - This class encapsulates the actual data values for /// for a "state" in our symbolic value tracking. It is intended to be @@ -169,7 +182,13 @@ public: void print(std::ostream& Out, StoreManager& StoreMgr, ConstraintManager& ConstraintMgr, Printer **Beg = 0, Printer **End = 0, - const char* nl = "\n", const char *sep = "") const; + const char* nl = "\n", const char *sep = "") const; + + // Tags used for the Generic Data Map. + struct NullDerefTag { + static int TagInt; + typedef const RVal* data_type; + }; }; template<> struct GRTrait { @@ -566,8 +585,7 @@ public: void printDOT(std::ostream& Out) const; }; - - + } // end clang namespace #endif diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp index f836e5b9951c..e35525df9c53 100644 --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -17,7 +17,7 @@ #include "clang/AST/DeclObjC.h" #include "clang/AST/Expr.h" #include "llvm/ADT/StringExtras.h" -#include + using namespace clang; bool QualType::isConstant(ASTContext& Ctx) const { diff --git a/clang/lib/Analysis/BasicValueFactory.cpp b/clang/lib/Analysis/BasicValueFactory.cpp index 8d737a9472de..a9bb2cec4bda 100644 --- a/clang/lib/Analysis/BasicValueFactory.cpp +++ b/clang/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/clang/lib/Analysis/CheckNSError.cpp b/clang/lib/Analysis/CheckNSError.cpp index 4c7f2cf25d1a..d39fa0a86a2a 100644 --- a/clang/lib/Analysis/CheckNSError.cpp +++ b/clang/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(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::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(&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(); + const lval::SymbolVal* SVX = dyn_cast_or_null(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/clang/lib/Analysis/GRExprEngine.cpp b/clang/lib/Analysis/GRExprEngine.cpp index aa5ab6af7fa0..8d6fea7f7c76 100644 --- a/clang/lib/Analysis/GRExprEngine.cpp +++ b/clang/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(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/clang/lib/Analysis/GRState.cpp b/clang/lib/Analysis/GRState.cpp index 4bef72c6c5c0..67bff39fc8c8 100644 --- a/clang/lib/Analysis/GRState.cpp +++ b/clang/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; +