From 3ccf14eb8e17aa166a456f6fec527f4fa97ecc71 Mon Sep 17 00:00:00 2001 From: Artem Dergachev Date: Wed, 15 Aug 2018 00:33:55 +0000 Subject: [analyzer] Add support for constructors of arguments. Once CFG-side support for argument construction contexts landed in r338436, the analyzer could make use of them to evaluate argument constructors properly. When evaluated as calls, constructors of arguments now use the variable region of the parameter as their target. The corresponding stack frame does not yet exist when the parameter is constructed, and this stack frame is created eagerly. Construction of functions whose body is unavailable and of virtual functions is not yet supported. Part of the reason is the analyzer doesn't consistently use canonical declarations o identify the function in these cases, and every re-declaration or potential override comes with its own set of parameter declarations. Also it is less important because if the function is not inlined, there's usually no benefit in inlining the argument constructor. Differential Revision: https://reviews.llvm.org/D49443 llvm-svn: 339745 --- clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 80 ++++++++++++++++++++++++- 1 file changed, 77 insertions(+), 3 deletions(-) (limited to 'clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp') diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp index 90dcf2f22e6..933d54e11c8 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp @@ -292,8 +292,75 @@ std::pair ExprEngine::prepareForObjectConstruction( return std::make_pair(State, V); } case ConstructionContext::ArgumentKind: { - // Function argument constructors. Not implemented yet. - break; + // Arguments are technically temporaries. + CallOpts.IsTemporaryCtorOrDtor = true; + + const auto *ACC = cast(CC); + const Expr *E = ACC->getCallLikeExpr(); + unsigned Idx = ACC->getIndex(); + const CXXBindTemporaryExpr *BTE = ACC->getCXXBindTemporaryExpr(); + + CallEventManager &CEMgr = getStateManager().getCallEventManager(); + SVal V = UnknownVal(); + auto getArgLoc = [&](CallEventRef<> Caller) -> Optional { + const LocationContext *FutureSFC = Caller->getCalleeStackFrame(); + // Return early if we are unable to reliably foresee + // the future stack frame. + if (!FutureSFC) + return None; + + // This should be equivalent to Caller->getDecl() for now, but + // FutureSFC->getDecl() is likely to support better stuff (like + // virtual functions) earlier. + const Decl *CalleeD = FutureSFC->getDecl(); + + // FIXME: Support for variadic arguments is not implemented here yet. + if (CallEvent::isVariadic(CalleeD)) + return None; + + // Operator arguments do not correspond to operator parameters + // because this-argument is implemented as a normal argument in + // operator call expressions but not in operator declarations. + const VarRegion *VR = Caller->getParameterLocation( + *Caller->getAdjustedParameterIndex(Idx)); + if (!VR) + return None; + + return loc::MemRegionVal(VR); + }; + + if (const auto *CE = dyn_cast(E)) { + CallEventRef<> Caller = CEMgr.getSimpleCall(CE, State, LCtx); + if (auto OptV = getArgLoc(Caller)) + V = *OptV; + else + break; + State = addObjectUnderConstruction(State, {CE, Idx}, LCtx, V); + } else if (const auto *CCE = dyn_cast(E)) { + // Don't bother figuring out the target region for the future + // constructor because we won't need it. + CallEventRef<> Caller = + CEMgr.getCXXConstructorCall(CCE, /*Target=*/nullptr, State, LCtx); + if (auto OptV = getArgLoc(Caller)) + V = *OptV; + else + break; + State = addObjectUnderConstruction(State, {CCE, Idx}, LCtx, V); + } else if (const auto *ME = dyn_cast(E)) { + CallEventRef<> Caller = CEMgr.getObjCMethodCall(ME, State, LCtx); + if (auto OptV = getArgLoc(Caller)) + V = *OptV; + else + break; + State = addObjectUnderConstruction(State, {ME, Idx}, LCtx, V); + } + + assert(!V.isUnknown()); + + if (BTE) + State = addObjectUnderConstruction(State, BTE, LCtx, V); + + return std::make_pair(State, V); } } } @@ -502,8 +569,15 @@ void ExprEngine::VisitCXXConstructExpr(const CXXConstructExpr *CE, } } + ExplodedNodeSet DstPostArgumentCleanup; + for (auto I : DstEvaluated) + finishArgumentConstruction(DstPostArgumentCleanup, I, *Call); + + // If there were other constructors called for object-type arguments + // of this constructor, clean them up. ExplodedNodeSet DstPostCall; - getCheckerManager().runCheckersForPostCall(DstPostCall, DstEvaluated, + getCheckerManager().runCheckersForPostCall(DstPostCall, + DstPostArgumentCleanup, *Call, *this); getCheckerManager().runCheckersForPostStmt(destNodes, DstPostCall, CE, *this); } -- cgit v1.2.3