From: Ted Kremenek Date: Mon, 21 Apr 2008 23:43:38 +0000 (+0000) Subject: Added support for detected bad dereferences involving MemberExprs, e.g. x->f where... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=469ecbded3616416ef938ed94a67f86149faf226;p=clang Added support for detected bad dereferences involving MemberExprs, e.g. x->f where "x" is NULL. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@50071 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/clang/Analysis/PathSensitive/GRExprEngine.h b/include/clang/Analysis/PathSensitive/GRExprEngine.h index 46ff661959..0ac5bbbdc9 100644 --- a/include/clang/Analysis/PathSensitive/GRExprEngine.h +++ b/include/clang/Analysis/PathSensitive/GRExprEngine.h @@ -479,6 +479,13 @@ protected: /// other functions that handle specific kinds of statements. void Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst); + /// VisitLVal - Similar to Visit, but the specified expression is assummed + /// to be evaluated under the context where it evaluates to an LVal. For + /// example, if Ex is a DeclRefExpr, under Visit Ex would evaluate to the + /// value bound to Ex in the symbolic state, while under VisitLVal it would + /// evaluate to an LVal representing the location of the referred Decl. + void VisitLVal(Expr* Ex, NodeTy* Pred, NodeSet& Dst); + /// VisitAsmStmt - Transfer function logic for inline asm. void VisitAsmStmt(AsmStmt* A, NodeTy* Pred, NodeSet& Dst); @@ -494,25 +501,13 @@ protected: /// VisitBinaryOperator - Transfer function logic for binary operators. void VisitBinaryOperator(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst); - - void VisitLVal(Expr* Ex, NodeTy* Pred, NodeSet& Dst); + /// VisitCall - Transfer function for function calls. void VisitCall(CallExpr* CE, NodeTy* Pred, CallExpr::arg_iterator AI, CallExpr::arg_iterator AE, NodeSet& Dst); - /// VisitObjCMessageExpr - Transfer function for ObjC message expressions. - void VisitObjCMessageExpr(ObjCMessageExpr* ME, NodeTy* Pred, NodeSet& Dst); - - void VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME, - ObjCMessageExpr::arg_iterator I, - ObjCMessageExpr::arg_iterator E, - NodeTy* Pred, NodeSet& Dst); - - void VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, NodeTy* Pred, - NodeSet& Dst); - /// VisitCast - Transfer function logic for all casts (implicit and explicit). void VisitCast(Expr* CastE, Expr* Ex, NodeTy* Pred, NodeSet& Dst); @@ -522,12 +517,36 @@ protected: /// VisitDeclStmt - Transfer function logic for DeclStmts. void VisitDeclStmt(DeclStmt* DS, 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); /// VisitLogicalExpr - Transfer function logic for '&&', '||' void VisitLogicalExpr(BinaryOperator* B, NodeTy* Pred, NodeSet& Dst); + /// 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); + + void VisitObjCMessageExprArgHelper(ObjCMessageExpr* ME, + ObjCMessageExpr::arg_iterator I, + ObjCMessageExpr::arg_iterator E, + NodeTy* Pred, NodeSet& Dst); + + void VisitObjCMessageExprDispatchHelper(ObjCMessageExpr* ME, NodeTy* Pred, + NodeSet& Dst); + /// VisitReturnStmt - Transfer function logic for return statements. void VisitReturnStmt(ReturnStmt* R, NodeTy* Pred, NodeSet& Dst); @@ -541,8 +560,8 @@ protected: /// VisitUnaryOperator - Transfer function logic for unary operators. void VisitUnaryOperator(UnaryOperator* B, NodeTy* Pred, NodeSet& Dst); - void VisitDeref(UnaryOperator* U, NodeTy* Pred, NodeSet& Dst, - bool GetLVal = false); + + RVal EvalCast(RVal X, QualType CastT) { if (X.isUnknownOrUndef()) @@ -554,6 +573,8 @@ protected: return TF->EvalCast(*this, cast(X), CastT); } + + RVal EvalMinus(UnaryOperator* U, RVal X) { return X.isValid() ? TF->EvalMinus(*this, U, cast(X)) : X; } diff --git a/lib/Analysis/GRExprEngine.cpp b/lib/Analysis/GRExprEngine.cpp index 8c771bffa1..86d2cc9ae5 100644 --- a/lib/Analysis/GRExprEngine.cpp +++ b/lib/Analysis/GRExprEngine.cpp @@ -285,6 +285,11 @@ void GRExprEngine::Visit(Stmt* S, NodeTy* Pred, NodeSet& Dst) { break; } + case Stmt::MemberExprClass: { + VisitMemberExpr(cast(S), Pred, Dst, false); + break; + } + case Stmt::ObjCMessageExprClass: { VisitObjCMessageExpr(cast(S), Pred, Dst); break; @@ -709,6 +714,36 @@ void GRExprEngine::VisitDeclRefExpr(DeclRefExpr* D, NodeTy* Pred, NodeSet& Dst){ MakeNode(Dst, D, Pred, SetBlkExprRVal(St, D, Y)); } +/// VisitMemberExpr - Transfer function for member expressions. +void GRExprEngine::VisitMemberExpr(MemberExpr* M, NodeTy* Pred, + NodeSet& Dst, bool asLVal) { + + Expr* Base = M->getBase()->IgnoreParens(); + + NodeSet Tmp; + VisitLVal(Base, Pred, Tmp); + + if (Base->getType()->isPointerType()) { + NodeSet Tmp2; + + 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); + } + + for (NodeSet::iterator I=Tmp2.begin(), E=Tmp2.end(); I!=E; ++I) + VisitMemberExprField(M, Base, *I, Dst, asLVal); + } + 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) { @@ -1149,9 +1184,9 @@ void GRExprEngine::VisitSizeOfAlignOfTypeExpr(SizeOfAlignOfTypeExpr* Ex, void GRExprEngine::VisitDeref(UnaryOperator* U, NodeTy* Pred, NodeSet& Dst, bool GetLVal) { - + Expr* Ex = U->getSubExpr()->IgnoreParens(); - + NodeSet DstTmp; if (isa(Ex)) @@ -1160,82 +1195,80 @@ void GRExprEngine::VisitDeref(UnaryOperator* U, NodeTy* Pred, Visit(Ex, Pred, DstTmp); for (NodeSet::iterator I = DstTmp.begin(), DE = DstTmp.end(); I != DE; ++I) { - - NodeTy* N = *I; - ValueState* St = GetState(N); - - // FIXME: Bifurcate when dereferencing a symbolic with no constraints? - + ValueState* St = GetState(Pred); RVal V = GetRVal(St, Ex); - - // Check for dereferences of undefined values. - - if (V.isUndef()) { - - NodeTy* Succ = Builder->generateNode(U, St, N); - - if (Succ) { - Succ->markAsSink(); - UndefDeref.insert(Succ); - } - - continue; - } - - // Check for dereferences of unknown values. Treat as No-Ops. - - if (V.isUnknown()) { - Dst.Add(N); - continue; + VisitDeref(U, V, St, Pred, 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); } - // 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(V); - bool isFeasibleNotNull; - - // "Assume" that the pointer is Not-NULL. - - ValueState* StNotNull = Assume(St, LV, true, isFeasibleNotNull); + 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(V); + bool isFeasibleNotNull; + + // "Assume" that the pointer is Not-NULL. + + ValueState* StNotNull = Assume(St, LV, true, isFeasibleNotNull); + + if (isFeasibleNotNull) { - if (isFeasibleNotNull) { - - if (GetLVal) MakeNode(Dst, U, N, SetRVal(StNotNull, U, LV)); - else { - - // FIXME: Currently symbolic analysis "generates" new symbols - // for the contents of values. We need a better approach. + if (GetLVal) + MakeNode(Dst, Ex, Pred, SetRVal(StNotNull, Ex, LV)); + else { - MakeNode(Dst, U, N, SetRVal(StNotNull, U, - GetRVal(StNotNull, LV, U->getType()))); - } + // 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) { - bool isFeasibleNull; - - // Now "assume" that the pointer is NULL. + // We don't use "MakeNode" here because the node will be a sink + // and we have no intention of processing it later. - ValueState* StNull = Assume(St, LV, false, isFeasibleNull); + NodeTy* NullNode = Builder->generateNode(Ex, StNull, Pred); - if (isFeasibleNull) { + if (NullNode) { - // 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(U, StNull, N); + NullNode->markAsSink(); - if (NullNode) { - - NullNode->markAsSink(); - - if (isFeasibleNotNull) ImplicitNullDeref.insert(NullNode); - else ExplicitNullDeref.insert(NullNode); - } - } + if (isFeasibleNotNull) ImplicitNullDeref.insert(NullNode); + else ExplicitNullDeref.insert(NullNode); + } } } @@ -1387,23 +1420,36 @@ void GRExprEngine::VisitSizeOfExpr(UnaryOperator* U, NodeTy* Pred, void GRExprEngine::VisitLVal(Expr* Ex, NodeTy* Pred, NodeSet& Dst) { - if (Ex != CurrentStmt && getCFG().isBlkExpr(Ex)) { - Dst.Add(Pred); - return; - } - Ex = Ex->IgnoreParens(); - - if (isa(Ex)) { + + if (Ex != CurrentStmt && getCFG().isBlkExpr(Ex)) { Dst.Add(Pred); return; } - if (UnaryOperator* U = dyn_cast(Ex)) - if (U->getOpcode() == UnaryOperator::Deref) { - VisitDeref(U, Pred, Dst, true); + switch (Ex->getStmtClass()) { + default: + break; + + case Stmt::DeclRefExprClass: + Dst.Add(Pred); return; + + case Stmt::UnaryOperatorClass: { + UnaryOperator* U = cast(Ex); + + if (U->getOpcode() == UnaryOperator::Deref) { + VisitDeref(U, Pred, Dst, true); + return; + } + + break; } + + case Stmt::MemberExprClass: + VisitMemberExpr(cast(Ex), Pred, Dst, true); + return; + } Visit(Ex, Pred, Dst); }