typedef llvm::SmallPtrSet<NodeTy*,5> UninitBranchesTy;
UninitBranchesTy UninitBranches;
+ /// ImplicitNullDeref - Nodes in the ExplodedGraph that result from
+ /// taking a dereference on a symbolic pointer that may be NULL.
+ typedef llvm::SmallPtrSet<NodeTy*,5> ImplicitNullDerefTy;
+ ImplicitNullDerefTy ImplicitNullDeref;
+
+
bool StateCleaned;
ASTContext& getContext() const { return G.getContext(); }
bool isUninitControlFlow(const NodeTy* N) const {
return N->isSink() && UninitBranches.count(const_cast<NodeTy*>(N)) != 0;
}
+
+ bool isImplicitNullDeref(const NodeTy* N) const {
+ return N->isSink() && ImplicitNullDeref.count(const_cast<NodeTy*>(N)) != 0;
+ }
/// ProcessStmt - Called by GREngine. Used to generate new successor
/// nodes by processing the 'effects' of a block-level statement.
return GetValue(St, const_cast<Stmt*>(S));
}
- inline RValue GetValue(const StateTy& St, const LValue& LV) {
- return StateMgr.GetValue(St, LV);
+ inline RValue GetValue(const StateTy& St, const LValue& LV,
+ QualType* T = NULL) {
+
+ return StateMgr.GetValue(St, LV, T);
}
inline LValue GetLValue(const StateTy& St, Stmt* S) {
StateTy AssumeSymInt(StateTy St, bool Assumption, const SymIntConstraint& C,
bool& isFeasible);
- void Nodify(NodeSet& Dst, Stmt* S, NodeTy* Pred, StateTy St);
+ NodeTy* Nodify(NodeSet& Dst, Stmt* S, NodeTy* Pred, StateTy St);
/// Nodify - This version of Nodify is used to batch process a set of states.
/// The states are not guaranteed to be unique.
return M;
}
-void GRConstants::Nodify(NodeSet& Dst, Stmt* S, NodeTy* Pred, StateTy St) {
+GRConstants::NodeTy*
+GRConstants::Nodify(NodeSet& Dst, Stmt* S, NodeTy* Pred, StateTy St) {
// If the state hasn't changed, don't generate a new node.
if (St == Pred->getState())
- return;
+ return NULL;
- Dst.Add(Builder->generateNode(S, St, Pred));
+ NodeTy* N = Builder->generateNode(S, St, Pred);
+ Dst.Add(N);
+ return N;
}
void GRConstants::Nodify(NodeSet& Dst, Stmt* S, NodeTy* Pred,
const RValue& V = GetValue(St, U->getSubExpr());
const LValue& L1 = cast<LValue>(V);
- Nodify(Dst, U, N1, SetValue(St, U, GetValue(St, L1)));
+ // After a dereference, one of two possible situations arise:
+ // (1) A crash, because the pointer was NULL.
+ // (2) The pointer is not NULL, and the dereference works.
+ //
+ // We add these assumptions.
+
+ bool isFeasible;
+
+ // "Assume" that the pointer is NULL.
+ StateTy StNull = Assume(St, L1, false, isFeasible);
+
+ if (isFeasible) {
+ NodeTy* NullNode = Nodify(Dst, U, N1, StNull);
+ if (NullNode) {
+ NullNode->markAsSink();
+ ImplicitNullDeref.insert(NullNode);
+ }
+ }
+
+ // "Assume" that the pointer is Not-NULL.
+ StateTy StNotNull = Assume(St, L1, true, isFeasible);
+
+ if (isFeasible) {
+ QualType T = U->getType();
+ Nodify(Dst, U, N1, SetValue(StNotNull, U,
+ GetValue(StNotNull, L1, &T)));
+ }
+
break;
}
<< (void*) L.getStmt() << ' ';
L.getStmt()->printPretty(Out);
+
+ if (GraphPrintCheckerState->isImplicitNullDeref(N)) {
+ Out << "\\|Implicit-Null Dereference.\\l";
+ }
+
break;
}
//===----------------------------------------------------------------------===//
SymbolID SymbolManager::getSymbol(ParmVarDecl* D) {
- SymbolID& X = DataToSymbol[D];
+ SymbolID& X = DataToSymbol[getKey(D)];
if (!X.isInitialized()) {
X = SymbolToData.size();
- SymbolToData.push_back(D);
+ SymbolToData.push_back(SymbolDataParmVar(D));
}
return X;
}
+SymbolID SymbolManager::getContentsOfSymbol(SymbolID sym) {
+ SymbolID& X = DataToSymbol[getKey(sym)];
+
+ if (!X.isInitialized()) {
+ X = SymbolToData.size();
+ SymbolToData.push_back(SymbolDataContentsOf(sym));
+ }
+
+ return X;
+}
+
QualType SymbolData::getType() const {
switch (getKind()) {
default:
assert (false && "getType() not implemented for this symbol.");
case ParmKind:
- return static_cast<ParmVarDecl*>(getPtr())->getType();
+ return cast<SymbolDataParmVar>(this)->getDecl()->getType();
+
}
}
}
}
-#if 0
+
void LValue::print(std::ostream& Out) const {
switch (getSubKind()) {
case lval::ConcreteIntKind:
break;
}
}
-#endif
+
}
};
+ // SymbolData: Used to record meta data about symbols.
+
class SymbolData {
+public:
+ enum Kind { UninitKind, ParmKind, ContentsOfKind };
+
+private:
uintptr_t Data;
+ Kind K;
+
+protected:
+ SymbolData(uintptr_t D, Kind k) : Data(D), K(k) {}
+ SymbolData(void* D, Kind k) : Data(reinterpret_cast<uintptr_t>(D)), K(k) {}
+
+ void* getPtr() const {
+ assert (K != UninitKind);
+ return reinterpret_cast<void*>(Data);
+ }
+
+ uintptr_t getInt() const {
+ assert (K != UninitKind);
+ return Data;
+ }
+
public:
- enum Kind { ParmKind = 0x0, Mask = 0x3 };
+ SymbolData() : Data(0), K(UninitKind) {}
- SymbolData(ParmVarDecl* D)
- : Data(reinterpret_cast<uintptr_t>(D) | ParmKind) {}
+ Kind getKind() const { return K; }
+
+ inline bool operator==(const SymbolData& R) const {
+ return K == R.K && Data == R.Data;
+ }
- inline Kind getKind() const { return (Kind) (Data & Mask); }
- inline void* getPtr() const { return reinterpret_cast<void*>(Data & ~Mask); }
- inline bool operator==(const SymbolData& R) const { return Data == R.Data; }
+ QualType getType() const;
- QualType getType() const;
+ // Implement isa<T> support.
+ static inline bool classof(const SymbolData*) { return true; }
};
+
+class SymbolDataParmVar : public SymbolData {
+public:
+ SymbolDataParmVar(ParmVarDecl* VD) : SymbolData(VD, ParmKind) {}
+
+ ParmVarDecl* getDecl() const { return (ParmVarDecl*) getPtr(); }
+
+ // Implement isa<T> support.
+ static inline bool classof(const SymbolData* D) {
+ return D->getKind() == ParmKind;
+ }
+};
+
+class SymbolDataContentsOf : public SymbolData {
+public:
+ SymbolDataContentsOf(SymbolID ID) : SymbolData(ID, ContentsOfKind) {}
+
+ SymbolID getSymbol() const { return (SymbolID) getInt(); }
+ // Implement isa<T> support.
+ static inline bool classof(const SymbolData* D) {
+ return D->getKind() == ContentsOfKind;
+ }
+};
+
+ // Constraints on symbols. Usually wrapped by RValues.
class SymIntConstraint : public llvm::FoldingSetNode {
SymbolID Symbol;
typedef llvm::DenseMap<void*,SymbolID> MapTy;
MapTy DataToSymbol;
+ void* getKey(void* P) const {
+ return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(P) | 0x1);
+ }
+
+ void* getKey(SymbolID sym) const {
+ return reinterpret_cast<void*>((uintptr_t) (sym << 1));
+ }
+
public:
SymbolManager();
~SymbolManager();
SymbolID getSymbol(ParmVarDecl* D);
+ SymbolID getContentsOfSymbol(SymbolID sym);
- inline SymbolData getSymbolData(SymbolID ID) const {
+ inline const SymbolData& getSymbolData(SymbolID ID) const {
assert (ID < SymbolToData.size());
return SymbolToData[ID];
}
} // end clang namespace
-//==------------------------------------------------------------------------==//
-// Casting machinery to get cast<> and dyn_cast<> working with SymbolData.
-//==------------------------------------------------------------------------==//
-
-namespace llvm {
-
- template<> inline bool
- isa<clang::ParmVarDecl,clang::SymbolData>(const clang::SymbolData& V) {
- return V.getKind() == clang::SymbolData::ParmKind;
- }
-
- template<> struct cast_retty_impl<clang::ParmVarDecl,clang::SymbolData> {
- typedef const clang::ParmVarDecl* ret_type;
- };
-
- template<> struct simplify_type<clang::SymbolData> {
- typedef void* SimpleType;
- static inline SimpleType getSimplifiedValue(const clang::SymbolData &V) {
- return V.getPtr();
- }
- };
-
-} // end llvm namespace
-
//==------------------------------------------------------------------------==//
// Base RValue types.
//==------------------------------------------------------------------------==//
NonLValue NE(ValueManager& ValMgr, const LValue& RHS) const;
public:
-// void print(std::ostream& Out) const;
+ void print(std::ostream& Out) const;
RValue EvalBinaryOp(ValueManager& ValMgr, BinaryOperator::Opcode Op,
const LValue& RHS) const;
-RValue ValueStateManager::GetValue(const StateTy& St, const LValue& LV) {
+RValue ValueStateManager::GetValue(const StateTy& St, const LValue& LV,
+ QualType* T) {
if (isa<InvalidValue>(LV))
return InvalidValue();
return T ? T->getValue().second : InvalidValue();
}
+
+ // FIXME: We should bind how far a "ContentsOf" will go...
+
+ case lval::SymbolValKind: {
+ const lval::SymbolVal& SV = cast<lval::SymbolVal>(LV);
+ assert (T);
+
+ if (T->getTypePtr()->isPointerType())
+ return lval::SymbolVal(SymMgr.getContentsOfSymbol(SV.getSymbol()));
+ else
+ return nonlval::SymbolVal(SymMgr.getContentsOfSymbol(SV.getSymbol()));
+ }
+
default:
assert (false && "Invalid LValue.");
break;
StateTy SetValue(StateTy St, const LValue& LV, const RValue& V);
RValue GetValue(const StateTy& St, Stmt* S, bool* hasVal = NULL);
- RValue GetValue(const StateTy& St, const LValue& LV);
+ RValue GetValue(const StateTy& St, const LValue& LV, QualType* T = NULL);
LValue GetLValue(const StateTy& St, Stmt* S);