Added recording of "implicit" NULL dereferences of symbolic pointers.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@46843 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/Analysis/GRConstants.cpp b/Analysis/GRConstants.cpp
index 399dacc..44c5d51 100644
--- a/Analysis/GRConstants.cpp
+++ b/Analysis/GRConstants.cpp
@@ -124,6 +124,12 @@
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(); }
@@ -162,6 +168,10 @@
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.
@@ -203,8 +213,10 @@
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) {
@@ -237,7 +249,7 @@
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.
@@ -557,13 +569,16 @@
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,
@@ -756,7 +771,34 @@
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;
}
@@ -1208,6 +1250,11 @@
<< (void*) L.getStmt() << ' ';
L.getStmt()->printPretty(Out);
+
+ if (GraphPrintCheckerState->isImplicitNullDeref(N)) {
+ Out << "\\|Implicit-Null Dereference.\\l";
+ }
+
break;
}