diff options
author | Artem Dergachev <artem.dergachev@gmail.com> | 2018-08-15 00:33:55 +0000 |
---|---|---|
committer | Artem Dergachev <artem.dergachev@gmail.com> | 2018-08-15 00:33:55 +0000 |
commit | 3ccf14eb8e17aa166a456f6fec527f4fa97ecc71 (patch) | |
tree | 0e6056c4a42258ee14df717722c55c87a0090db5 /clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | |
parent | 4ec8bca13e7fd756dfd1ebfe24ffa09f5554e505 (diff) | |
download | bcm5719-llvm-3ccf14eb8e17aa166a456f6fec527f4fa97ecc71.tar.gz bcm5719-llvm-3ccf14eb8e17aa166a456f6fec527f4fa97ecc71.zip |
[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
Diffstat (limited to 'clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp')
-rw-r--r-- | clang/lib/StaticAnalyzer/Core/ExprEngineCXX.cpp | 80 |
1 files changed, 77 insertions, 3 deletions
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<ProgramStateRef, SVal> 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<ArgumentConstructionContext>(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<SVal> { + 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<CallExpr>(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<CXXConstructExpr>(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<ObjCMessageExpr>(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); } |