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/ExprEngine.cpp | 33 ++++++++++++++++++---------- 1 file changed, 21 insertions(+), 12 deletions(-) (limited to 'clang/lib/StaticAnalyzer/Core/ExprEngine.cpp') diff --git a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp index 40259fb0c03..8469a601b06 100644 --- a/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp +++ b/clang/lib/StaticAnalyzer/Core/ExprEngine.cpp @@ -2199,17 +2199,21 @@ void ExprEngine::processBeginOfFunction(NodeBuilderContext &BC, void ExprEngine::processEndOfFunction(NodeBuilderContext& BC, ExplodedNode *Pred, const ReturnStmt *RS) { + ProgramStateRef State = Pred->getState(); + + if (!Pred->getStackFrame()->inTopFrame()) + State = finishArgumentConstruction( + State, *getStateManager().getCallEventManager().getCaller( + Pred->getStackFrame(), Pred->getState())); + // FIXME: We currently cannot assert that temporaries are clear, because // lifetime extended temporaries are not always modelled correctly. In some // cases when we materialize the temporary, we do // createTemporaryRegionIfNeeded(), and the region changes, and also the // respective destructor becomes automatic from temporary. So for now clean up - // the state manually before asserting. Ideally, the code above the assertion - // should go away, but the assertion should remain. + // the state manually before asserting. Ideally, this braced block of code + // should go away. { - ExplodedNodeSet CleanUpObjects; - NodeBuilder Bldr(Pred, CleanUpObjects, BC); - ProgramStateRef State = Pred->getState(); const LocationContext *FromLC = Pred->getLocationContext(); const LocationContext *ToLC = FromLC->getStackFrame()->getParent(); const LocationContext *LC = FromLC; @@ -2228,15 +2232,20 @@ void ExprEngine::processEndOfFunction(NodeBuilderContext& BC, } LC = LC->getParent(); } - if (State != Pred->getState()) { - Pred = Bldr.generateNode(Pred->getLocation(), State, Pred); - if (!Pred) { - // The node with clean temporaries already exists. We might have reached - // it on a path on which we initialize different temporaries. - return; - } + } + + // Perform the transition with cleanups. + if (State != Pred->getState()) { + ExplodedNodeSet PostCleanup; + NodeBuilder Bldr(Pred, PostCleanup, BC); + Pred = Bldr.generateNode(Pred->getLocation(), State, Pred); + if (!Pred) { + // The node with clean temporaries already exists. We might have reached + // it on a path on which we initialize different temporaries. + return; } } + assert(areAllObjectsFullyConstructed(Pred->getState(), Pred->getLocationContext(), Pred->getStackFrame()->getParent())); -- cgit v1.2.3