Author: dergachev Date: Wed Jun 13 18:32:46 2018 New Revision: 334681 URL: http://llvm.org/viewvc/llvm-project?rev=334681&view=rev Log: [analyzer] pr37270: Track constructor target region, even if just a variable.
The very idea of construction context implies that first the object is constructed, and then later, in a separate moment of time, the constructed object goes into scope, i.e. becomes "live". Most construction contexts require path-sensitive tracking of the constructed object region in order to compute the outer expressions accordingly before the object becomes live. Semantics of simple variable construction contexts don't immediately require that such tracking happens in path-sensitive manner, but shortcomings of the analyzer force us to track it path-sensitively as well. Namely, whether construction context was available at all during construction is a path-sensitive information. Additionally, path-sensitive tracking takes care of our liveness problems that kick in as the temporal gap between construction and going-into-scope becomes larger (eg., due to copy elision). Differential Revision: https://reviews.llvm.org/D47305 Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp cfe/trunk/test/Analysis/cxx17-mandatory-elision.cpp Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp?rev=334681&r1=334680&r2=334681&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineC.cpp Wed Jun 13 18:32:46 2018 @@ -590,24 +590,12 @@ void ExprEngine::VisitDeclStmt(const Dec SVal InitVal = state->getSVal(InitEx, LC); assert(DS->isSingleDecl()); - if (auto *CtorExpr = findDirectConstructorForCurrentCFGElement()) { - assert(InitEx->IgnoreImplicit() == CtorExpr); - (void)CtorExpr; + if (getObjectUnderConstruction(state, DS, LC)) { + state = finishObjectConstruction(state, DS, LC); // We constructed the object directly in the variable. // No need to bind anything. B.generateNode(DS, UpdatedN, state); } else { - // We bound the temp obj region to the CXXConstructExpr. Now recover - // the lazy compound value when the variable is not a reference. - if (AMgr.getLangOpts().CPlusPlus && VD->getType()->isRecordType() && - !VD->getType()->isReferenceType()) { - if (Optional<loc::MemRegionVal> M = - InitVal.getAs<loc::MemRegionVal>()) { - InitVal = state->getSVal(M->getRegion()); - assert(InitVal.getAs<nonloc::LazyCompoundVal>()); - } - } - // Recover some path-sensitivity if a scalar value evaluated to // UnknownVal. if (InitVal.isUnknown()) { Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp?rev=334681&r1=334680&r2=334681&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp Wed Jun 13 18:32:46 2018 @@ -125,9 +125,11 @@ std::pair<ProgramStateRef, SVal> ExprEng const auto *Var = cast<VarDecl>(DS->getSingleDecl()); SVal LValue = State->getLValue(Var, LCtx); QualType Ty = Var->getType(); - return std::make_pair( - State, - makeZeroElementRegion(State, LValue, Ty, CallOpts.IsArrayCtorOrDtor)); + LValue = + makeZeroElementRegion(State, LValue, Ty, CallOpts.IsArrayCtorOrDtor); + State = + addObjectUnderConstruction(State, DSCC->getDeclStmt(), LCtx, LValue); + return std::make_pair(State, LValue); } case ConstructionContext::SimpleConstructorInitializerKind: { const auto *ICC = cast<ConstructorInitializerConstructionContext>(CC); Modified: cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp?rev=334681&r1=334680&r2=334681&view=diff ============================================================================== --- cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp (original) +++ cfe/trunk/lib/StaticAnalyzer/Core/ExprEngineCallAndReturn.cpp Wed Jun 13 18:32:46 2018 @@ -193,23 +193,6 @@ static bool wasDifferentDeclUsedForInlin return RuntimeCallee->getCanonicalDecl() != StaticDecl->getCanonicalDecl(); } -/// Returns true if the CXXConstructExpr \p E was intended to construct a -/// prvalue for the region in \p V. -/// -/// Note that we can't just test for rvalue vs. glvalue because -/// CXXConstructExprs embedded in DeclStmts and initializers are considered -/// rvalues by the AST, and the analyzer would like to treat them as lvalues. -static bool isTemporaryPRValue(const CXXConstructExpr *E, SVal V) { - if (E->isGLValue()) - return false; - - const MemRegion *MR = V.getAsRegion(); - if (!MR) - return false; - - return isa<CXXTempObjectRegion>(MR); -} - /// The call exit is simulated with a sequence of nodes, which occur between /// CallExitBegin and CallExitEnd. The following operations occur between the /// two program points: @@ -269,11 +252,7 @@ void ExprEngine::processCallExit(Explode loc::MemRegionVal This = svalBuilder.getCXXThis(CCE->getConstructor()->getParent(), calleeCtx); SVal ThisV = state->getSVal(This); - - // If the constructed object is a temporary prvalue, get its bindings. - if (isTemporaryPRValue(CCE, ThisV)) - ThisV = state->getSVal(ThisV.castAs<Loc>()); - + ThisV = state->getSVal(ThisV.castAs<Loc>()); state = state->BindExpr(CCE, callerCtx, ThisV); } @@ -574,11 +553,7 @@ ProgramStateRef ExprEngine::bindReturnVa } } else if (const CXXConstructorCall *C = dyn_cast<CXXConstructorCall>(&Call)){ SVal ThisV = C->getCXXThisVal(); - - // If the constructed object is a temporary prvalue, get its bindings. - if (isTemporaryPRValue(cast<CXXConstructExpr>(E), ThisV)) - ThisV = State->getSVal(ThisV.castAs<Loc>()); - + ThisV = State->getSVal(ThisV.castAs<Loc>()); return State->BindExpr(E, LCtx, ThisV); } Modified: cfe/trunk/test/Analysis/cxx17-mandatory-elision.cpp URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/Analysis/cxx17-mandatory-elision.cpp?rev=334681&r1=334680&r2=334681&view=diff ============================================================================== --- cfe/trunk/test/Analysis/cxx17-mandatory-elision.cpp (original) +++ cfe/trunk/test/Analysis/cxx17-mandatory-elision.cpp Wed Jun 13 18:32:46 2018 @@ -3,6 +3,26 @@ void clang_analyzer_eval(bool); +namespace variable_functional_cast_crash { + +struct A { + A(int) {} +}; + +void foo() { + A a = A(0); +} + +struct B { + A a; + B(): a(A(0)) {} +}; + +} // namespace variable_functional_cast_crash + + +namespace address_vector_tests { + template <typename T> struct AddressVector { T *buf[10]; int len; @@ -56,3 +76,5 @@ void testMultipleReturns() { clang_analyzer_eval(v.buf[4] == &c); // expected-warning{{TRUE}} #endif } + +} // namespace address_vector_tests _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits