Refactor DereferenceChecker to use only the new Checker API instead of

the old builder API.  This percolated a bunch of changes up to the
Checker class (where CheckLocation has been renamed VisitLocation) and
GRExprEngine.  ProgramPoint now has the notion of a "LocationCheck"
point (with PreLoad and PreStore respectively), and a bunch of the old
ProgramPoints that are no longer used have been removed.

llvm-svn: 86798
This commit is contained in:
Ted Kremenek 2009-11-11 03:26:34 +00:00
parent 598825e832
commit 5e1f78aeb1
10 changed files with 284 additions and 303 deletions

View File

@ -39,22 +39,19 @@ class CheckerContext {
SaveAndRestore<const void*> OldTag;
SaveAndRestore<ProgramPoint::Kind> OldPointKind;
SaveOr OldHasGen;
const GRState *state;
public:
CheckerContext(ExplodedNodeSet &dst,
GRStmtNodeBuilder &builder,
GRExprEngine &eng,
ExplodedNode *pred,
const void *tag, bool preVisit)
CheckerContext(ExplodedNodeSet &dst, GRStmtNodeBuilder &builder,
GRExprEngine &eng, ExplodedNode *pred,
const void *tag, ProgramPoint::Kind K,
const GRState *st = 0)
: Dst(dst), B(builder), Eng(eng), Pred(pred),
OldSink(B.BuildSinks), OldTag(B.Tag),
OldPointKind(B.PointKind), OldHasGen(B.HasGeneratedNode) {
//assert(Dst.empty()); // This is a fake assertion.
// See GRExprEngine::CheckerVisit(), CurrSet is repeatedly used.
B.Tag = tag;
if (preVisit)
B.PointKind = ProgramPoint::PreStmtKind;
}
OldSink(B.BuildSinks),
OldTag(B.Tag, tag),
OldPointKind(B.PointKind, K),
OldHasGen(B.HasGeneratedNode),
state(st) {}
~CheckerContext() {
if (!B.BuildSinks && !B.HasGeneratedNode)
@ -72,7 +69,7 @@ public:
ExplodedNodeSet &getNodeSet() { return Dst; }
GRStmtNodeBuilder &getNodeBuilder() { return B; }
ExplodedNode *&getPredecessor() { return Pred; }
const GRState *getState() { return B.GetState(Pred); }
const GRState *getState() { return state ? state : B.GetState(Pred); }
ASTContext &getASTContext() {
return Eng.getContext();
@ -113,43 +110,54 @@ class Checker {
private:
friend class GRExprEngine;
// FIXME: Remove the 'tag' option.
void GR_Visit(ExplodedNodeSet &Dst,
GRStmtNodeBuilder &Builder,
GRExprEngine &Eng,
const Stmt *stmt,
const Stmt *S,
ExplodedNode *Pred, void *tag, bool isPrevisit) {
CheckerContext C(Dst, Builder, Eng, Pred, tag, isPrevisit);
CheckerContext C(Dst, Builder, Eng, Pred, tag,
isPrevisit ? ProgramPoint::PreStmtKind :
ProgramPoint::PostStmtKind);
assert(isPrevisit && "Only previsit supported for now.");
_PreVisit(C, stmt);
_PreVisit(C, S);
}
// FIXME: Remove the 'tag' option.
void GR_VisitBind(ExplodedNodeSet &Dst,
GRStmtNodeBuilder &Builder, GRExprEngine &Eng,
const Stmt *AssignE,
const Stmt *StoreE, ExplodedNode *Pred, void *tag,
SVal location, SVal val,
bool isPrevisit) {
CheckerContext C(Dst, Builder, Eng, Pred, tag, isPrevisit);
CheckerContext C(Dst, Builder, Eng, Pred, tag,
isPrevisit ? ProgramPoint::PreStmtKind :
ProgramPoint::PostStmtKind);
assert(isPrevisit && "Only previsit supported for now.");
PreVisitBind(C, AssignE, StoreE, location, val);
}
// FIXME: Remove the 'tag' option.
void GR_VisitLocation(ExplodedNodeSet &Dst,
GRStmtNodeBuilder &Builder,
GRExprEngine &Eng,
const Stmt *S,
ExplodedNode *Pred, const GRState *state,
SVal location,
void *tag, bool isLoad) {
CheckerContext C(Dst, Builder, Eng, Pred, tag,
isLoad ? ProgramPoint::PreLoadKind :
ProgramPoint::PreStoreKind, state);
VisitLocation(C, S, location);
}
public:
virtual ~Checker() {}
virtual void _PreVisit(CheckerContext &C, const Stmt *ST) {}
// This is a previsit which takes a node returns a node.
virtual ExplodedNode *CheckLocation(const Stmt *S, ExplodedNode *Pred,
const GRState *state, SVal V,
GRExprEngine &Eng) {
return Pred;
}
virtual void PreVisitBind(CheckerContext &C,
const Stmt *AssignE, const Stmt *StoreE,
SVal location, SVal val) {}
virtual void VisitLocation(CheckerContext &C, const Stmt *S, SVal location) {}
virtual void PreVisitBind(CheckerContext &C, const Stmt *AssignE,
const Stmt *StoreE, SVal location, SVal val) {}
};
} // end clang namespace
#endif

View File

@ -16,38 +16,16 @@
#ifndef LLVM_CLANG_DEREFCHECKER
#define LLVM_CLANG_DEREFCHECKER
#include "clang/Analysis/PathSensitive/Checker.h"
#include "clang/Analysis/PathSensitive/BugType.h"
#include <utility>
namespace clang {
class GRExprEngine;
class ExplodedNode;
class NullDerefChecker : public Checker {
BuiltinBug *BT;
llvm::SmallVector<ExplodedNode*, 2> ImplicitNullDerefNodes;
public:
NullDerefChecker() : BT(0) {}
ExplodedNode *CheckLocation(const Stmt *S, ExplodedNode *Pred,
const GRState *state, SVal V,GRExprEngine &Eng);
static void *getTag();
typedef llvm::SmallVectorImpl<ExplodedNode*>::iterator iterator;
iterator implicit_nodes_begin() { return ImplicitNullDerefNodes.begin(); }
iterator implicit_nodes_end() { return ImplicitNullDerefNodes.end(); }
};
class UndefDerefChecker : public Checker {
BuiltinBug *BT;
public:
UndefDerefChecker() : BT(0) {}
ExplodedNode *CheckLocation(const Stmt *S, ExplodedNode *Pred,
const GRState *state, SVal V, GRExprEngine &Eng);
static void *getTag();
};
std::pair<ExplodedNode * const *, ExplodedNode * const *>
GetImplicitNullDereferences(GRExprEngine &Eng);
} // end clang namespace
#endif

View File

@ -556,16 +556,21 @@ protected:
bool atDeclInit = false);
public:
// FIXME: 'tag' should be removed, and a LocationContext should be used
// instead.
void EvalLoad(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred,
const GRState* St, SVal location, const void *tag = 0);
ExplodedNode* EvalLocation(Stmt* Ex, ExplodedNode* Pred,
// FIXME: 'tag' should be removed, and a LocationContext should be used
// instead.
void EvalLocation(ExplodedNodeSet &Dst, Stmt *S, ExplodedNode* Pred,
const GRState* St, SVal location,
const void *tag = 0);
const void *tag, bool isLoad);
// FIXME: 'tag' should be removed, and a LocationContext should be used
// instead.
void EvalStore(ExplodedNodeSet& Dst, Expr* AssignE, Expr* StoreE,
ExplodedNode* Pred,
const GRState* St, SVal TargetLV, SVal Val,
ExplodedNode* Pred, const GRState* St, SVal TargetLV, SVal Val,
const void *tag = 0);
};

