[cfe-commits] r50443 - in /cfe/trunk: include/clang/Analysis/PathSensitive/GRCoreEngine.h include/clang/Analysis/PathSensitive/GRExprEngine.h include/clang/Analysis/PathSensitive/ValueState.h include/clang/Analysis/ProgramPoint.h lib/Analysis/GRCoreEngine.cpp lib/Analysis/GRExprEngine.cpp lib/Analysis/ValueState.cpp
Ted Kremenek
kremenek at apple.com
Tue Apr 29 14:04:26 PDT 2008
Author: kremenek
Date: Tue Apr 29 16:04:26 2008
New Revision: 50443
URL: http://llvm.org/viewvc/llvm-project?rev=50443&view=rev
Log:
Major rewrite/refactoring of static analysis engine. We now use
EvalStore/EvalLoad to handle all loads/stores from symbolic memory, allowing us
to do checks for null dereferences, etc., at any arbitrary load/store (these
were missed checks before). This also resulted in some major cleanups, some
conceptual, and others just in the structure of the code.
This temporarily introduces a regression in the test suite (null-deref-ps.c)
before I add a new LVal type for structure fields.
Modified:
cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h
cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h
cfe/trunk/include/clang/Analysis/PathSensitive/ValueState.h
cfe/trunk/include/clang/Analysis/ProgramPoint.h
cfe/trunk/lib/Analysis/GRCoreEngine.cpp
cfe/trunk/lib/Analysis/GRExprEngine.cpp
cfe/trunk/lib/Analysis/ValueState.cpp
Modified: cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h?rev=50443&r1=50442&r2=50443&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/GRCoreEngine.h Tue Apr 29 16:04:26 2008
@@ -151,12 +151,14 @@
}
ExplodedNodeImpl* generateNodeImpl(Stmt* S, void* State,
- ExplodedNodeImpl* Pred);
+ ExplodedNodeImpl* Pred,
+ bool isLoad = false);
- inline ExplodedNodeImpl* generateNodeImpl(Stmt* S, void* State) {
+ inline ExplodedNodeImpl* generateNodeImpl(Stmt* S, void* State,
+ bool isLoad = false) {
ExplodedNodeImpl* N = getLastNode();
assert (N && "Predecessor of new node is infeasible.");
- return generateNodeImpl(S, State, N);
+ return generateNodeImpl(S, State, N, isLoad);
}
Stmt* getStmt() const { return B[Idx]; }
@@ -201,14 +203,14 @@
return static_cast<NodeTy*>(NB.getLastNode());
}
- NodeTy* generateNode(Stmt* S, StateTy* St, NodeTy* Pred) {
+ NodeTy* generateNode(Stmt* S, StateTy* St, NodeTy* Pred, bool isLoad = false){
HasGeneratedNode = true;
- return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, Pred));
+ return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, Pred, isLoad));
}
- NodeTy* generateNode(Stmt* S, StateTy* St) {
+ NodeTy* generateNode(Stmt* S, StateTy* St, bool isLoad = false) {
HasGeneratedNode = true;
- return static_cast<NodeTy*>(NB.generateNodeImpl(S, St));
+ return static_cast<NodeTy*>(NB.generateNodeImpl(S, St, isLoad));
}
GRBlockCounter getBlockCounter() const {
Modified: cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h?rev=50443&r1=50442&r2=50443&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/GRExprEngine.h Tue Apr 29 16:04:26 2008
@@ -425,10 +425,6 @@
return StateMgr.GetRVal(St, LV, T);
}
- RVal GetLVal(ValueState* St, Expr* Ex) {
- return StateMgr.GetLVal(St, Ex);
- }
-
inline NonLVal MakeConstantVal(uint64_t X, Expr* Ex) {
return NonLVal::MakeVal(BasicVals, X, Ex->getType());
}
@@ -474,11 +470,7 @@
assert (Builder && "GRStmtNodeBuilder not present.");
return Builder->MakeNode(Dst, S, Pred, St);
}
-
- /// HandleUndefinedStore - Create the necessary sink node to represent
- /// a store to an "undefined" LVal.
- void HandleUndefinedStore(Stmt* S, NodeTy* Pred);
-
+
/// Visit - Transfer function logic for all statements. Dispatches to
/// other functions that handle specific kinds of statements.
void Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst);
@@ -520,7 +512,8 @@
void VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst);
/// VisitDeclRefExpr - Transfer function logic for DeclRefExprs.
- void VisitDeclRefExpr(DeclRefExpr* DR, NodeTy* Pred, NodeSet& Dst);
+ void VisitDeclRefExpr(DeclRefExpr* DR, NodeTy* Pred, NodeSet& Dst,
+ bool asLval);
/// VisitDeclStmt - Transfer function logic for DeclStmts.
void VisitDeclStmt(DeclStmt* DS, NodeTy* Pred, NodeSet& Dst);
@@ -528,12 +521,6 @@
void VisitDeclStmtAux(DeclStmt* DS, ScopedDecl* D,
NodeTy* Pred, NodeSet& Dst);
- void VisitDeref(UnaryOperator* U, NodeTy* Pred, NodeSet& Dst,
- bool GetLVal = false);
-
- void VisitDeref(Expr* Ex, RVal V, ValueState* St, NodeTy* Pred, NodeSet& Dst,
- bool GetLVal);
-
/// VisitGuardedExpr - Transfer function logic for ?, __builtin_choose
void VisitGuardedExpr(Expr* Ex, Expr* L, Expr* R, NodeTy* Pred, NodeSet& Dst);
@@ -543,10 +530,6 @@
/// VisitMemberExpr - Transfer function for member expressions.
void VisitMemberExpr(MemberExpr* M, NodeTy* Pred, NodeSet& Dst, bool asLVal);
- void VisitMemberExprField(MemberExpr* M, Expr* Base, NodeTy* Pred,
- NodeSet& Dst, bool asLVal);
-
-
/// VisitObjCMessageExpr - Transfer function for ObjC message expressions.
void VisitObjCMessageExpr(ObjCMessageExpr* ME, NodeTy* Pred, NodeSet& Dst);
@@ -564,15 +547,12 @@
/// VisitSizeOfAlignOfTypeExpr - Transfer function for sizeof(type).
void VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr* Ex, NodeTy* Pred,
NodeSet& Dst);
-
- // VisitSizeOfExpr - Transfer function for sizeof(expr).
- void VisitSizeOfExpr(UnaryOperator* U, NodeTy* Pred, NodeSet& Dst);
-
+
/// VisitUnaryOperator - Transfer function logic for unary operators.
- void VisitUnaryOperator(UnaryOperator* B, NodeTy* Pred, NodeSet& Dst);
-
-
-
+ void VisitUnaryOperator(UnaryOperator* B, NodeTy* Pred, NodeSet& Dst,
+ bool asLVal);
+
+ bool CheckDivideZero(Expr* Ex, ValueState* St, NodeTy* Pred, RVal Denom);
RVal EvalCast(RVal X, QualType CastT) {
if (X.isUnknownOrUndef())
@@ -584,8 +564,6 @@
return TF->EvalCast(*this, cast<NonLVal>(X), CastT);
}
-
-
RVal EvalMinus(UnaryOperator* U, RVal X) {
return X.isValid() ? TF->EvalMinus(*this, U, cast<NonLVal>(X)) : X;
}
@@ -603,27 +581,27 @@
}
RVal EvalBinOp(BinaryOperator::Opcode Op, RVal L, RVal R) {
-
+
if (L.isUndef() || R.isUndef())
return UndefinedVal();
-
+
if (L.isUnknown() || R.isUnknown())
return UnknownVal();
-
+
if (isa<LVal>(L)) {
if (isa<LVal>(R))
return TF->EvalBinOp(*this, Op, cast<LVal>(L), cast<LVal>(R));
else
return TF->EvalBinOp(*this, Op, cast<LVal>(L), cast<NonLVal>(R));
}
-
+
if (isa<LVal>(R)) {
// Support pointer arithmetic where the increment/decrement operand
// is on the left and the pointer on the right.
-
+
assert (Op == BinaryOperator::Add || Op == BinaryOperator::Sub);
- // Commute the operands.
+ // Commute the operands.
return TF->EvalBinOp(*this, Op, cast<LVal>(R), cast<NonLVal>(L));
}
else
@@ -631,11 +609,11 @@
}
void EvalCall(NodeSet& Dst, CallExpr* CE, RVal L, NodeTy* Pred) {
- assert (Builder && "GRStmtNodeBuilder must be defined.");
+ assert (Builder && "GRStmtNodeBuilder must be defined.");
TF->EvalCall(Dst, *this, *Builder, CE, L, Pred);
}
- void EvalObjCMessageExpr(NodeSet& Dst, ObjCMessageExpr* ME, NodeTy* Pred) {
+ void EvalObjCMessageExpr(NodeSet& Dst, ObjCMessageExpr* ME, NodeTy* Pred) {
assert (Builder && "GRStmtNodeBuilder must be defined.");
TF->EvalObjCMessageExpr(Dst, *this, *Builder, ME, Pred);
}
@@ -643,7 +621,16 @@
void EvalStore(NodeSet& Dst, Expr* E, NodeTy* Pred, ValueState* St,
RVal TargetLV, RVal Val);
- void EvalReturn(NodeSet& Dst, ReturnStmt* s, NodeTy* Pred);
+ // FIXME: The "CheckOnly" option exists only because Array and Field
+ // loads aren't fully implemented. Eventually this option will go away.
+
+ void EvalLoad(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
+ ValueState* St, RVal location, bool CheckOnly = false);
+
+ ValueState* EvalLocation(Expr* Ex, NodeTy* Pred,
+ ValueState* St, RVal location, bool isLoad = false);
+
+ void EvalReturn(NodeSet& Dst, ReturnStmt* s, NodeTy* Pred);
ValueState* MarkBranch(ValueState* St, Stmt* Terminator, bool branchTaken);
};
Modified: cfe/trunk/include/clang/Analysis/PathSensitive/ValueState.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/PathSensitive/ValueState.h?rev=50443&r1=50442&r2=50443&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/PathSensitive/ValueState.h (original)
+++ cfe/trunk/include/clang/Analysis/PathSensitive/ValueState.h Tue Apr 29 16:04:26 2008
@@ -242,7 +242,6 @@
RVal GetRVal(ValueState* St, Expr* E);
RVal GetRVal(ValueState* St, LVal LV, QualType T = QualType());
- RVal GetLVal(ValueState* St, Expr* E);
RVal GetBlkExprRVal(ValueState* St, Expr* Ex);
Modified: cfe/trunk/include/clang/Analysis/ProgramPoint.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Analysis/ProgramPoint.h?rev=50443&r1=50442&r2=50443&view=diff
==============================================================================
--- cfe/trunk/include/clang/Analysis/ProgramPoint.h (original)
+++ cfe/trunk/include/clang/Analysis/ProgramPoint.h Tue Apr 29 16:04:26 2008
@@ -25,8 +25,9 @@
class ProgramPoint {
public:
- enum Kind { BlockEntranceKind=0, PostStmtKind=1, BlockExitKind=2,
- BlockEdgeSrcKind=3, BlockEdgeDstKind=4, BlockEdgeAuxKind=5 };
+ enum Kind { BlockEntranceKind=0, PostStmtKind=1, PostLoadKind=2,
+ BlockExitKind=3, BlockEdgeSrcKind=4, BlockEdgeDstKind=5,
+ BlockEdgeAuxKind=6 };
protected:
uintptr_t Data;
@@ -100,13 +101,25 @@
class PostStmt : public ProgramPoint {
+protected:
+ PostStmt(const Stmt* S, Kind k) : ProgramPoint(S, k) {}
public:
PostStmt(const Stmt* S) : ProgramPoint(S, PostStmtKind) {}
-
+
Stmt* getStmt() const { return (Stmt*) getRawPtr(); }
static bool classof(const ProgramPoint* Location) {
- return Location->getKind() == PostStmtKind;
+ unsigned k = Location->getKind();
+ return k == PostStmtKind || k == PostLoadKind;
+ }
+};
+
+class PostLoad : public PostStmt {
+public:
+ PostLoad(const Stmt* S) : PostStmt(S, PostLoadKind) {}
+
+ static bool classof(const ProgramPoint* Location) {
+ return Location->getKind() == PostLoadKind;
}
};
Modified: cfe/trunk/lib/Analysis/GRCoreEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/GRCoreEngine.cpp?rev=50443&r1=50442&r2=50443&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/GRCoreEngine.cpp (original)
+++ cfe/trunk/lib/Analysis/GRCoreEngine.cpp Tue Apr 29 16:04:26 2008
@@ -102,7 +102,8 @@
case ProgramPoint::BlockExitKind:
assert (false && "BlockExit location never occur in forward analysis.");
break;
-
+
+ case ProgramPoint::PostLoadKind:
case ProgramPoint::PostStmtKind:
HandlePostStmt(cast<PostStmt>(Node->getLocation()), WU.getBlock(),
WU.getIndex(), Node);
@@ -316,11 +317,13 @@
Eng.WList->Enqueue(Succ, B, Idx+1);
}
-ExplodedNodeImpl* GRStmtNodeBuilderImpl::generateNodeImpl(Stmt* S, void* State,
- ExplodedNodeImpl* Pred) {
+ExplodedNodeImpl*
+GRStmtNodeBuilderImpl::generateNodeImpl(Stmt* S, void* State,
+ ExplodedNodeImpl* Pred, bool isLoad) {
bool IsNew;
- ExplodedNodeImpl* N = Eng.G->getNodeImpl(PostStmt(S), State, &IsNew);
+ ProgramPoint Loc = isLoad ? PostLoad(S) : PostStmt(S);
+ ExplodedNodeImpl* N = Eng.G->getNodeImpl(Loc, State, &IsNew);
N->addPredecessor(Pred);
Deferred.erase(Pred);
Modified: cfe/trunk/lib/Analysis/GRExprEngine.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/GRExprEngine.cpp?rev=50443&r1=50442&r2=50443&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/GRExprEngine.cpp (original)
+++ cfe/trunk/lib/Analysis/GRExprEngine.cpp Tue Apr 29 16:04:26 2008
@@ -312,7 +312,7 @@
}
case Stmt::DeclRefExprClass:
- VisitDeclRefExpr(cast<DeclRefExpr>(S), Pred, Dst);
+ VisitDeclRefExpr(cast<DeclRefExpr>(S), Pred, Dst, false);
break;
case Stmt::DeclStmtClass:
@@ -339,6 +339,10 @@
Visit(cast<ParenExpr>(S)->getSubExpr()->IgnoreParens(), Pred, Dst);
break;
+ case Stmt::ReturnStmtClass:
+ VisitReturnStmt(cast<ReturnStmt>(S), Pred, Dst);
+ break;
+
case Stmt::SizeOfAlignOfTypeExprClass:
VisitSizeOfAlignOfTypeExpr(cast<SizeOfAlignOfTypeExpr>(S), Pred, Dst);
break;
@@ -360,25 +364,41 @@
break;
}
- // FIXME: We may wish to always bind state to ReturnStmts so
- // that users can quickly query what was the state at the
- // exit points of a function.
+ case Stmt::UnaryOperatorClass:
+ VisitUnaryOperator(cast<UnaryOperator>(S), Pred, Dst, false);
+ break;
+ }
+}
+
+void GRExprEngine::VisitLVal(Expr* Ex, NodeTy* Pred, NodeSet& Dst) {
+
+ Ex = Ex->IgnoreParens();
+
+ if (Ex != CurrentStmt && getCFG().isBlkExpr(Ex)) {
+ Dst.Add(Pred);
+ return;
+ }
+
+ switch (Ex->getStmtClass()) {
+ default:
+ Visit(Ex, Pred, Dst);
+ return;
- case Stmt::ReturnStmtClass:
- VisitReturnStmt(cast<ReturnStmt>(S), Pred, Dst); break;
+ case Stmt::ArraySubscriptExprClass:
+ VisitArraySubscriptExpr(cast<ArraySubscriptExpr>(Ex), Pred, Dst, true);
+ return;
- case Stmt::UnaryOperatorClass: {
- UnaryOperator* U = cast<UnaryOperator>(S);
+ case Stmt::DeclRefExprClass:
+ VisitDeclRefExpr(cast<DeclRefExpr>(Ex), Pred, Dst, true);
+ return;
- switch (U->getOpcode()) {
- case UnaryOperator::Deref: VisitDeref(U, Pred, Dst); break;
- case UnaryOperator::Plus: Visit(U->getSubExpr(), Pred, Dst); break;
- case UnaryOperator::SizeOf: VisitSizeOfExpr(U, Pred, Dst); break;
- default: VisitUnaryOperator(U, Pred, Dst); break;
- }
+ case Stmt::UnaryOperatorClass:
+ VisitUnaryOperator(cast<UnaryOperator>(Ex), Pred, Dst, true);
+ return;
- break;
- }
+ case Stmt::MemberExprClass:
+ VisitMemberExpr(cast<MemberExpr>(Ex), Pred, Dst, true);
+ return;
}
}
@@ -741,20 +761,18 @@
// Transfer functions: Loads and stores.
//===----------------------------------------------------------------------===//
-void GRExprEngine::VisitDeclRefExpr(DeclRefExpr* D, NodeTy* Pred, NodeSet& Dst){
-
- if (D != CurrentStmt) {
- Dst.Add(Pred); // No-op. Simply propagate the current state unchanged.
- return;
- }
-
- // If we are here, we are loading the value of the decl and binding
- // it to the block-level expression.
+void GRExprEngine::VisitDeclRefExpr(DeclRefExpr* D, NodeTy* Pred, NodeSet& Dst,
+ bool asLVal) {
- ValueState* St = GetState(Pred);
+ ValueState* St = GetState(Pred);
RVal X = RVal::MakeVal(BasicVals, D);
- RVal Y = isa<lval::DeclVal>(X) ? GetRVal(St, cast<lval::DeclVal>(X)) : X;
- MakeNode(Dst, D, Pred, SetBlkExprRVal(St, D, Y));
+
+ if (asLVal)
+ MakeNode(Dst, D, Pred, SetRVal(St, D, cast<LVal>(X)));
+ else {
+ RVal V = isa<lval::DeclVal>(X) ? GetRVal(St, cast<LVal>(X)) : X;
+ MakeNode(Dst, D, Pred, SetRVal(St, D, V));
+ }
}
/// VisitArraySubscriptExpr - Transfer function for array accesses
@@ -763,24 +781,57 @@
Expr* Base = A->getBase()->IgnoreParens();
- // Evaluate the base.
- NodeSet Tmp1;
- Visit(Base, Pred, Tmp1);
+ // Always visit the base as an LVal expression. This computes the
+ // abstract address of the base object.
+ NodeSet Tmp;
- // Dereference the base.
- NodeSet Tmp2;
-
- for (NodeSet::iterator I=Tmp1.begin(), E=Tmp1.end(); I!=E; ++I) {
- ValueState* St = GetState(*I);
- VisitDeref(Base, GetRVal(St, Base), St, *I, Tmp2, true);
+ if (Base->getType()->isPointerType()) // Base always is an LVal.
+ Visit(Base, Pred, Tmp);
+ else
+ VisitLVal(Base, Pred, Tmp);
+
+ // TODO: Compute the LVal for the entry. This will enable array sensitivity
+ // for the analysis.
+
+ // Return the LVal of the array entry.
+ if (asLVal) {
+
+ // This is a redunant copy; we do this as a placeholder for future logic.
+ for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+
+ ValueState* St = GetState(*I);
+ RVal V = GetRVal(St, Base);
+
+ // TODO: Compute the LVal for the entry. This will enable array sensitivity
+ // for the analysis.
+
+ if (!(V.isUndef() || V.isUnknown() || isa<lval::ConcreteInt>(V)))
+ V = UnknownVal();
+
+ MakeNode(Dst, A, *I, SetRVal(St, A, V));
+ }
+
+ return;
}
- // Get the index.
- Tmp1.clear();
- Expr* Index = A->getIdx()->IgnoreParens();
+ // We are doing a load. Check for a bad dereference. In the future we
+ // will check the actual entry lval; for now, check the Base LVal. For now
+ // the load will just return "UnknownVal" (since we don't have array
+ // sensitivity), but it will perform a null check.
- for (NodeSet::iterator I=Tmp2.begin(), E=Tmp2.end(); I!=E; ++I)
- Visit(Index, *I, Dst);
+ for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+
+ ValueState* St = GetState(*I);
+ RVal V = GetRVal(St, Base);
+
+ // TODO: Compute the LVal for the entry. This will enable array sensitivity
+ // for the analysis.
+
+ if (!(V.isUndef() || V.isUnknown() || isa<lval::ConcreteInt>(V)))
+ V = UnknownVal();
+
+ EvalLoad(Dst, A, *I, St, GetRVal(St, Base), true);
+ }
}
/// VisitMemberExpr - Transfer function for member expressions.
@@ -789,50 +840,165 @@
Expr* Base = M->getBase()->IgnoreParens();
+ // Always visit the base as an LVal expression. This computes the
+ // abstract address of the base object.
NodeSet Tmp;
- VisitLVal(Base, Pred, Tmp);
- if (Base->getType()->isPointerType()) {
- NodeSet Tmp2;
+ if (Base->getType()->isPointerType()) // Base always is an LVal.
+ Visit(Base, Pred, Tmp);
+ else
+ VisitLVal(Base, Pred, Tmp);
+
+
+ // Return the LVal of the field access.
+ if (asLVal) {
+ // This is a redunant copy; we do this as a placeholder for future logic.
for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- ValueState* St = GetState(*I);
- VisitDeref(Base, GetRVal(St, Base), St, *I, Tmp2, true);
+ ValueState* St = GetState(*I);
+ RVal V = GetRVal(St, Base);
+
+ // TODO: Compute the LVal for the field. This will enable field
+ // sensitivity for the analysis.
+
+ if (!(V.isUndef() || V.isUnknown() || isa<lval::ConcreteInt>(V)))
+ V = UnknownVal();
+
+ MakeNode(Dst, M, *I, SetRVal(St, M, V));
+
}
+
+ return;
+ }
+
+ // We are doing a load. Check for a bad dereference. In the future we
+ // will check the actual field lval; for now, check the Base LVal. For now
+ // the load will just return "UnknownVal" (since we don't have field
+ // sensitivity), but it will perform a null check.
+
+ for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+ ValueState* St = GetState(*I);
+
+ RVal V = GetRVal(St, Base);
+
+ // TODO: Compute the LVal for the field. This will enable field
+ // sensitivity for the analysis.
+
+ if (!(V.isUndef() || V.isUnknown() || isa<lval::ConcreteInt>(V)))
+ V = UnknownVal();
- for (NodeSet::iterator I=Tmp2.begin(), E=Tmp2.end(); I!=E; ++I)
- VisitMemberExprField(M, Base, *I, Dst, asLVal);
+ EvalLoad(Dst, M, *I, St, V, true);
}
- else
- for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I)
- VisitMemberExprField(M, Base, *I, Dst, asLVal);
-}
-
-void GRExprEngine::VisitMemberExprField(MemberExpr* M, Expr* Base, NodeTy* Pred,
- NodeSet& Dst, bool asLVal) {
- Dst.Add(Pred);
}
-void GRExprEngine::EvalStore(NodeSet& Dst, Expr* E, NodeTy* Pred,
- ValueState* St, RVal TargetLV, RVal Val) {
+void GRExprEngine::EvalStore(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
+ ValueState* St, RVal location, RVal Val) {
assert (Builder && "GRStmtNodeBuilder must be defined.");
+ // Evaluate the location (checks for bad dereferences).
+ St = EvalLocation(Ex, Pred, St, location);
+
+ if (!St)
+ return;
+
+ // Proceed with the store.
+
unsigned size = Dst.size();
SaveAndRestore<bool> OldSink(Builder->BuildSinks);
SaveOr OldHasGen(Builder->HasGeneratedNode);
- assert (!TargetLV.isUndef());
+ assert (!location.isUndef());
- TF->EvalStore(Dst, *this, *Builder, E, Pred, St, TargetLV, Val);
+ TF->EvalStore(Dst, *this, *Builder, Ex, Pred, St, location, Val);
// Handle the case where no nodes where generated. Auto-generate that
// contains the updated state if we aren't generating sinks.
if (!Builder->BuildSinks && Dst.size() == size && !Builder->HasGeneratedNode)
- TF->GRTransferFuncs::EvalStore(Dst, *this, *Builder, E, Pred, St,
- TargetLV, Val);
+ TF->GRTransferFuncs::EvalStore(Dst, *this, *Builder, Ex, Pred, St,
+ location, Val);
+}
+
+void GRExprEngine::EvalLoad(NodeSet& Dst, Expr* Ex, NodeTy* Pred,
+ ValueState* St, RVal location, bool CheckOnly) {
+
+ // Evaluate the location (checks for bad dereferences).
+
+ St = EvalLocation(Ex, Pred, St, location, true);
+
+ if (!St)
+ return;
+
+ // Proceed with the load.
+
+ // FIXME: Currently symbolic analysis "generates" new symbols
+ // for the contents of values. We need a better approach.
+
+ // FIXME: The "CheckOnly" option exists only because Array and Field
+ // loads aren't fully implemented. Eventually this option will go away.
+
+ if (location.isUnknown() || CheckOnly)
+ MakeNode(Dst, Ex, Pred, St);
+ else
+ MakeNode(Dst, Ex, Pred, SetRVal(St, Ex, GetRVal(St, cast<LVal>(location),
+ Ex->getType())));
+}
+
+ValueState* GRExprEngine::EvalLocation(Expr* Ex, NodeTy* Pred,
+ ValueState* St, RVal location,
+ bool isLoad) {
+
+ // Check for loads/stores from/to undefined values.
+ if (location.isUndef()) {
+ if (NodeTy* Succ = Builder->generateNode(Ex, St, Pred, isLoad)) {
+ Succ->markAsSink();
+ UndefDeref.insert(Succ);
+ }
+
+ return NULL;
+ }
+
+ // Check for loads/stores from/to unknown locations. Treat as No-Ops.
+ if (location.isUnknown())
+ return St;
+
+ // During a load, one of two possible situations arise:
+ // (1) A crash, because the location (pointer) was NULL.
+ // (2) The location (pointer) is not NULL, and the dereference works.
+ //
+ // We add these assumptions.
+
+ LVal LV = cast<LVal>(location);
+
+ // "Assume" that the pointer is not NULL.
+
+ bool isFeasibleNotNull = false;
+ ValueState* StNotNull = Assume(St, LV, true, isFeasibleNotNull);
+
+ // "Assume" that the pointer is NULL.
+
+ bool isFeasibleNull = false;
+ ValueState* StNull = Assume(St, LV, false, isFeasibleNull);
+
+ if (isFeasibleNull) {
+
+ // We don't use "MakeNode" here because the node will be a sink
+ // and we have no intention of processing it later.
+
+ NodeTy* NullNode = Builder->generateNode(Ex, StNull, Pred, isLoad);
+
+ if (NullNode) {
+
+ NullNode->markAsSink();
+
+ if (isFeasibleNotNull) ImplicitNullDeref.insert(NullNode);
+ else ExplicitNullDeref.insert(NullNode);
+ }
+ }
+
+ return isFeasibleNotNull ? StNotNull : NULL;
}
//===----------------------------------------------------------------------===//
@@ -870,7 +1036,7 @@
for (NodeSet::iterator DI = DstTmp.begin(), DE = DstTmp.end(); DI!=DE; ++DI) {
ValueState* St = GetState(*DI);
- RVal L = GetLVal(St, Callee);
+ RVal L = GetRVal(St, Callee);
// FIXME: Add support for symbolic function calls (calls involving
// function pointer values that are symbolic).
@@ -1127,7 +1293,7 @@
for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) {
NodeTy* N = *I1;
ValueState* St = GetState(N);
- RVal V = T->isReferenceType() ? GetLVal(St, Ex) : GetRVal(St, Ex);
+ RVal V = GetRVal(St, Ex);
// Unknown?
@@ -1275,7 +1441,6 @@
void GRExprEngine::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr* Ex,
NodeTy* Pred,
NodeSet& Dst) {
-
QualType T = Ex->getArgumentType();
uint64_t amt;
@@ -1295,284 +1460,191 @@
amt = getContext().getTypeAlign(T) / 8;
MakeNode(Dst, Ex, Pred,
- SetRVal(GetState(Pred), Ex,
- NonLVal::MakeVal(BasicVals, amt, Ex->getType())));
+ SetRVal(GetState(Pred), Ex,
+ NonLVal::MakeVal(BasicVals, amt, Ex->getType())));
}
-void GRExprEngine::VisitDeref(UnaryOperator* U, NodeTy* Pred,
- NodeSet& Dst, bool GetLVal) {
-
- Expr* Ex = U->getSubExpr()->IgnoreParens();
-
- NodeSet DstTmp;
-
- if (isa<DeclRefExpr>(Ex))
- DstTmp.Add(Pred);
- else
- Visit(Ex, Pred, DstTmp);
-
- for (NodeSet::iterator I = DstTmp.begin(), DE = DstTmp.end(); I != DE; ++I) {
- ValueState* St = GetState(*I);
- RVal V = GetRVal(St, Ex);
- VisitDeref(U, V, St, *I, Dst, GetLVal);
- }
-}
-
-void GRExprEngine::VisitDeref(Expr* Ex, RVal V, ValueState* St, NodeTy* Pred,
- NodeSet& Dst, bool GetLVal) {
-
- // Check for dereferences of undefined values.
-
- if (V.isUndef()) {
- if (NodeTy* Succ = Builder->generateNode(Ex, St, Pred)) {
- Succ->markAsSink();
- UndefDeref.insert(Succ);
- }
-
- return;
- }
-
- // Check for dereferences of unknown values. Treat as No-Ops.
-
- if (V.isUnknown()) {
- Dst.Add(Pred);
- return;
- }
-
- // 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.
-
- LVal LV = cast<LVal>(V);
- bool isFeasibleNotNull;
-
- // "Assume" that the pointer is Not-NULL.
-
- ValueState* StNotNull = Assume(St, LV, true, isFeasibleNotNull);
-
- if (isFeasibleNotNull) {
-
- if (GetLVal)
- MakeNode(Dst, Ex, Pred, SetRVal(StNotNull, Ex, LV));
- else {
-
- // FIXME: Currently symbolic analysis "generates" new symbols
- // for the contents of values. We need a better approach.
-
- MakeNode(Dst, Ex, Pred,
- SetRVal(StNotNull, Ex, GetRVal(StNotNull, LV, Ex->getType())));
- }
- }
-
- bool isFeasibleNull;
-
- // Now "assume" that the pointer is NULL.
-
- ValueState* StNull = Assume(St, LV, false, isFeasibleNull);
-
- if (isFeasibleNull) {
-
- // We don't use "MakeNode" here because the node will be a sink
- // and we have no intention of processing it later.
-
- NodeTy* NullNode = Builder->generateNode(Ex, StNull, Pred);
-
- if (NullNode) {
-
- NullNode->markAsSink();
-
- if (isFeasibleNotNull) ImplicitNullDeref.insert(NullNode);
- else ExplicitNullDeref.insert(NullNode);
- }
- }
-}
void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, NodeTy* Pred,
- NodeSet& Dst) {
-
- NodeSet S1;
-
- assert (U->getOpcode() != UnaryOperator::Deref);
- assert (U->getOpcode() != UnaryOperator::SizeOf);
- assert (U->getOpcode() != UnaryOperator::AlignOf);
-
- bool use_GetLVal = false;
-
+ NodeSet& Dst, bool asLVal) {
+
switch (U->getOpcode()) {
- case UnaryOperator::PostInc:
- case UnaryOperator::PostDec:
- case UnaryOperator::PreInc:
- case UnaryOperator::PreDec:
- case UnaryOperator::AddrOf:
- // Evalue subexpression as an LVal.
- use_GetLVal = true;
- VisitLVal(U->getSubExpr(), Pred, S1);
- break;
default:
- Visit(U->getSubExpr(), Pred, S1);
break;
- }
-
- for (NodeSet::iterator I1 = S1.begin(), E1 = S1.end(); I1 != E1; ++I1) {
-
- NodeTy* N1 = *I1;
- ValueState* St = GetState(N1);
+
+ case UnaryOperator::Deref: {
+
+ Expr* Ex = U->getSubExpr()->IgnoreParens();
+ NodeSet Tmp;
+ Visit(Ex, Pred, Tmp);
+
+ for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
- RVal SubV = use_GetLVal ? GetLVal(St, U->getSubExpr()) :
- GetRVal(St, U->getSubExpr());
-
- if (SubV.isUnknown()) {
- Dst.Add(N1);
- continue;
- }
+ ValueState* St = GetState(*I);
+ RVal location = GetRVal(St, Ex);
+
+ if (asLVal)
+ MakeNode(Dst, U, *I, SetRVal(St, U, location));
+ else
+ EvalLoad(Dst, Ex, *I, St, location);
+ }
- if (SubV.isUndef()) {
- MakeNode(Dst, U, N1, SetRVal(St, U, SubV));
- continue;
+ return;
}
-
- if (U->isIncrementDecrementOp()) {
+
+ case UnaryOperator::Plus: assert (!asLVal); // FALL-THROUGH.
+ case UnaryOperator::Extension: {
- // Handle ++ and -- (both pre- and post-increment).
+ // Unary "+" is a no-op, similar to a parentheses. We still have places
+ // where it may be a block-level expression, so we need to
+ // generate an extra node that just propagates the value of the
+ // subexpression.
+
+ Expr* Ex = U->getSubExpr()->IgnoreParens();
+ NodeSet Tmp;
+ Visit(Ex, Pred, Tmp);
- LVal SubLV = cast<LVal>(SubV);
- RVal V = GetRVal(St, SubLV, U->getType());
+ for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+ ValueState* St = GetState(*I);
+ MakeNode(Dst, U, *I, SetRVal(St, U, GetRVal(St, Ex)));
+ }
- if (V.isUnknown()) {
- Dst.Add(N1);
- continue;
+ return;
+ }
+
+ case UnaryOperator::AddrOf: {
+
+ assert (!asLVal);
+ Expr* Ex = U->getSubExpr()->IgnoreParens();
+ NodeSet Tmp;
+ VisitLVal(Ex, Pred, Tmp);
+
+ for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+ ValueState* St = GetState(*I);
+ RVal V = GetRVal(St, Ex);
+ St = SetRVal(St, U, V);
+ MakeNode(Dst, U, *I, St);
}
- // Propagate undefined values.
- if (V.isUndef()) {
- MakeNode(Dst, U, N1, SetRVal(St, U, V));
- continue;
- }
-
- // Handle all other values.
+ return;
+ }
- BinaryOperator::Opcode Op = U->isIncrementOp() ? BinaryOperator::Add
- : BinaryOperator::Sub;
+ case UnaryOperator::LNot:
+ case UnaryOperator::Minus:
+ case UnaryOperator::Not: {
- RVal Result = EvalBinOp(Op, V, MakeConstantVal(1U, U));
+ assert (!asLVal);
+ Expr* Ex = U->getSubExpr()->IgnoreParens();
+ NodeSet Tmp;
+ Visit(Ex, Pred, Tmp);
- if (U->isPostfix())
- St = SetRVal(SetRVal(St, U, V), SubLV, Result);
- else
- St = SetRVal(SetRVal(St, U, Result), SubLV, Result);
-
- MakeNode(Dst, U, N1, St);
- continue;
- }
-
- // Handle all other unary operators.
-
- switch (U->getOpcode()) {
+ for (NodeSet::iterator I=Tmp.begin(), E=Tmp.end(); I!=E; ++I) {
+ ValueState* St = GetState(*I);
+ RVal V = GetRVal(St, Ex);
- case UnaryOperator::Extension:
- St = SetRVal(St, U, SubV);
- break;
-
- case UnaryOperator::Minus:
- St = SetRVal(St, U, EvalMinus(U, cast<NonLVal>(SubV)));
- break;
+ if (V.isUnknownOrUndef()) {
+ MakeNode(Dst, U, *I, SetRVal(St, U, V));
+ continue;
+ }
- case UnaryOperator::Not:
- St = SetRVal(St, U, EvalComplement(cast<NonLVal>(SubV)));
- break;
+ switch (U->getOpcode()) {
+ default:
+ assert(false && "Invalid Opcode.");
+ break;
+
+ case UnaryOperator::Not:
+ St = SetRVal(St, U, EvalComplement(cast<NonLVal>(V)));
+ break;
+
+ case UnaryOperator::Minus:
+ St = SetRVal(St, U, EvalMinus(U, cast<NonLVal>(V)));
+ break;
+
+ case UnaryOperator::LNot:
+
+ // C99 6.5.3.3: "The expression !E is equivalent to (0==E)."
+ //
+ // Note: technically we do "E == 0", but this is the same in the
+ // transfer functions as "0 == E".
+
+ if (isa<LVal>(V)) {
+ lval::ConcreteInt X(BasicVals.getZeroWithPtrWidth());
+ RVal Result = EvalBinOp(BinaryOperator::EQ, cast<LVal>(V), X);
+ St = SetRVal(St, U, Result);
+ }
+ else {
+ nonlval::ConcreteInt X(BasicVals.getValue(0, Ex->getType()));
+ RVal Result = EvalBinOp(BinaryOperator::EQ, cast<NonLVal>(V), X);
+ St = SetRVal(St, U, Result);
+ }
+
+ break;
+ }
- case UnaryOperator::LNot:
+ MakeNode(Dst, U, *I, St);
+ }
+
+ return;
+ }
+
+ case UnaryOperator::SizeOf: {
+
+ QualType T = U->getSubExpr()->getType();
- // C99 6.5.3.3: "The expression !E is equivalent to (0==E)."
- //
- // Note: technically we do "E == 0", but this is the same in the
- // transfer functions as "0 == E".
-
- if (isa<LVal>(SubV)) {
- lval::ConcreteInt V(BasicVals.getZeroWithPtrWidth());
- RVal Result = EvalBinOp(BinaryOperator::EQ, cast<LVal>(SubV), V);
- St = SetRVal(St, U, Result);
- }
- else {
- Expr* Ex = U->getSubExpr();
- nonlval::ConcreteInt V(BasicVals.getValue(0, Ex->getType()));
- RVal Result = EvalBinOp(BinaryOperator::EQ, cast<NonLVal>(SubV), V);
- St = SetRVal(St, U, Result);
- }
+ // FIXME: Add support for VLAs.
+
+ if (!T.getTypePtr()->isConstantSizeType())
+ return;
- break;
+ uint64_t size = getContext().getTypeSize(T) / 8;
+ ValueState* St = GetState(Pred);
+ St = SetRVal(St, U, NonLVal::MakeVal(BasicVals, size, U->getType()));
- case UnaryOperator::AddrOf: {
- assert (isa<LVal>(SubV));
- St = SetRVal(St, U, SubV);
- break;
- }
-
- default: ;
- assert (false && "Not implemented.");
- }
-
- MakeNode(Dst, U, N1, St);
+ MakeNode(Dst, U, Pred, St);
+ return;
+ }
}
-}
-void GRExprEngine::VisitSizeOfExpr(UnaryOperator* U, NodeTy* Pred,
- NodeSet& Dst) {
-
- QualType T = U->getSubExpr()->getType();
-
- // FIXME: Add support for VLAs.
- if (!T.getTypePtr()->isConstantSizeType())
- return;
-
- uint64_t size = getContext().getTypeSize(T) / 8;
- ValueState* St = GetState(Pred);
- St = SetRVal(St, U, NonLVal::MakeVal(BasicVals, size, U->getType()));
-
- MakeNode(Dst, U, Pred, St);
-}
+ // Handle ++ and -- (both pre- and post-increment).
-void GRExprEngine::VisitLVal(Expr* Ex, NodeTy* Pred, NodeSet& Dst) {
-
- Ex = Ex->IgnoreParens();
-
- if (Ex != CurrentStmt && getCFG().isBlkExpr(Ex)) {
- Dst.Add(Pred);
- return;
- }
+ assert (U->isIncrementDecrementOp());
+ NodeSet Tmp;
+ Expr* Ex = U->getSubExpr()->IgnoreParens();
+ VisitLVal(Ex, Pred, Tmp);
- switch (Ex->getStmtClass()) {
- default:
- break;
-
- case Stmt::ArraySubscriptExprClass:
- VisitArraySubscriptExpr(cast<ArraySubscriptExpr>(Ex), Pred, Dst, true);
- return;
+ for (NodeSet::iterator I = Tmp.begin(), E = Tmp.end(); I!=E; ++I) {
+
+ ValueState* St = GetState(*I);
+ RVal V1 = GetRVal(St, Ex);
+
+ // Perform a load.
+ NodeSet Tmp2;
+ EvalLoad(Tmp2, Ex, *I, St, V1);
- case Stmt::DeclRefExprClass:
- Dst.Add(Pred);
- return;
+ for (NodeSet::iterator I2 = Tmp2.begin(), E2 = Tmp2.end(); I2!=E2; ++I2) {
+
+ St = GetState(*I2);
+ RVal V2 = GetRVal(St, Ex);
+
+ // Propagate unknown and undefined values.
+ if (V2.isUnknownOrUndef()) {
+ MakeNode(Dst, U, *I2, SetRVal(St, U, V2));
+ continue;
+ }
- case Stmt::UnaryOperatorClass: {
- UnaryOperator* U = cast<UnaryOperator>(Ex);
+ // Handle all other values.
- if (U->getOpcode() == UnaryOperator::Deref) {
- VisitDeref(U, Pred, Dst, true);
- return;
- }
+ BinaryOperator::Opcode Op = U->isIncrementOp() ? BinaryOperator::Add
+ : BinaryOperator::Sub;
- break;
+ RVal Result = EvalBinOp(Op, V2, MakeConstantVal(1U, U));
+ St = SetRVal(St, U, U->isPostfix() ? V2 : Result);
+
+ // Perform the store.
+ EvalStore(Dst, U, *I, St, V1, Result);
}
-
- case Stmt::MemberExprClass:
- VisitMemberExpr(cast<MemberExpr>(Ex), Pred, Dst, true);
- return;
}
-
- Visit(Ex, Pred, Dst);
}
void GRExprEngine::VisitAsmStmt(AsmStmt* A, NodeTy* Pred, NodeSet& Dst) {
@@ -1615,9 +1687,8 @@
for (AsmStmt::outputs_iterator OI = A->begin_outputs(),
OE = A->end_outputs(); OI != OE; ++OI) {
- RVal X = GetLVal(St, *OI);
-
- assert (!isa<NonLVal>(X));
+ RVal X = GetRVal(St, *OI);
+ assert (!isa<NonLVal>(X)); // Should be an Lval, or unknown, undef.
if (isa<LVal>(X))
St = SetRVal(St, cast<LVal>(X), UnknownVal());
@@ -1705,136 +1776,83 @@
// Transfer functions: Binary operators.
//===----------------------------------------------------------------------===//
+bool GRExprEngine::CheckDivideZero(Expr* Ex, ValueState* St,
+ NodeTy* Pred, RVal Denom) {
+
+ // Divide by undefined? (potentially zero)
+
+ if (Denom.isUndef()) {
+ NodeTy* DivUndef = Builder->generateNode(Ex, St, Pred);
+
+ if (DivUndef) {
+ DivUndef->markAsSink();
+ ExplicitBadDivides.insert(DivUndef);
+ }
+
+ return true;
+ }
+
+ // Check for divide/remainder-by-zero.
+ // First, "assume" that the denominator is 0 or undefined.
+
+ bool isFeasibleZero = false;
+ ValueState* ZeroSt = Assume(St, Denom, false, isFeasibleZero);
+
+ // Second, "assume" that the denominator cannot be 0.
+
+ bool isFeasibleNotZero = false;
+ St = Assume(St, Denom, true, isFeasibleNotZero);
+
+ // Create the node for the divide-by-zero (if it occurred).
+
+ if (isFeasibleZero)
+ if (NodeTy* DivZeroNode = Builder->generateNode(Ex, ZeroSt, Pred)) {
+ DivZeroNode->markAsSink();
+
+ if (isFeasibleNotZero)
+ ImplicitBadDivides.insert(DivZeroNode);
+ else
+ ExplicitBadDivides.insert(DivZeroNode);
+
+ }
+
+ return !isFeasibleNotZero;
+}
+
void GRExprEngine::VisitBinaryOperator(BinaryOperator* B,
GRExprEngine::NodeTy* Pred,
GRExprEngine::NodeSet& Dst) {
- NodeSet S1;
+
+ NodeSet Tmp1;
+ Expr* LHS = B->getLHS()->IgnoreParens();
+ Expr* RHS = B->getRHS()->IgnoreParens();
if (B->isAssignmentOp())
- VisitLVal(B->getLHS(), Pred, S1);
+ VisitLVal(LHS, Pred, Tmp1);
else
- Visit(B->getLHS(), Pred, S1);
+ Visit(LHS, Pred, Tmp1);
- for (NodeSet::iterator I1=S1.begin(), E1=S1.end(); I1 != E1; ++I1) {
+ for (NodeSet::iterator I1=Tmp1.begin(), E1=Tmp1.end(); I1 != E1; ++I1) {
- NodeTy* N1 = *I1;
+ RVal LeftV = GetRVal((*I1)->getState(), LHS);
- // When getting the value for the LHS, check if we are in an assignment.
- // In such cases, we want to (initially) treat the LHS as an LVal,
- // so we use GetLVal instead of GetRVal so that DeclRefExpr's are
- // evaluated to LValDecl's instead of to an NonLVal.
-
- RVal LeftV = B->isAssignmentOp() ? GetLVal(GetState(N1), B->getLHS())
- : GetRVal(GetState(N1), B->getLHS());
+ // Process the RHS.
- // Visit the RHS...
+ NodeSet Tmp2;
+ Visit(RHS, *I1, Tmp2);
- NodeSet S2;
- Visit(B->getRHS(), N1, S2);
+ // With both the LHS and RHS evaluated, process the operation itself.
- // Process the binary operator.
-
- for (NodeSet::iterator I2 = S2.begin(), E2 = S2.end(); I2 != E2; ++I2) {
+ for (NodeSet::iterator I2=Tmp2.begin(), E2=Tmp2.end(); I2 != E2; ++I2) {
- NodeTy* N2 = *I2;
- ValueState* St = GetState(N2);
- Expr* RHS = B->getRHS();
+ ValueState* St = GetState(*I2);
RVal RightV = GetRVal(St, RHS);
-
BinaryOperator::Opcode Op = B->getOpcode();
- if ((Op == BinaryOperator::Div || Op == BinaryOperator::Rem)
- && RHS->getType()->isIntegerType()) {
-
- // Check if the denominator is undefined.
-
- if (!RightV.isUnknown()) {
-
- if (RightV.isUndef()) {
- NodeTy* DivUndef = Builder->generateNode(B, St, N2);
-
- if (DivUndef) {
- DivUndef->markAsSink();
- ExplicitBadDivides.insert(DivUndef);
- }
-
- continue;
- }
-
- // Check for divide/remainder-by-zero.
- //
- // First, "assume" that the denominator is 0 or undefined.
-
- bool isFeasibleZero = false;
- ValueState* ZeroSt = Assume(St, RightV, false, isFeasibleZero);
-
- // Second, "assume" that the denominator cannot be 0.
-
- bool isFeasibleNotZero = false;
- St = Assume(St, RightV, true, isFeasibleNotZero);
-
- // Create the node for the divide-by-zero (if it occurred).
-
- if (isFeasibleZero)
- if (NodeTy* DivZeroNode = Builder->generateNode(B, ZeroSt, N2)) {
- DivZeroNode->markAsSink();
-
- if (isFeasibleNotZero)
- ImplicitBadDivides.insert(DivZeroNode);
- else
- ExplicitBadDivides.insert(DivZeroNode);
-
- }
-
- if (!isFeasibleNotZero)
- continue;
- }
-
- // Fall-through. The logic below processes the divide.
- }
-
-
- if (Op <= BinaryOperator::Or) {
-
- // Process non-assignements except commas or short-circuited
- // logical expressions (LAnd and LOr).
-
- RVal Result = EvalBinOp(Op, LeftV, RightV);
-
- if (Result.isUnknown()) {
- Dst.Add(N2);
- continue;
- }
-
- if (Result.isUndef() && !LeftV.isUndef() && !RightV.isUndef()) {
-
- // The operands were not undefined, but the result is undefined.
-
- if (NodeTy* UndefNode = Builder->generateNode(B, St, N2)) {
- UndefNode->markAsSink();
- UndefResults.insert(UndefNode);
- }
-
- continue;
- }
-
- MakeNode(Dst, B, N2, SetRVal(St, B, Result));
- continue;
- }
-
- // Process assignments.
-
- switch (Op) {
+ switch (Op) {
case BinaryOperator::Assign: {
- // Simple assignments.
-
- if (LeftV.isUndef()) {
- HandleUndefinedStore(B, N2);
- continue;
- }
-
// EXPERIMENTAL: "Conjured" symbols.
if (RightV.isUnknown()) {
@@ -1842,180 +1860,144 @@
SymbolID Sym = SymMgr.getConjuredSymbol(B->getRHS(), Count);
RightV = B->getRHS()->getType()->isPointerType()
- ? cast<RVal>(lval::SymbolVal(Sym))
- : cast<RVal>(nonlval::SymbolVal(Sym));
+ ? cast<RVal>(lval::SymbolVal(Sym))
+ : cast<RVal>(nonlval::SymbolVal(Sym));
}
// Simulate the effects of a "store": bind the value of the RHS
// to the L-Value represented by the LHS.
-
- EvalStore(Dst, B, N2, SetRVal(St, B, RightV),
- LeftV, RightV);
+ EvalStore(Dst, B, *I2, SetRVal(St, B, RightV), LeftV, RightV);
continue;
}
-
- // Compound assignment operators.
- default: {
+ case BinaryOperator::Div:
+ case BinaryOperator::Rem:
- assert (B->isCompoundAssignmentOp());
+ // Special checking for integer denominators.
- if (Op >= BinaryOperator::AndAssign)
- ((int&) Op) -= (BinaryOperator::AndAssign - BinaryOperator::And);
- else
- ((int&) Op) -= BinaryOperator::MulAssign;
+ if (RHS->getType()->isIntegerType()
+ && CheckDivideZero(B, St, *I2, RightV))
+ continue;
- // Check if the LHS is undefined.
+ // FALL-THROUGH.
+
+ default: {
+
+ if (B->isAssignmentOp())
+ break;
- if (LeftV.isUndef()) {
- HandleUndefinedStore(B, N2);
+ // Process non-assignements except commas or short-circuited
+ // logical expressions (LAnd and LOr).
+
+ RVal Result = EvalBinOp(Op, LeftV, RightV);
+
+ if (Result.isUnknown()) {
+ Dst.Add(*I2);
continue;
}
- if (LeftV.isUnknown()) {
- assert (isa<UnknownVal>(GetRVal(St, B)));
- Dst.Add(N2);
+ if (Result.isUndef() && !LeftV.isUndef() && !RightV.isUndef()) {
+
+ // The operands were *not* undefined, but the result is undefined.
+ // This is a special node that should be flagged as an error.
+
+ if (NodeTy* UndefNode = Builder->generateNode(B, St, *I2)) {
+ UndefNode->markAsSink();
+ UndefResults.insert(UndefNode);
+ }
+
continue;
}
- // At this pointer we know that the LHS evaluates to an LVal
- // that is neither "Unknown" or "Undefined."
-
- LVal LeftLV = cast<LVal>(LeftV);
-
- // Fetch the value of the LHS (the value of the variable, etc.).
+ // Otherwise, create a new node.
- RVal V = GetRVal(GetState(N1), LeftLV, B->getLHS()->getType());
+ MakeNode(Dst, B, *I2, SetRVal(St, B, Result));
+ continue;
+ }
+ }
+
+ assert (B->isCompoundAssignmentOp());
+
+ if (Op >= BinaryOperator::AndAssign)
+ ((int&) Op) -= (BinaryOperator::AndAssign - BinaryOperator::And);
+ else
+ ((int&) Op) -= BinaryOperator::MulAssign;
- // Propagate undefined value (left-side). We
- // propogate undefined values for the RHS below when
- // we also check for divide-by-zero.
+ // Perform a load (the LHS). This performs the checks for
+ // null dereferences, and so on.
+ NodeSet Tmp3;
+ RVal location = GetRVal(St, LHS);
+ EvalLoad(Tmp3, LHS, *I2, St, location);
+
+ for (NodeSet::iterator I3=Tmp3.begin(), E3=Tmp3.end(); I3!=E3; ++I3) {
+
+ St = GetState(*I3);
+ RVal V = GetRVal(St, LHS);
+
+ // Propagate undefined values (left-side).
+ if (V.isUndef()) {
+ EvalStore(Dst, B, *I3, SetRVal(St, B, V), location, V);
+ continue;
+ }
+
+ // Propagate unknown values (left and right-side).
+ if (RightV.isUnknown() || V.isUnknown()) {
+ EvalStore(Dst, B, *I3, SetRVal(St, B, UnknownVal()), location,
+ UnknownVal());
+ continue;
+ }
+
+ // At this point:
+ //
+ // The LHS is not Undef/Unknown.
+ // The RHS is not Unknown.
+
+ // Get the computation type.
+ QualType CTy = cast<CompoundAssignOperator>(B)->getComputationType();
- if (V.isUndef()) {
- St = SetRVal(St, B, V);
- break;
- }
+ // Perform promotions.
+ V = EvalCast(V, CTy);
+ RightV = EvalCast(RightV, CTy);
- // Propagate unknown values.
+ // Evaluate operands and promote to result type.
+
+ if ((Op == BinaryOperator::Div || Op == BinaryOperator::Rem)
+ && RHS->getType()->isIntegerType()) {
- if (V.isUnknown()) {
- // The value bound to LeftV is unknown. Thus we just
- // propagate the current node (as "B" is already bound to nothing).
- assert (isa<UnknownVal>(GetRVal(St, B)));
- Dst.Add(N2);
+ if (CheckDivideZero(B, St, *I3, RightV))
continue;
- }
-
- if (RightV.isUnknown()) {
- assert (isa<UnknownVal>(GetRVal(St, B)));
- St = SetRVal(St, LeftLV, UnknownVal());
- break;
- }
+ }
+ else if (RightV.isUndef()) {
- // At this point:
- //
- // The LHS is not Undef/Unknown.
- // The RHS is not Unknown.
-
- // Get the computation type.
- QualType CTy = cast<CompoundAssignOperator>(B)->getComputationType();
-
- // Perform promotions.
- V = EvalCast(V, CTy);
- RightV = EvalCast(RightV, CTy);
+ // Propagate undefined values (right-side).
- // Evaluate operands and promote to result type.
-
- if ((Op == BinaryOperator::Div || Op == BinaryOperator::Rem)
- && RHS->getType()->isIntegerType()) {
-
- // Check if the denominator is undefined.
-
- if (RightV.isUndef()) {
- NodeTy* DivUndef = Builder->generateNode(B, St, N2);
-
- if (DivUndef) {
- DivUndef->markAsSink();
- ExplicitBadDivides.insert(DivUndef);
- }
-
- continue;
- }
-
- // First, "assume" that the denominator is 0.
-
- bool isFeasibleZero = false;
- ValueState* ZeroSt = Assume(St, RightV, false, isFeasibleZero);
-
- // Second, "assume" that the denominator cannot be 0.
-
- bool isFeasibleNotZero = false;
- St = Assume(St, RightV, true, isFeasibleNotZero);
-
- // Create the node for the divide-by-zero error (if it occurred).
-
- if (isFeasibleZero) {
- NodeTy* DivZeroNode = Builder->generateNode(B, ZeroSt, N2);
-
- if (DivZeroNode) {
- DivZeroNode->markAsSink();
-
- if (isFeasibleNotZero)
- ImplicitBadDivides.insert(DivZeroNode);
- else
- ExplicitBadDivides.insert(DivZeroNode);
- }
- }
-
- if (!isFeasibleNotZero)
- continue;
-
- // Fall-through. The logic below processes the divide.
- }
- else {
-
- // Propagate undefined values (right-side).
-
- if (RightV.isUndef()) {
- St = SetRVal(SetRVal(St, B, RightV), LeftLV, RightV);
- break;
- }
-
- }
-
- RVal Result = EvalCast(EvalBinOp(Op, V, RightV), B->getType());
+ EvalStore(Dst, B, *I3, SetRVal(St, B, RightV), location, RightV);
+ continue;
+ }
+
+ // Compute the result of the operation.
+
+ RVal Result = EvalCast(EvalBinOp(Op, V, RightV), B->getType());
- if (Result.isUndef()) {
-
- // The operands were not undefined, but the result is undefined.
+ if (Result.isUndef()) {
- if (NodeTy* UndefNode = Builder->generateNode(B, St, N2)) {
- UndefNode->markAsSink();
- UndefResults.insert(UndefNode);
- }
-
- continue;
+ // The operands were not undefined, but the result is undefined.
+
+ if (NodeTy* UndefNode = Builder->generateNode(B, St, *I3)) {
+ UndefNode->markAsSink();
+ UndefResults.insert(UndefNode);
}
- // St = SetRVal(SetRVal(St, B, Result), LeftLV, Result);
- EvalStore(Dst, B, N2, SetRVal(St, B, Result), LeftLV, Result);
continue;
}
+
+ EvalStore(Dst, B, *I3, SetRVal(St, B, Result), location, Result);
}
-
- MakeNode(Dst, B, N2, St);
}
}
}
-void GRExprEngine::HandleUndefinedStore(Stmt* S, NodeTy* Pred) {
- NodeTy* N = Builder->generateNode(S, GetState(Pred), Pred);
- N->markAsSink();
- UndefStores.insert(N);
-}
-
-
//===----------------------------------------------------------------------===//
// "Assume" logic.
//===----------------------------------------------------------------------===//
@@ -2325,6 +2307,7 @@
assert (false);
break;
+ case ProgramPoint::PostLoadKind:
case ProgramPoint::PostStmtKind: {
const PostStmt& L = cast<PostStmt>(Loc);
Stmt* S = L.getStmt();
Modified: cfe/trunk/lib/Analysis/ValueState.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Analysis/ValueState.cpp?rev=50443&r1=50442&r2=50443&view=diff
==============================================================================
--- cfe/trunk/lib/Analysis/ValueState.cpp (original)
+++ cfe/trunk/lib/Analysis/ValueState.cpp Tue Apr 29 16:04:26 2008
@@ -271,22 +271,6 @@
E = cast<ParenExpr>(E)->getSubExpr();
continue;
- // DeclRefExprs can either evaluate to an LVal or a Non-LVal
- // (assuming an implicit "load") depending on the context. In this
- // context we assume that we are retrieving the value contained
- // within the referenced variables.
-
- case Stmt::DeclRefExprClass: {
-
- // Check if this expression is a block-level expression. If so,
- // return its value.
- ValueState::ExprBindingsTy::TreeTy* T=St->BlockExprBindings.SlimFind(E);
- if (T) return T->getValue().second;
-
- RVal X = RVal::MakeVal(BasicVals, cast<DeclRefExpr>(E));
- return isa<lval::DeclVal>(X) ? GetRVal(St, cast<lval::DeclVal>(X)) : X;
- }
-
case Stmt::CharacterLiteralClass: {
CharacterLiteral* C = cast<CharacterLiteral>(E);
return NonLVal::MakeVal(BasicVals, C->getValue(), C->getType());
@@ -326,18 +310,6 @@
break;
}
- case Stmt::UnaryOperatorClass: {
-
- UnaryOperator* U = cast<UnaryOperator>(E);
-
- if (U->getOpcode() == UnaryOperator::Plus) {
- E = U->getSubExpr();
- continue;
- }
-
- break;
- }
-
// Handle all other Expr* using a lookup.
default:
@@ -377,34 +349,6 @@
}
}
-RVal ValueStateManager::GetLVal(ValueState* St, Expr* E) {
-
- E = E->IgnoreParens();
-
- if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E)) {
- ValueDecl* VD = DR->getDecl();
-
- if (FunctionDecl* FD = dyn_cast<FunctionDecl>(VD))
- return lval::FuncVal(FD);
- else
- return lval::DeclVal(cast<VarDecl>(DR->getDecl()));
- }
-
- if (UnaryOperator* U = dyn_cast<UnaryOperator>(E))
- if (U->getOpcode() == UnaryOperator::Deref) {
- E = U->getSubExpr()->IgnoreParens();
-
- if (DeclRefExpr* DR = dyn_cast<DeclRefExpr>(E)) {
- lval::DeclVal X(cast<VarDecl>(DR->getDecl()));
- return GetRVal(St, X);
- }
- else
- return GetRVal(St, E);
- }
-
- return GetRVal(St, E);
-}
-
ValueState*
ValueStateManager::SetRVal(ValueState* St, Expr* E, RVal V,
bool isBlkExpr, bool Invalidate) {
More information about the cfe-commits
mailing list