From: Ted Kremenek Date: Tue, 19 Feb 2008 01:44:53 +0000 (+0000) Subject: Added boilerplate transfer function support for CallExprs. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=de43424560f1a744de6214dab6bbee28ad8437f5;p=clang Added boilerplate transfer function support for CallExprs. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@47298 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/Analysis/GRExprEngine.cpp b/Analysis/GRExprEngine.cpp index 09ffcd47a5..4ea7819497 100644 --- a/Analysis/GRExprEngine.cpp +++ b/Analysis/GRExprEngine.cpp @@ -259,7 +259,7 @@ void GRExprEngine::ProcessSwitch(SwitchNodeBuilder& builder) { do { nonlval::ConcreteInt CaseVal(ValMgr.getValue(V1)); - NonLValue Res = EvalBinaryOp(ValMgr, BinaryOperator::EQ, CondV, CaseVal); + NonLValue Res = EvalBinaryOp(BinaryOperator::EQ, CondV, CaseVal); // Now "assume" that the case matches. bool isFeasible = false; @@ -407,12 +407,51 @@ void GRExprEngine::VisitDeclRefExpr(DeclRefExpr* D, NodeTy* Pred, NodeSet& Dst){ Nodify(Dst, D, Pred, SetValue(St, D, GetValue(St, D))); } +void GRExprEngine::VisitCall(CallExpr* CE, NodeTy* Pred, + CallExpr::arg_iterator I, CallExpr::arg_iterator E, + NodeSet& Dst) { + + if (I != E) { + NodeSet DstTmp; + Visit(*I, Pred, DstTmp); + ++I; + + for (NodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI!=DE; ++DI) + VisitCall(CE, *DI, I, E, Dst); + + return; + } + + // If we reach here we have processed all of the arguments. Evaluate + // the callee expression. + NodeSet DstTmp; + Visit(CE->getCallee(), Pred, DstTmp); + + // Finally, evaluate the function call. + for (NodeSet::iterator DI=DstTmp.begin(), DE=DstTmp.end(); DI!=DE; ++DI) { + StateTy St = (*DI)->getState(); + LValue L = GetLValue(St, CE->getCallee()); + + // Check for uninitialized control-flow. + if (isa(L)) { + NodeTy* N = Builder->generateNode(CE, St, *DI); + N->markAsSink(); + UninitBranches.insert(N); + continue; + } + + // Note: EvalCall must handle the case where the callee is "UnknownVal." + Nodify(Dst, CE, *DI, EvalCall(CE, (*DI)->getState())); + } +} + void GRExprEngine::VisitCast(Expr* CastE, Expr* E, NodeTy* Pred, NodeSet& Dst) { QualType T = CastE->getType(); // Check for redundant casts. - if (E->getType() == T) { + if (E->getType() == T || + (T->isPointerType() && E->getType()->isFunctionType())) { Dst.Add(Pred); return; } @@ -515,7 +554,7 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, BinaryOperator::Opcode Op = U->isIncrementOp() ? BinaryOperator::Add : BinaryOperator::Sub; - RValue Result = EvalBinaryOp(ValMgr, Op, R1, GetRValueConstant(1U, U)); + RValue Result = EvalBinaryOp(Op, R1, GetRValueConstant(1U, U)); if (U->isPostfix()) Nodify(Dst, U, N1, SetValue(SetValue(St, U, R1), L1, Result)); @@ -553,14 +592,14 @@ void GRExprEngine::VisitUnaryOperator(UnaryOperator* U, const LValue& L1 = cast(V1); lval::ConcreteInt V2(ValMgr.getZeroWithPtrWidth()); Nodify(Dst, U, N1, - SetValue(St, U, EvalBinaryOp(ValMgr, BinaryOperator::EQ, + SetValue(St, U, EvalBinaryOp(BinaryOperator::EQ, L1, V2))); } else { const NonLValue& R1 = cast(V1); nonlval::ConcreteInt V2(ValMgr.getZeroWithPtrWidth()); Nodify(Dst, U, N1, - SetValue(St, U, EvalBinaryOp(ValMgr, BinaryOperator::EQ, + SetValue(St, U, EvalBinaryOp(BinaryOperator::EQ, R1, V2))); } @@ -705,7 +744,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, continue; } - Nodify(Dst, B, N2, SetValue(St, B, EvalBinaryOp(ValMgr, Op, V1, V2))); + Nodify(Dst, B, N2, SetValue(St, B, EvalBinaryOp(Op, V1, V2))); continue; } @@ -742,14 +781,14 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, if (B->getType()->isPointerType()) { // Perform pointer arithmetic. const NonLValue& R2 = cast(V2); - Result = EvalBinaryOp(ValMgr, Op, L1, R2); + Result = EvalBinaryOp(Op, L1, R2); } else if (isa(V2)) { const LValue& L2 = cast(V2); if (B->getRHS()->getType()->isPointerType()) { // LValue comparison. - Result = EvalBinaryOp(ValMgr, Op, L1, L2); + Result = EvalBinaryOp(Op, L1, L2); } else { QualType T1 = B->getLHS()->getType(); @@ -757,7 +796,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, // An operation between two variables of a non-lvalue type. Result = - EvalBinaryOp(ValMgr, Op, + EvalBinaryOp(Op, cast(GetValue(N1->getState(), L1, &T1)), cast(GetValue(N2->getState(), L2, &T2))); } @@ -767,7 +806,7 @@ void GRExprEngine::VisitBinaryOperator(BinaryOperator* B, const NonLValue& R1 = cast(GetValue(N1->getState(), L1, &T)); const NonLValue& R2 = cast(V2); - Result = EvalBinaryOp(ValMgr, Op, R1, R2); + Result = EvalBinaryOp(Op, R1, R2); } Nodify(Dst, B, N2, SetValue(SetValue(St, B, Result), L1, Result)); @@ -821,6 +860,12 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) { VisitBinaryOperator(cast(S), Pred, Dst); break; } + + case Stmt::CallExprClass: { + CallExpr* C = cast(S); + VisitCall(C, Pred, C->arg_begin(), C->arg_end(), Dst); + break; + } case Stmt::CastExprClass: { CastExpr* C = cast(S); diff --git a/Analysis/RValues.cpp b/Analysis/RValues.cpp index c8a4dfa8d9..0fc03dda58 100644 --- a/Analysis/RValues.cpp +++ b/Analysis/RValues.cpp @@ -342,7 +342,12 @@ void LValue::print(std::ostream& Out) const { case lval::DeclValKind: Out << '&' - << cast(this)->getDecl()->getIdentifier()->getName(); + << cast(this)->getDecl()->getIdentifier()->getName(); + break; + + case lval::FuncValKind: + Out << "function " + << cast(this)->getDecl()->getIdentifier()->getName(); break; default: diff --git a/Analysis/ValueState.cpp b/Analysis/ValueState.cpp index 32be0c6d71..0f29def4a0 100644 --- a/Analysis/ValueState.cpp +++ b/Analysis/ValueState.cpp @@ -220,6 +220,8 @@ RValue ValueStateManager::GetValue(ValueState St, Expr* E, bool* hasVal) { // a better way, since APInts are fairly lightweight. return nonlval::ConcreteInt(ValMgr.getValue(ED->getInitVal())); } + else if (FunctionDecl* FD = dyn_cast(D)) + return lval::FuncVal(FD); assert (false && "ValueDecl support for this ValueDecl not implemented."); @@ -248,7 +250,10 @@ RValue ValueStateManager::GetValue(ValueState St, Expr* E, bool* hasVal) { case Stmt::ImplicitCastExprClass: { ImplicitCastExpr* C = cast(E); - if (C->getType() == C->getSubExpr()->getType()) { + QualType CT = C->getType(); + QualType ST = C->getSubExpr()->getType(); + + if (CT == ST || (CT->isPointerType() && ST->isFunctionType())) { E = C->getSubExpr(); continue; } @@ -257,7 +262,10 @@ RValue ValueStateManager::GetValue(ValueState St, Expr* E, bool* hasVal) { case Stmt::CastExprClass: { CastExpr* C = cast(E); - if (C->getType() == C->getSubExpr()->getType()) { + QualType CT = C->getType(); + QualType ST = C->getSubExpr()->getType(); + + if (CT == ST || (CT->isPointerType() && ST->isFunctionType())) { E = C->getSubExpr(); continue; } @@ -297,8 +305,14 @@ LValue ValueStateManager::GetLValue(ValueState St, Expr* E) { while (ParenExpr* P = dyn_cast(E)) E = P->getSubExpr(); - if (DeclRefExpr* DR = dyn_cast(E)) - return lval::DeclVal(cast(DR->getDecl())); + if (DeclRefExpr* DR = dyn_cast(E)) { + ValueDecl* VD = DR->getDecl(); + + if (FunctionDecl* FD = dyn_cast(VD)) + return lval::FuncVal(FD); + else + return lval::DeclVal(cast(DR->getDecl())); + } if (UnaryOperator* U = dyn_cast(E)) if (U->getOpcode() == UnaryOperator::Deref) diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h index 1bdbb2afda..4f9456d4e3 100644 --- a/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -296,6 +296,11 @@ public: void VisitAssignmentLHS(Expr* E, NodeTy* Pred, NodeSet& Dst); + /// VisitCall - Transfer function for function calls. + void VisitCall(CallExpr* CE, NodeTy* Pred, + CallExpr::arg_iterator I, CallExpr::arg_iterator E, + NodeSet& Dst); + /// VisitCast - Transfer function logic for all casts (implicit and explicit). void VisitCast(Expr* CastE, Expr* E, NodeTy* Pred, NodeSet& Dst); @@ -342,7 +347,7 @@ public: return TF->EvalComplement(ValMgr, X); } - inline NonLValue EvalBinaryOp(ValueManager& ValMgr, BinaryOperator::Opcode Op, + inline NonLValue EvalBinaryOp(BinaryOperator::Opcode Op, NonLValue LHS, NonLValue RHS) { if (isa(LHS) || isa(RHS)) @@ -354,7 +359,7 @@ public: return TF->EvalBinaryOp(ValMgr, Op, LHS, RHS); } - inline RValue EvalBinaryOp(ValueManager& ValMgr, BinaryOperator::Opcode Op, + inline RValue EvalBinaryOp(BinaryOperator::Opcode Op, LValue LHS, LValue RHS) { if (isa(LHS) || isa(RHS)) @@ -366,7 +371,7 @@ public: return TF->EvalBinaryOp(ValMgr, Op, LHS, RHS); } - inline RValue EvalBinaryOp(ValueManager& ValMgr, BinaryOperator::Opcode Op, + inline RValue EvalBinaryOp(BinaryOperator::Opcode Op, LValue LHS, NonLValue RHS) { if (isa(LHS) || isa(RHS)) @@ -378,7 +383,7 @@ public: return TF->EvalBinaryOp(ValMgr, Op, LHS, RHS); } - inline RValue EvalBinaryOp(ValueManager& ValMgr, BinaryOperator::Opcode Op, + inline RValue EvalBinaryOp(BinaryOperator::Opcode Op, RValue LHS, RValue RHS) { if (isa(LHS) || isa(RHS)) @@ -389,5 +394,9 @@ public: return TF->EvalBinaryOp(ValMgr, Op, LHS, RHS); } + + StateTy EvalCall(CallExpr* CE, StateTy St) { + return St; + } }; } // end clang namespace \ No newline at end of file diff --git a/include/clang/Analysis/PathSensitive/RValues.h b/include/clang/Analysis/PathSensitive/RValues.h index 202c2306bf..d4a2766ce6 100644 --- a/include/clang/Analysis/PathSensitive/RValues.h +++ b/include/clang/Analysis/PathSensitive/RValues.h @@ -147,9 +147,9 @@ public: namespace nonlval { - enum Kind { SymbolValKind, + enum Kind { ConcreteIntKind, + SymbolValKind, SymIntConstraintValKind, - ConcreteIntKind, NumKind }; class SymbolVal : public NonLValue { @@ -218,6 +218,7 @@ namespace lval { enum Kind { SymbolValKind, GotoLabelKind, DeclValKind, + FuncValKind, ConcreteIntKind, NumKind }; @@ -282,6 +283,32 @@ namespace lval { return V->getSubKind() == DeclValKind; } }; + + class FuncVal : public LValue { + public: + FuncVal(const FunctionDecl* fd) : LValue(FuncValKind, fd) {} + + FunctionDecl* getDecl() const { + return static_cast(Data); + } + + inline bool operator==(const FuncVal& R) const { + return getDecl() == R.getDecl(); + } + + inline bool operator!=(const FuncVal& R) const { + return getDecl() != R.getDecl(); + } + + // Implement isa support. + static inline bool classof(const RValue* V) { + return isa(V) && V->getSubKind() == FuncValKind; + } + + static inline bool classof(const LValue* V) { + return V->getSubKind() == FuncValKind; + } + }; class ConcreteInt : public LValue { public: