forked from OSchip/llvm-project
Implement second part of PR 2600: NSError** parameter may be null, and should be checked before being dereferenced.
llvm-svn: 56318
This commit is contained in:
parent
c38b3fbc4c
commit
b42f482c91
|
@ -77,6 +77,8 @@ public:
|
|||
|
||||
const std::pair<RVal, RVal>&
|
||||
getPersistentRValPair(const RVal& V1, const RVal& V2);
|
||||
|
||||
const RVal* getPersistentRVal(RVal X);
|
||||
};
|
||||
|
||||
} // end clang namespace
|
||||
|
|
|
@ -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(); }
|
||||
|
|
|
@ -43,12 +43,25 @@ namespace clang {
|
|||
|
||||
class GRStateManager;
|
||||
class GRTransferFuncs;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// GRStateTrait - Traits used by the Generic Data Map of a GRState.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
template <typename T> struct GRStatePartialTrait;
|
||||
|
||||
template <typename T> 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<typename T> 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<GRState*> {
|
||||
|
@ -566,8 +585,7 @@ public:
|
|||
|
||||
void printDOT(std::ostream& Out) const;
|
||||
};
|
||||
|
||||
|
||||
|
||||
} // end clang namespace
|
||||
|
||||
#endif
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include "clang/AST/DeclObjC.h"
|
||||
#include "clang/AST/Expr.h"
|
||||
#include "llvm/ADT/StringExtras.h"
|
||||
#include <sstream>
|
||||
|
||||
using namespace clang;
|
||||
|
||||
bool QualType::isConstant(ASTContext& Ctx) const {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Reference in New Issue