From: Jordan Rose Date: Wed, 11 Dec 2013 17:58:10 +0000 (+0000) Subject: [analyzer] Add checker callbacks for MemberExpr and UnaryExprOrTypeTraitExpr. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3b147785f249c388f6c1a0a229aca245cb8ba473;p=clang [analyzer] Add checker callbacks for MemberExpr and UnaryExprOrTypeTraitExpr. Found by Arthur Yoo! git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@197059 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index e0a764a1a6..970fecd1b4 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -1751,75 +1751,85 @@ void ExprEngine::VisitLvalArraySubscriptExpr(const ArraySubscriptExpr *A, /// VisitMemberExpr - Transfer function for member expressions. void ExprEngine::VisitMemberExpr(const MemberExpr *M, ExplodedNode *Pred, - ExplodedNodeSet &TopDst) { + ExplodedNodeSet &Dst) { - StmtNodeBuilder Bldr(Pred, TopDst, *currBldrCtx); - ExplodedNodeSet Dst; + // FIXME: Prechecks eventually go in ::Visit(). + ExplodedNodeSet CheckedSet; + getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, M, *this); + + ExplodedNodeSet EvalSet; ValueDecl *Member = M->getMemberDecl(); // Handle static member variables and enum constants accessed via // member syntax. if (isa(Member) || isa(Member)) { - Bldr.takeNodes(Pred); - VisitCommonDeclRefExpr(M, Member, Pred, Dst); - Bldr.addNodes(Dst); - return; - } - - ProgramStateRef state = Pred->getState(); - const LocationContext *LCtx = Pred->getLocationContext(); - Expr *BaseExpr = M->getBase(); + ExplodedNodeSet Dst; + for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); + I != E; ++I) { + VisitCommonDeclRefExpr(M, Member, Pred, EvalSet); + } + } else { + StmtNodeBuilder Bldr(CheckedSet, EvalSet, *currBldrCtx); + ExplodedNodeSet Tmp; - // Handle C++ method calls. - if (const CXXMethodDecl *MD = dyn_cast(Member)) { - if (MD->isInstance()) - state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); + for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); + I != E; ++I) { + ProgramStateRef state = (*I)->getState(); + const LocationContext *LCtx = (*I)->getLocationContext(); + Expr *BaseExpr = M->getBase(); - SVal MDVal = svalBuilder.getFunctionPointer(MD); - state = state->BindExpr(M, LCtx, MDVal); + // Handle C++ method calls. + if (const CXXMethodDecl *MD = dyn_cast(Member)) { + if (MD->isInstance()) + state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); - Bldr.generateNode(M, Pred, state); - return; - } + SVal MDVal = svalBuilder.getFunctionPointer(MD); + state = state->BindExpr(M, LCtx, MDVal); - // Handle regular struct fields / member variables. - state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); - SVal baseExprVal = state->getSVal(BaseExpr, LCtx); - - FieldDecl *field = cast(Member); - SVal L = state->getLValue(field, baseExprVal); - - if (M->isGLValue() || M->getType()->isArrayType()) { - - // We special case rvalue of array type because the analyzer cannot reason - // about it, since we expect all regions to be wrapped in Locs. So we will - // treat these as lvalues assuming that they will decay to pointers as soon - // as they are used. - if (!M->isGLValue()) { - assert(M->getType()->isArrayType()); - const ImplicitCastExpr *PE = - dyn_cast(Pred->getParentMap().getParent(M)); - if (!PE || PE->getCastKind() != CK_ArrayToPointerDecay) { - assert(false && - "We assume that array is always wrapped in ArrayToPointerDecay"); - L = UnknownVal(); + Bldr.generateNode(M, *I, state); + continue; } - } - if (field->getType()->isReferenceType()) { - if (const MemRegion *R = L.getAsRegion()) - L = state->getSVal(R); - else - L = UnknownVal(); - } + // Handle regular struct fields / member variables. + state = createTemporaryRegionIfNeeded(state, LCtx, BaseExpr); + SVal baseExprVal = state->getSVal(BaseExpr, LCtx); + + FieldDecl *field = cast(Member); + SVal L = state->getLValue(field, baseExprVal); + + if (M->isGLValue() || M->getType()->isArrayType()) { + // We special-case rvalues of array type because the analyzer cannot + // reason about them, since we expect all regions to be wrapped in Locs. + // We instead treat these as lvalues and assume that they will decay to + // pointers as soon as they are used. + if (!M->isGLValue()) { + assert(M->getType()->isArrayType()); + const ImplicitCastExpr *PE = + dyn_cast((*I)->getParentMap().getParent(M)); + if (!PE || PE->getCastKind() != CK_ArrayToPointerDecay) { + llvm_unreachable("should always be wrapped in ArrayToPointerDecay"); + L = UnknownVal(); + } + } - Bldr.generateNode(M, Pred, state->BindExpr(M, LCtx, L), 0, - ProgramPoint::PostLValueKind); - } else { - Bldr.takeNodes(Pred); - evalLoad(Dst, M, M, Pred, state, L); - Bldr.addNodes(Dst); + if (field->getType()->isReferenceType()) { + if (const MemRegion *R = L.getAsRegion()) + L = state->getSVal(R); + else + L = UnknownVal(); + } + + Bldr.generateNode(M, *I, state->BindExpr(M, LCtx, L), 0, + ProgramPoint::PostLValueKind); + } else { + Bldr.takeNodes(*I); + evalLoad(Tmp, M, M, *I, state, L); + Bldr.addNodes(Tmp); + } + } } + + getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, M, *this); } namespace { diff --git a/lib/StaticAnalyzer/Core/ExprEngineC.cpp b/lib/StaticAnalyzer/Core/ExprEngineC.cpp index 9ba086ce71..d79d8fc688 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineC.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineC.cpp @@ -708,34 +708,43 @@ void ExprEngine:: VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *Ex, ExplodedNode *Pred, ExplodedNodeSet &Dst) { - StmtNodeBuilder Bldr(Pred, Dst, *currBldrCtx); + // FIXME: Prechecks eventually go in ::Visit(). + ExplodedNodeSet CheckedSet; + getCheckerManager().runCheckersForPreStmt(CheckedSet, Pred, Ex, *this); + + ExplodedNodeSet EvalSet; + StmtNodeBuilder Bldr(CheckedSet, EvalSet, *currBldrCtx); QualType T = Ex->getTypeOfArgument(); - - if (Ex->getKind() == UETT_SizeOf) { - if (!T->isIncompleteType() && !T->isConstantSizeType()) { - assert(T->isVariableArrayType() && "Unknown non-constant-sized type."); - - // FIXME: Add support for VLA type arguments and VLA expressions. - // When that happens, we should probably refactor VLASizeChecker's code. - return; - } - else if (T->getAs()) { - // Some code tries to take the sizeof an ObjCObjectType, relying that - // the compiler has laid out its representation. Just report Unknown - // for these. - return; + + for (ExplodedNodeSet::iterator I = CheckedSet.begin(), E = CheckedSet.end(); + I != E; ++I) { + if (Ex->getKind() == UETT_SizeOf) { + if (!T->isIncompleteType() && !T->isConstantSizeType()) { + assert(T->isVariableArrayType() && "Unknown non-constant-sized type."); + + // FIXME: Add support for VLA type arguments and VLA expressions. + // When that happens, we should probably refactor VLASizeChecker's code. + continue; + } else if (T->getAs()) { + // Some code tries to take the sizeof an ObjCObjectType, relying that + // the compiler has laid out its representation. Just report Unknown + // for these. + continue; + } } + + APSInt Value = Ex->EvaluateKnownConstInt(getContext()); + CharUnits amt = CharUnits::fromQuantity(Value.getZExtValue()); + + ProgramStateRef state = (*I)->getState(); + state = state->BindExpr(Ex, (*I)->getLocationContext(), + svalBuilder.makeIntVal(amt.getQuantity(), + Ex->getType())); + Bldr.generateNode(Ex, *I, state); } - - APSInt Value = Ex->EvaluateKnownConstInt(getContext()); - CharUnits amt = CharUnits::fromQuantity(Value.getZExtValue()); - - ProgramStateRef state = Pred->getState(); - state = state->BindExpr(Ex, Pred->getLocationContext(), - svalBuilder.makeIntVal(amt.getQuantity(), - Ex->getType())); - Bldr.generateNode(Ex, Pred, state); + + getCheckerManager().runCheckersForPostStmt(Dst, EvalSet, Ex, *this); } void ExprEngine::VisitUnaryOperator(const UnaryOperator* U,