diff options
author | Devin Coughlin <dcoughlin@apple.com> | 2016-12-15 21:27:06 +0000 |
---|---|---|
committer | Devin Coughlin <dcoughlin@apple.com> | 2016-12-15 21:27:06 +0000 |
commit | 64c01f7bef8d65716f12e7556238ea8f8c2c010e (patch) | |
tree | 41fb79676ba342a7cfb2638af738338f2b0d25ec /clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | |
parent | 6698c15cb64c5a6b27521466ab8565a906b2323f (diff) | |
download | bcm5719-llvm-64c01f7bef8d65716f12e7556238ea8f8c2c010e.tar.gz bcm5719-llvm-64c01f7bef8d65716f12e7556238ea8f8c2c010e.zip |
[analyzer] Add a new SVal to support pointer-to-member operations.
Add a new type of NonLoc SVal for C++ pointer-to-member operations. This SVal
supports both pointers to member functions and pointers to member data.
A patch by Kirill Romanenkov!
Differential Revision: https://reviews.llvm.org/D25475
llvm-svn: 289873
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp | 161 |
1 files changed, 119 insertions, 42 deletions
diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp index cae6ea03aea..f1238f6d357 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -12,6 +12,7 @@ //===----------------------------------------------------------------------===// #include "clang/AST/ExprCXX.h" +#include "clang/AST/DeclCXX.h" #include "clang/StaticAnalyzer/Core/CheckerManager.h" #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" @@ -246,6 +247,38 @@ void ExprEngine::VisitBlockExpr(const BlockExpr *BE, ExplodedNode *Pred, getCheckerManager().runCheckersForPostStmt(Dst, Tmp, BE, *this); } +ProgramStateRef ExprEngine::handleLValueBitCast( + ProgramStateRef state, const Expr* Ex, const LocationContext* LCtx, + QualType T, QualType ExTy, const CastExpr* CastE, StmtNodeBuilder& Bldr, + ExplodedNode* Pred) { + // Delegate to SValBuilder to process. + SVal V = state->getSVal(Ex, LCtx); + V = svalBuilder.evalCast(V, T, ExTy); + // Negate the result if we're treating the boolean as a signed i1 + if (CastE->getCastKind() == CK_BooleanToSignedIntegral) + V = evalMinus(V); + state = state->BindExpr(CastE, LCtx, V); + Bldr.generateNode(CastE, Pred, state); + + return state; +} + +ProgramStateRef ExprEngine::handleLVectorSplat( + ProgramStateRef state, const LocationContext* LCtx, const CastExpr* CastE, + StmtNodeBuilder &Bldr, ExplodedNode* Pred) { + // Recover some path sensitivity by conjuring a new value. + QualType resultType = CastE->getType(); + if (CastE->isGLValue()) + resultType = getContext().getPointerType(resultType); + SVal result = svalBuilder.conjureSymbolVal(nullptr, CastE, LCtx, + resultType, + currBldrCtx->blockCount()); + state = state->BindExpr(CastE, LCtx, result); + Bldr.generateNode(CastE, Pred, state); + + return state; +} + void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst) { @@ -310,8 +343,21 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, continue; } case CK_MemberPointerToBoolean: - // FIXME: For now, member pointers are represented by void *. - // FALLTHROUGH + case CK_PointerToBoolean: { + SVal V = state->getSVal(Ex, LCtx); + auto PTMSV = V.getAs<nonloc::PointerToMember>(); + if (PTMSV) + V = svalBuilder.makeTruthVal(!PTMSV->isNullMemberPointer(), ExTy); + if (V.isUndef() || PTMSV) { + state = state->BindExpr(CastE, LCtx, V); + Bldr.generateNode(CastE, Pred, state); + continue; + } + // Explicitly proceed with default handler for this case cascade. + state = + handleLValueBitCast(state, Ex, LCtx, T, ExTy, CastE, Bldr, Pred); + continue; + } case CK_Dependent: case CK_ArrayToPointerDecay: case CK_BitCast: @@ -319,8 +365,18 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, case CK_BooleanToSignedIntegral: case CK_NullToPointer: case CK_IntegralToPointer: - case CK_PointerToIntegral: - case CK_PointerToBoolean: + case CK_PointerToIntegral: { + SVal V = state->getSVal(Ex, LCtx); + if (V.getAs<nonloc::PointerToMember>()) { + state = state->BindExpr(CastE, LCtx, UnknownVal()); + Bldr.generateNode(CastE, Pred, state); + continue; + } + // Explicitly proceed with default handler for this case cascade. + state = + handleLValueBitCast(state, Ex, LCtx, T, ExTy, CastE, Bldr, Pred); + continue; + } case CK_IntegralToBoolean: case CK_IntegralToFloating: case CK_FloatingToIntegral: @@ -343,14 +399,8 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, case CK_ZeroToOCLEvent: case CK_IntToOCLSampler: case CK_LValueBitCast: { - // Delegate to SValBuilder to process. - SVal V = state->getSVal(Ex, LCtx); - V = svalBuilder.evalCast(V, T, ExTy); - // Negate the result if we're treating the boolean as a signed i1 - if (CastE->getCastKind() == CK_BooleanToSignedIntegral) - V = evalMinus(V); - state = state->BindExpr(CastE, LCtx, V); - Bldr.generateNode(CastE, Pred, state); + state = + handleLValueBitCast(state, Ex, LCtx, T, ExTy, CastE, Bldr, Pred); continue; } case CK_IntegralCast: { @@ -435,27 +485,32 @@ void ExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex, continue; } case CK_NullToMemberPointer: { - // FIXME: For now, member pointers are represented by void *. - SVal V = svalBuilder.makeNull(); + SVal V = svalBuilder.getMemberPointer(nullptr); state = state->BindExpr(CastE, LCtx, V); Bldr.generateNode(CastE, Pred, state); continue; } + case CK_DerivedToBaseMemberPointer: + case CK_BaseToDerivedMemberPointer: + case CK_ReinterpretMemberPointer: { + SVal V = state->getSVal(Ex, LCtx); + if (auto PTMSV = V.getAs<nonloc::PointerToMember>()) { + SVal CastedPTMSV = svalBuilder.makePointerToMember( + getBasicVals().accumCXXBase( + llvm::make_range<CastExpr::path_const_iterator>( + CastE->path_begin(), CastE->path_end()), *PTMSV)); + state = state->BindExpr(CastE, LCtx, CastedPTMSV); + Bldr.generateNode(CastE, Pred, state); + continue; + } + // Explicitly proceed with default handler for this case cascade. + state = handleLVectorSplat(state, LCtx, CastE, Bldr, Pred); + continue; + } // Various C++ casts that are not handled yet. case CK_ToUnion: - case CK_BaseToDerivedMemberPointer: - case CK_DerivedToBaseMemberPointer: - case CK_ReinterpretMemberPointer: case CK_VectorSplat: { - // Recover some path-sensitivty by conjuring a new value. - QualType resultType = CastE->getType(); - if (CastE->isGLValue()) - resultType = getContext().getPointerType(resultType); - SVal result = svalBuilder.conjureSymbolVal(nullptr, CastE, LCtx, - resultType, - currBldrCtx->blockCount()); - state = state->BindExpr(CastE, LCtx, result); - Bldr.generateNode(CastE, Pred, state); + state = handleLVectorSplat(state, LCtx, CastE, Bldr, Pred); continue; } } @@ -658,7 +713,7 @@ void ExprEngine::VisitInitListExpr(const InitListExpr *IE, for (InitListExpr::const_reverse_iterator it = IE->rbegin(), ei = IE->rend(); it != ei; ++it) { SVal V = state->getSVal(cast<Expr>(*it), LCtx); - vals = getBasicVals().consVals(V, vals); + vals = getBasicVals().prependSVal(V, vals); } B.generateNode(IE, Pred, @@ -803,8 +858,24 @@ VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex, getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, Ex, *this); } -void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, - ExplodedNode *Pred, +void ExprEngine::handleUOExtension(ExplodedNodeSet::iterator I, + const UnaryOperator *U, + StmtNodeBuilder &Bldr) { + // FIXME: We can probably just have some magic in Environment::getSVal() + // that propagates values, instead of creating a new node here. + // + // 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. + const Expr *Ex = U->getSubExpr()->IgnoreParens(); + ProgramStateRef state = (*I)->getState(); + const LocationContext *LCtx = (*I)->getLocationContext(); + Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, + state->getSVal(Ex, LCtx))); +} + +void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, ExplodedNode *Pred, ExplodedNodeSet &Dst) { // FIXME: Prechecks eventually go in ::Visit(). ExplodedNodeSet CheckedSet; @@ -856,24 +927,30 @@ void ExprEngine::VisitUnaryOperator(const UnaryOperator* U, break; } + case UO_AddrOf: { + // Process pointer-to-member address operation. + const Expr *Ex = U->getSubExpr()->IgnoreParens(); + if (const DeclRefExpr *DRE = dyn_cast<DeclRefExpr>(Ex)) { + const ValueDecl *VD = DRE->getDecl(); + + if (isa<CXXMethodDecl>(VD) || isa<FieldDecl>(VD)) { + ProgramStateRef State = (*I)->getState(); + const LocationContext *LCtx = (*I)->getLocationContext(); + SVal SV = svalBuilder.getMemberPointer(cast<DeclaratorDecl>(VD)); + Bldr.generateNode(U, *I, State->BindExpr(U, LCtx, SV)); + break; + } + } + // Explicitly proceed with default handler for this case cascade. + handleUOExtension(I, U, Bldr); + break; + } case UO_Plus: assert(!U->isGLValue()); // FALL-THROUGH. case UO_Deref: - case UO_AddrOf: case UO_Extension: { - // FIXME: We can probably just have some magic in Environment::getSVal() - // that propagates values, instead of creating a new node here. - // - // 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. - const Expr *Ex = U->getSubExpr()->IgnoreParens(); - ProgramStateRef state = (*I)->getState(); - const LocationContext *LCtx = (*I)->getLocationContext(); - Bldr.generateNode(U, *I, state->BindExpr(U, LCtx, - state->getSVal(Ex, LCtx))); + handleUOExtension(I, U, Bldr); break; } |