View File

@ -33,13 +33,10 @@ public:
BlockEntranceKind,
BlockExitKind,
PreStmtKind,
// Keep the following together and in this order.
PostStmtKind,
PostLocationChecksSucceedKind,
PostOutOfBoundsCheckFailedKind,
PostNullCheckFailedKind,
PostUndefLocationCheckFailedKind,
PreLoadKind,
PostLoadKind,
PreStoreKind,
PostStoreKind,
PostPurgeDeadSymbolsKind,
PostStmtCustomKind,
@ -194,17 +191,6 @@ public:
}
};
class PostLocationChecksSucceed : public PostStmt {
public:
PostLocationChecksSucceed(const Stmt* S, const LocationContext *L,
const void *tag = 0)
: PostStmt(S, PostLocationChecksSucceedKind, L, tag) {}
static bool classof(const ProgramPoint* Location) {
return Location->getKind() == PostLocationChecksSucceedKind;
}
};
class PostStmtCustom : public PostStmt {
public:
PostStmtCustom(const Stmt* S,
@ -226,36 +212,36 @@ public:
}
};
class PostOutOfBoundsCheckFailed : public PostStmt {
class LocationCheck : public StmtPoint {
protected:
LocationCheck(const Stmt *S, const LocationContext *L,
ProgramPoint::Kind K, const void *tag)
: StmtPoint(S, NULL, K, L, tag) {}
static bool classof(const ProgramPoint *location) {
unsigned k = location->getKind();
return k == PreLoadKind || PreStoreKind;
}
};
class PreLoad : public LocationCheck {
public:
PostOutOfBoundsCheckFailed(const Stmt* S, const LocationContext *L,
const void *tag = 0)
: PostStmt(S, PostOutOfBoundsCheckFailedKind, L, tag) {}
static bool classof(const ProgramPoint* Location) {
return Location->getKind() == PostOutOfBoundsCheckFailedKind;
PreLoad(const Stmt *S, const LocationContext *L, const void *tag = 0)
: LocationCheck(S, L, PreLoadKind, tag) {}
static bool classof(const ProgramPoint *location) {
return location->getKind() == PreLoadKind;
}
};
class PostUndefLocationCheckFailed : public PostStmt {
class PreStore : public LocationCheck {
public:
PostUndefLocationCheckFailed(const Stmt* S, const LocationContext *L,
const void *tag = 0)
: PostStmt(S, PostUndefLocationCheckFailedKind, L, tag) {}
static bool classof(const ProgramPoint* Location) {
return Location->getKind() == PostUndefLocationCheckFailedKind;
}
};
class PostNullCheckFailed : public PostStmt {
public:
PostNullCheckFailed(const Stmt* S, const LocationContext *L,
const void *tag = 0)
: PostStmt(S, PostNullCheckFailedKind, L, tag) {}
static bool classof(const ProgramPoint* Location) {
return Location->getKind() == PostNullCheckFailedKind;
PreStore(const Stmt *S, const LocationContext *L, const void *tag = 0)
: LocationCheck(S, L, PreStoreKind, tag) {}
static bool classof(const ProgramPoint *location) {
return location->getKind() == PreStoreKind;
}
};

View File

@ -13,99 +13,103 @@
//===----------------------------------------------------------------------===//
#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h"
#include "clang/Analysis/PathSensitive/Checker.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "GRExprEngineInternalChecks.h"
using namespace clang;
void *NullDerefChecker::getTag() {
static int x = 0;
return &x;
namespace {
class VISIBILITY_HIDDEN DereferenceChecker : public Checker {
BuiltinBug *BT_null;
BuiltinBug *BT_undef;
llvm::SmallVector<ExplodedNode*, 2> ImplicitNullDerefNodes;
public:
DereferenceChecker() : BT_null(0), BT_undef(0) {}
static void *getTag() { static int tag = 0; return &tag; }
void VisitLocation(CheckerContext &C, const Stmt *S, SVal location);
std::pair<ExplodedNode * const*, ExplodedNode * const*>
getImplicitNodes() const {
return std::make_pair(ImplicitNullDerefNodes.data(),
ImplicitNullDerefNodes.data() +
ImplicitNullDerefNodes.size());
}
};
} // end anonymous namespace
void clang::RegisterDereferenceChecker(GRExprEngine &Eng) {
Eng.registerCheck(new DereferenceChecker());
}
ExplodedNode *NullDerefChecker::CheckLocation(const Stmt *S, ExplodedNode *Pred,
const GRState *state, SVal V,
GRExprEngine &Eng) {
Loc *LV = dyn_cast<Loc>(&V);
// If the value is not a location, don't touch the node.
if (!LV)
return Pred;
const GRState *NotNullState = state->Assume(*LV, true);
const GRState *NullState = state->Assume(*LV, false);
GRStmtNodeBuilder &Builder = Eng.getBuilder();
BugReporter &BR = Eng.getBugReporter();
// The explicit NULL case.
if (NullState) {
// Use the GDM to mark in the state what lval was null.
const SVal *PersistentLV = Eng.getBasicVals().getPersistentSVal(*LV);
NullState = NullState->set<GRState::NullDerefTag>(PersistentLV);
ExplodedNode *N = Builder.generateNode(S, NullState, Pred,
ProgramPoint::PostNullCheckFailedKind);
std::pair<ExplodedNode * const *, ExplodedNode * const *>
clang::GetImplicitNullDereferences(GRExprEngine &Eng) {
DereferenceChecker *checker = Eng.getChecker<DereferenceChecker>();
if (!checker)
return std::make_pair((ExplodedNode * const *) 0,
(ExplodedNode * const *) 0);
return checker->getImplicitNodes();
}
void DereferenceChecker::VisitLocation(CheckerContext &C, const Stmt *S,
SVal l) {
// Check for dereference of an undefined value.
if (l.isUndef()) {
ExplodedNode *N = C.GenerateNode(S, true);
if (N) {
N->markAsSink();
if (!BT_undef)
BT_undef = new BuiltinBug("Dereference of undefined pointer value");
if (!NotNullState) { // Explicit null case.
if (!BT)
BT = new BuiltinBug("Null dereference","Dereference of null pointer");
EnhancedBugReport *report =
new EnhancedBugReport(*BT_undef, BT_undef->getDescription().c_str(), N);
report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
bugreporter::GetDerefExpr(N));
C.EmitReport(report);
}
return;
}
DefinedOrUnknownSVal location = cast<DefinedOrUnknownSVal>(l);
// Check for null dereferences.
if (!isa<Loc>(location))
return;
const GRState *state = C.getState();
const GRState *notNullState, *nullState;
llvm::tie(notNullState, nullState) = state->Assume(location);
// The explicit NULL case.
if (nullState) {
// Generate an error node.
ExplodedNode *N = C.GenerateNode(S, nullState, true);
if (N) {
if (!notNullState) {
// We know that 'location' cannot be non-null. This is what
// we call an "explicit" null dereference.
if (!BT_null)
BT_null = new BuiltinBug("Null pointer dereference",
"Dereference of null pointer");
EnhancedBugReport *R =
new EnhancedBugReport(*BT, BT->getDescription().c_str(), N);
EnhancedBugReport *report =
new EnhancedBugReport(*BT_null, BT_null->getDescription().c_str(), N);
report->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
bugreporter::GetDerefExpr(N));
C.EmitReport(report);
return;
}
R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
bugreporter::GetDerefExpr(N));
BR.EmitReport(R);
return 0;
} else // Implicit null case.
ImplicitNullDerefNodes.push_back(N);
// Otherwise, we have the case where the location could either be
// null or not-null. Record the error node as an "implicit" null
// dereference.
ImplicitNullDerefNodes.push_back(N);
}
}
if (!NotNullState)
return 0;
return Builder.generateNode(S, NotNullState, Pred,
ProgramPoint::PostLocationChecksSucceedKind);
// From this point forward, we know that the location is not null.
assert(notNullState);
C.addTransition(state != nullState ? C.GenerateNode(S, notNullState) :
C.getPredecessor());
}
void *UndefDerefChecker::getTag() {
static int x = 0;
return &x;
}
ExplodedNode *UndefDerefChecker::CheckLocation(const Stmt *S,
ExplodedNode *Pred,
const GRState *state, SVal V,
GRExprEngine &Eng) {
GRStmtNodeBuilder &Builder = Eng.getBuilder();
BugReporter &BR = Eng.getBugReporter();
if (V.isUndef()) {
ExplodedNode *N = Builder.generateNode(S, state, Pred,
ProgramPoint::PostUndefLocationCheckFailedKind);
if (N) {
N->markAsSink();
if (!BT)
BT = new BuiltinBug(0, "Undefined dereference",
"Dereference of undefined pointer value");
EnhancedBugReport *R =
new EnhancedBugReport(*BT, BT->getDescription().c_str(), N);
R->addVisitorCreator(bugreporter::registerTrackNullOrUndefValue,
bugreporter::GetDerefExpr(N));
BR.EmitReport(R);
}
return 0;
}
return Pred;
}

View File

@ -418,51 +418,38 @@ void GRStmtNodeBuilder::GenerateAutoTransition(ExplodedNode* N) {
Eng.WList->Enqueue(Succ, B, Idx+1);
}
static inline PostStmt GetPostLoc(const Stmt* S, ProgramPoint::Kind K,
const LocationContext *L, const void *tag) {
static ProgramPoint GetProgramPoint(const Stmt *S, ProgramPoint::Kind K,
const LocationContext *LC, const void *tag){
switch (K) {
default:
assert(false && "Invalid PostXXXKind.");
assert(false && "Unhandled ProgramPoint kind");
case ProgramPoint::PreStmtKind:
return PreStmt(S, LC, tag);
case ProgramPoint::PostStmtKind:
return PostStmt(S, L, tag);
return PostStmt(S, LC, tag);
case ProgramPoint::PreLoadKind:
return PreLoad(S, LC, tag);
case ProgramPoint::PostLoadKind:
return PostLoad(S, L, tag);
case ProgramPoint::PostUndefLocationCheckFailedKind:
return PostUndefLocationCheckFailed(S, L, tag);
case ProgramPoint::PostLocationChecksSucceedKind:
return PostLocationChecksSucceed(S, L, tag);
case ProgramPoint::PostOutOfBoundsCheckFailedKind:
return PostOutOfBoundsCheckFailed(S, L, tag);
case ProgramPoint::PostNullCheckFailedKind:
return PostNullCheckFailed(S, L, tag);
return PostLoad(S, LC, tag);
case ProgramPoint::PreStoreKind:
return PreStore(S, LC, tag);
case ProgramPoint::PostStoreKind:
return PostStore(S, L, tag);
return PostStore(S, LC, tag);
case ProgramPoint::PostLValueKind:
return PostLValue(S, L, tag);
return PostLValue(S, LC, tag);
case ProgramPoint::PostPurgeDeadSymbolsKind:
return PostPurgeDeadSymbols(S, L, tag);
return PostPurgeDeadSymbols(S, LC, tag);
}
}
ExplodedNode*
GRStmtNodeBuilder::generateNodeInternal(const Stmt* S, const GRState* State,
GRStmtNodeBuilder::generateNodeInternal(const Stmt* S, const GRState* state,
ExplodedNode* Pred,
ProgramPoint::Kind K,
const void *tag) {
return K == ProgramPoint::PreStmtKind
? generateNodeInternal(PreStmt(S, Pred->getLocationContext(),tag),
State, Pred)
: generateNodeInternal(GetPostLoc(S, K, Pred->getLocationContext(), tag),
State, Pred);
const ProgramPoint &L = GetProgramPoint(S, K, Pred->getLocationContext(),tag);
return generateNodeInternal(L, state, Pred);
}
ExplodedNode*

View File

@ -1190,68 +1190,87 @@ void GRExprEngine::EvalStore(ExplodedNodeSet& Dst, Expr *AssignE,
assert(Builder && "GRStmtNodeBuilder must be defined.");
// Evaluate the location (checks for bad dereferences).
Pred = EvalLocation(StoreE, Pred, state, location, tag);
ExplodedNodeSet Tmp;
EvalLocation(Tmp, StoreE, Pred, state, location, tag, false);
if (!Pred)
if (Tmp.empty())
return;
assert (!location.isUndef());
state = GetState(Pred);
assert(!location.isUndef());
SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind,
ProgramPoint::PostStoreKind);
SaveAndRestore<const void*> OldTag(Builder->Tag, tag);
// Proceed with the store.
SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind);
SaveAndRestore<const void*> OldTag(Builder->Tag);
Builder->PointKind = ProgramPoint::PostStoreKind;
Builder->Tag = tag;
EvalBind(Dst, AssignE, StoreE, Pred, state, location, Val);
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI)
EvalBind(Dst, AssignE, StoreE, *NI, GetState(*NI), location, Val);
}
void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr* Ex, ExplodedNode* Pred,
void GRExprEngine::EvalLoad(ExplodedNodeSet& Dst, Expr *Ex, ExplodedNode* Pred,
const GRState* state, SVal location,
const void *tag) {
// Evaluate the location (checks for bad dereferences).
Pred = EvalLocation(Ex, Pred, state, location, tag);
ExplodedNodeSet Tmp;
EvalLocation(Tmp, Ex, Pred, state, location, tag, true);
if (!Pred)
if (Tmp.empty())
return;
state = GetState(Pred);
assert(!location.isUndef());
SaveAndRestore<ProgramPoint::Kind> OldSPointKind(Builder->PointKind);
SaveAndRestore<const void*> OldTag(Builder->Tag);
// Proceed with the load.
ProgramPoint::Kind K = ProgramPoint::PostLoadKind;
if (location.isUnknown()) {
// This is important. We must nuke the old binding.
MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, UnknownVal()),
K, tag);
}
else {
SVal V = state->getSVal(cast<Loc>(location), Ex->getType());
MakeNode(Dst, Ex, Pred, state->BindExpr(Ex, V), K, tag);
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
state = GetState(*NI);
if (location.isUnknown()) {
// This is important. We must nuke the old binding.
MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, UnknownVal()),
ProgramPoint::PostLoadKind, tag);
}
else {
SVal V = state->getSVal(cast<Loc>(location), Ex->getType());
MakeNode(Dst, Ex, *NI, state->BindExpr(Ex, V), ProgramPoint::PostLoadKind,
tag);
}
}
}
ExplodedNode* GRExprEngine::EvalLocation(Stmt* Ex, ExplodedNode* Pred,
const GRState* state, SVal location,
const void *tag) {
void GRExprEngine::EvalLocation(ExplodedNodeSet &Dst, Stmt *S,
ExplodedNode* Pred,
const GRState* state, SVal location,
const void *tag, bool isLoad) {
SaveAndRestore<const void*> OldTag(Builder->Tag);
Builder->Tag = tag;
if (location.isUnknown() || Checkers.empty())
return Pred;
for (CheckersOrdered::iterator I=Checkers.begin(), E=Checkers.end(); I!=E;++I)
{
Pred = I->second->CheckLocation(Ex, Pred, state, location, *this);
if (!Pred)
break;
if (location.isUnknown() || Checkers.empty()) {
Dst.Add(Pred);
return;
}
ExplodedNodeSet Src, Tmp;
Src.Add(Pred);
ExplodedNodeSet *PrevSet = &Src;
for (CheckersOrdered::iterator I=Checkers.begin(),E=Checkers.end(); I!=E; ++I)
{
ExplodedNodeSet *CurrSet = (I+1 == E) ? &Dst
: (PrevSet == &Tmp) ? &Src : &Tmp;
CurrSet->clear();
void *tag = I->first;
Checker *checker = I->second;
for (ExplodedNodeSet::iterator NI = PrevSet->begin(), NE = PrevSet->end();
NI != NE; ++NI)
checker->GR_VisitLocation(*CurrSet, *Builder, *this, S, *NI, state,
location, tag, isLoad);
// Update which NodeSet is the current one.
PrevSet = CurrSet;
}
return Pred;
// FIXME: Temporarily disable out-of-bounds checking until we make
// the logic reflect recent changes to CastRegion and friends.
#if 0
@ -1746,46 +1765,47 @@ void GRExprEngine::VisitObjCForCollectionStmtAux(ObjCForCollectionStmt* S,
ExplodedNode* Pred, ExplodedNodeSet& Dst,
SVal ElementV) {
// Get the current state. Use 'EvalLocation' to determine if it is a null
// pointer, etc.
// Check if the location we are writing back to is a null pointer.
Stmt* elem = S->getElement();
Pred = EvalLocation(elem, Pred, GetState(Pred), ElementV);
if (!Pred)
ExplodedNodeSet Tmp;
EvalLocation(Tmp, elem, Pred, GetState(Pred), ElementV, NULL, false);
if (Tmp.empty())
return;
for (ExplodedNodeSet::iterator NI=Tmp.begin(), NE=Tmp.end(); NI!=NE; ++NI) {
Pred = *NI;
const GRState *state = GetState(Pred);
const GRState *state = GetState(Pred);
// Handle the case where the container still has elements.
SVal TrueV = ValMgr.makeTruthVal(1);
const GRState *hasElems = state->BindExpr(S, TrueV);
// Handle the case where the container still has elements.
SVal TrueV = ValMgr.makeTruthVal(1);
const GRState *hasElems = state->BindExpr(S, TrueV);
// Handle the case where the container has no elements.
SVal FalseV = ValMgr.makeTruthVal(0);
const GRState *noElems = state->BindExpr(S, FalseV);
// Handle the case where the container has no elements.
SVal FalseV = ValMgr.makeTruthVal(0);
const GRState *noElems = state->BindExpr(S, FalseV);
if (loc::MemRegionVal* MV = dyn_cast<loc::MemRegionVal>(&ElementV))
if (const TypedRegion* R = dyn_cast<TypedRegion>(MV->getRegion())) {
// FIXME: The proper thing to do is to really iterate over the
// container. We will do this with dispatch logic to the store.
// For now, just 'conjure' up a symbolic value.
QualType T = R->getValueType(getContext());
assert(Loc::IsLocType(T));
unsigned Count = Builder->getCurrentBlockCount();
SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count);
SVal V = ValMgr.makeLoc(Sym);
hasElems = hasElems->bindLoc(ElementV, V);
if (loc::MemRegionVal* MV = dyn_cast<loc::MemRegionVal>(&ElementV))
if (const TypedRegion* R = dyn_cast<TypedRegion>(MV->getRegion())) {
// FIXME: The proper thing to do is to really iterate over the
// container. We will do this with dispatch logic to the store.
// For now, just 'conjure' up a symbolic value.
QualType T = R->getValueType(getContext());
assert (Loc::IsLocType(T));
unsigned Count = Builder->getCurrentBlockCount();
SymbolRef Sym = SymMgr.getConjuredSymbol(elem, T, Count);
SVal V = ValMgr.makeLoc(Sym);
hasElems = hasElems->bindLoc(ElementV, V);
// Bind the location to 'nil' on the false branch.
SVal nilV = ValMgr.makeIntVal(0, T);
noElems = noElems->bindLoc(ElementV, nilV);
}
// Bind the location to 'nil' on the false branch.
SVal nilV = ValMgr.makeIntVal(0, T);
noElems = noElems->bindLoc(ElementV, nilV);
}
// Create the new nodes.
MakeNode(Dst, S, Pred, hasElems);
MakeNode(Dst, S, Pred, noElems);
// Create the new nodes.
MakeNode(Dst, S, Pred, hasElems);
MakeNode(Dst, S, Pred, noElems);
}
}
//===----------------------------------------------------------------------===//
@ -2920,10 +2940,6 @@ struct VISIBILITY_HIDDEN DOTGraphTraits<ExplodedNode*> :
Out << "\\lPostStore\\l";
else if (isa<PostLValue>(Loc))
Out << "\\lPostLValue\\l";
else if (isa<PostLocationChecksSucceed>(Loc))
Out << "\\lPostLocationChecksSucceed\\l";
else if (isa<PostNullCheckFailed>(Loc))
Out << "\\lPostNullCheckFailed\\l";
if (GraphPrintCheckerState->isImplicitNullDeref(N))
Out << "\\|Implicit-Null Dereference.\\l";

View File

@ -16,7 +16,6 @@
#include "clang/Analysis/PathSensitive/BugReporter.h"
#include "clang/Analysis/PathSensitive/GRExprEngine.h"
#include "clang/Analysis/PathSensitive/CheckerVisitor.h"
#include "clang/Analysis/PathSensitive/Checkers/DereferenceChecker.h"
#include "clang/Analysis/PathSensitive/Checkers/BadCallChecker.h"
#include "clang/Analysis/PathSensitive/Checkers/UndefinedArgChecker.h"
#include "clang/Analysis/PathSensitive/Checkers/UndefinedAssignmentChecker.h"
@ -405,9 +404,8 @@ void GRExprEngine::RegisterInternalChecks() {
registerCheck(new UndefinedArgChecker());
registerCheck(new UndefinedAssignmentChecker());
registerCheck(new BadCallChecker());
registerCheck(new UndefDerefChecker());
registerCheck(new NullDerefChecker());
RegisterDereferenceChecker(*this);
RegisterVLASizeChecker(*this);
RegisterDivZeroChecker(*this);
RegisterReturnStackAddressChecker(*this);

View File

@ -19,6 +19,7 @@ namespace clang {
class GRExprEngine;
void RegisterDereferenceChecker(GRExprEngine &Eng);
void RegisterDivZeroChecker(GRExprEngine &Eng);
void RegisterReturnPointerRangeChecker(GRExprEngine &Eng);
void RegisterReturnStackAddressChecker(GRExprEngine &Eng);
@ -28,5 +29,6 @@ void RegisterPointerSubChecker(GRExprEngine &Eng);
void RegisterPointerArithChecker(GRExprEngine &Eng);
void RegisterFixedAddressChecker(GRExprEngine &Eng);
void RegisterCastToStructChecker(GRExprEngine &Eng);
} // end clang namespace
#endif

View File

@ -209,15 +209,12 @@ void NSErrorChecker::CheckParamDeref(const VarDecl *Param,
return;
// Iterate over the implicit-null dereferences.
NullDerefChecker *Checker = Eng.getChecker<NullDerefChecker>();
assert(Checker && "NullDerefChecker not exist.");
for (NullDerefChecker::iterator I = Checker->implicit_nodes_begin(),
E = Checker->implicit_nodes_end(); I != E; ++I) {
ExplodedNode *const* I, *const* E;
llvm::tie(I, E) = GetImplicitNullDereferences(Eng);
for ( ; I != E; ++I) {
const GRState *state = (*I)->getState();
const SVal* X = state->get<GRState::NullDerefTag>();
if (!X || X->getAsSymbol() != ParamSym)
SVal location = state->getSVal((*I)->getLocationAs<StmtPoint>()->getStmt());
if (location.getAsSymbol() != ParamSym)
continue;
// Emit an error.