diff options
Diffstat (limited to 'lib/StaticAnalyzer/Core')
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngine.cpp | 33 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 64 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp | 2 |
3 files changed, 73 insertions, 26 deletions
diff --git a/lib/StaticAnalyzer/Core/ExprEngine.cpp b/lib/StaticAnalyzer/Core/ExprEngine.cpp index 789abb7d86..ffc382fcf0 100644 --- a/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -432,14 +432,41 @@ void ExprEngine::ProcessInitializer(const CFGInitializer Init, // but non-objects must be copied in from the initializer. const Expr *Init = BMI->getInit()->IgnoreImplicit(); if (!isa<CXXConstructExpr>(Init)) { + const ValueDecl *Field; SVal FieldLoc; - if (BMI->isIndirectMemberInitializer()) + if (BMI->isIndirectMemberInitializer()) { + Field = BMI->getIndirectMember(); FieldLoc = State->getLValue(BMI->getIndirectMember(), thisVal); - else + } else { + Field = BMI->getMember(); FieldLoc = State->getLValue(BMI->getMember(), thisVal); + } - SVal InitVal = State->getSVal(BMI->getInit(), stackFrame); + SVal InitVal; + if (BMI->getNumArrayIndices() > 0) { + // Handle arrays of trivial type. We can represent this with a + // primitive load/copy from the base array region. + const ArraySubscriptExpr *ASE; + while ((ASE = dyn_cast<ArraySubscriptExpr>(Init))) + Init = ASE->getBase()->IgnoreImplicit(); + + SVal LValue = State->getSVal(Init, stackFrame); + if (Optional<Loc> LValueLoc = LValue.getAs<Loc>()) + InitVal = State->getSVal(*LValueLoc); + + // If we fail to get the value for some reason, use a symbolic value. + if (InitVal.isUnknownOrUndef()) { + SValBuilder &SVB = getSValBuilder(); + InitVal = SVB.conjureSymbolVal(BMI->getInit(), stackFrame, + Field->getType(), + currBldrCtx->blockCount()); + } + } else { + InitVal = State->getSVal(BMI->getInit(), stackFrame); + } + assert(Tmp.size() == 1 && "have not generated any new nodes yet"); + assert(*Tmp.begin() == Pred && "have not generated any new nodes yet"); Tmp.clear(); evalBind(Tmp, Init, Pred, FieldLoc, InitVal, /*isInit=*/true, &PP); } diff --git a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index b0f2579cd9..ed90dc5891 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -96,6 +96,26 @@ void ExprEngine::performTrivialCopy(NodeBuilder &Bldr, ExplodedNode *Pred, } } + +/// Returns a region representing the first element of a (possibly +/// multi-dimensional) array. +/// +/// On return, \p Ty will be set to the base type of the array. +/// +/// If the type is not an array type at all, the original value is returned. +static SVal makeZeroElementRegion(ProgramStateRef State, SVal LValue, + QualType &Ty) { + SValBuilder &SVB = State->getStateManager().getSValBuilder(); + ASTContext &Ctx = SVB.getContext(); + + while (const ArrayType *AT = Ctx.getAsArrayType(Ty)) { + Ty = AT->getElementType(); + LValue = State->getLValue(Ty, SVB.makeZeroArrayIndex(), LValue); + } + + return LValue; +} + void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, ExplodedNode *Pred, ExplodedNodeSet &destNodes) { @@ -103,7 +123,10 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, ProgramStateRef State = Pred->getState(); const MemRegion *Target = 0; - bool IsArray = false; + + // FIXME: Handle arrays, which run the same constructor for every element. + // For now, we just run the first constructor (which should still invalidate + // the entire array). switch (CE->getConstructionKind()) { case CXXConstructExpr::CK_Complete: { @@ -118,19 +141,10 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, if (const DeclStmt *DS = dyn_cast<DeclStmt>(StmtElem->getStmt())) { if (const VarDecl *Var = dyn_cast<VarDecl>(DS->getSingleDecl())) { if (Var->getInit()->IgnoreImplicit() == CE) { + SVal LValue = State->getLValue(Var, LCtx); QualType Ty = Var->getType(); - if (const ArrayType *AT = getContext().getAsArrayType(Ty)) { - // FIXME: Handle arrays, which run the same constructor for - // every element. This workaround will just run the first - // constructor (which should still invalidate the entire array). - SVal Base = State->getLValue(Var, LCtx); - Target = State->getLValue(AT->getElementType(), - getSValBuilder().makeZeroArrayIndex(), - Base).getAsRegion(); - IsArray = true; - } else { - Target = State->getLValue(Var, LCtx).getAsRegion(); - } + LValue = makeZeroElementRegion(State, LValue, Ty); + Target = LValue.getAsRegion(); } } } @@ -146,13 +160,19 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, LCtx->getCurrentStackFrame()); SVal ThisVal = State->getSVal(ThisPtr); + const ValueDecl *Field; + SVal FieldVal; if (Init->isIndirectMemberInitializer()) { - SVal Field = State->getLValue(Init->getIndirectMember(), ThisVal); - Target = Field.getAsRegion(); + Field = Init->getIndirectMember(); + FieldVal = State->getLValue(Init->getIndirectMember(), ThisVal); } else { - SVal Field = State->getLValue(Init->getMember(), ThisVal); - Target = Field.getAsRegion(); + Field = Init->getMember(); + FieldVal = State->getLValue(Init->getMember(), ThisVal); } + + QualType Ty = Field->getType(); + FieldVal = makeZeroElementRegion(State, FieldVal, Ty); + Target = FieldVal.getAsRegion(); } // FIXME: This will eventually need to handle new-expressions as well. @@ -202,6 +222,7 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, ExplodedNodeSet DstEvaluated; StmtNodeBuilder Bldr(DstPreCall, DstEvaluated, *currBldrCtx); + bool IsArray = isa<ElementRegion>(Target); if (CE->getConstructor()->isTrivial() && CE->getConstructor()->isCopyOrMoveConstructor() && !IsArray) { @@ -234,12 +255,9 @@ void ExprEngine::VisitCXXDestructor(QualType ObjectType, // FIXME: We need to run the same destructor on every element of the array. // This workaround will just run the first destructor (which will still // invalidate the entire array). - // This is a loop because of multidimensional arrays. - while (const ArrayType *AT = getContext().getAsArrayType(ObjectType)) { - ObjectType = AT->getElementType(); - Dest = State->getLValue(ObjectType, getSValBuilder().makeZeroArrayIndex(), - loc::MemRegionVal(Dest)).getAsRegion(); - } + SVal DestVal = loc::MemRegionVal(Dest); + DestVal = makeZeroElementRegion(State, DestVal, ObjectType); + Dest = DestVal.getAsRegion(); const CXXRecordDecl *RecordDecl = ObjectType->getAsCXXRecordDecl(); assert(RecordDecl && "Only CXXRecordDecls should have destructors"); diff --git a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp index ee603d728e..f01e4e7640 100644 --- a/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp +++ b/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp @@ -605,6 +605,8 @@ static CallInlinePolicy mayInlineCallKind(const CallEvent &Call, const CXXConstructorCall &Ctor = cast<CXXConstructorCall>(Call); // FIXME: We don't handle constructors or destructors for arrays properly. + // Even once we do, we still need to be careful about implicitly-generated + // initializers for array fields in default move/copy constructors. const MemRegion *Target = Ctor.getCXXThisVal().getAsRegion(); if (Target && isa<ElementRegion>(Target)) return CIP_DisallowedOnce; |