@@ -54,8 +54,8 @@ class StackAddrEscapeChecker
5454 CheckerContext &C) const ;
5555 void checkAsyncExecutedBlockCaptures (const BlockDataRegion &B,
5656 CheckerContext &C) const ;
57- void EmitReturnLeakError (CheckerContext &C, const MemRegion *LeakedRegion ,
58- const Expr *RetE) const ;
57+ void EmitStackError (CheckerContext &C, const MemRegion *R ,
58+ const Expr *RetE) const ;
5959 bool isSemaphoreCaptured (const BlockDecl &B) const ;
6060 static SourceRange genName (raw_ostream &os, const MemRegion *R,
6161 ASTContext &Ctx);
@@ -147,38 +147,21 @@ StackAddrEscapeChecker::getCapturedStackRegions(const BlockDataRegion &B,
147147 return Regions;
148148}
149149
150- static void EmitReturnedAsPartOfError (llvm::raw_ostream &OS, SVal ReturnedVal,
151- const MemRegion *LeakedRegion) {
152- if (const MemRegion *ReturnedRegion = ReturnedVal.getAsRegion ()) {
153- if (isa<BlockDataRegion>(ReturnedRegion)) {
154- OS << " is captured by a returned block" ;
155- return ;
156- }
157- }
158-
159- // Generic message
160- OS << " returned to caller" ;
161- }
162-
163- void StackAddrEscapeChecker::EmitReturnLeakError (CheckerContext &C,
164- const MemRegion *R,
165- const Expr *RetE) const {
150+ void StackAddrEscapeChecker::EmitStackError (CheckerContext &C,
151+ const MemRegion *R,
152+ const Expr *RetE) const {
166153 ExplodedNode *N = C.generateNonFatalErrorNode ();
167154 if (!N)
168155 return ;
169156 if (!BT_returnstack)
170157 BT_returnstack = std::make_unique<BugType>(
171158 CheckNames[CK_StackAddrEscapeChecker],
172159 " Return of address to stack-allocated memory" );
173-
174160 // Generate a report for this bug.
175161 SmallString<128 > buf;
176162 llvm::raw_svector_ostream os (buf);
177-
178- // Error message formatting
179163 SourceRange range = genName (os, R, C.getASTContext ());
180- EmitReturnedAsPartOfError (os, C.getSVal (RetE), R);
181-
164+ os << " returned to caller" ;
182165 auto report =
183166 std::make_unique<PathSensitiveBugReport>(*BT_returnstack, os.str (), N);
184167 report->addRange (RetE->getSourceRange ());
@@ -226,6 +209,30 @@ void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures(
226209 }
227210}
228211
212+ void StackAddrEscapeChecker::checkReturnedBlockCaptures (
213+ const BlockDataRegion &B, CheckerContext &C) const {
214+ for (const MemRegion *Region : getCapturedStackRegions (B, C)) {
215+ if (isNotInCurrentFrame (Region, C))
216+ continue ;
217+ ExplodedNode *N = C.generateNonFatalErrorNode ();
218+ if (!N)
219+ continue ;
220+ if (!BT_capturedstackret)
221+ BT_capturedstackret = std::make_unique<BugType>(
222+ CheckNames[CK_StackAddrEscapeChecker],
223+ " Address of stack-allocated memory is captured" );
224+ SmallString<128 > Buf;
225+ llvm::raw_svector_ostream Out (Buf);
226+ SourceRange Range = genName (Out, Region, C.getASTContext ());
227+ Out << " is captured by a returned block" ;
228+ auto Report = std::make_unique<PathSensitiveBugReport>(*BT_capturedstackret,
229+ Out.str (), N);
230+ if (Range.isValid ())
231+ Report->addRange (Range);
232+ C.emitReport (std::move (Report));
233+ }
234+ }
235+
229236void StackAddrEscapeChecker::checkPreCall (const CallEvent &Call,
230237 CheckerContext &C) const {
231238 if (!ChecksEnabled[CK_StackAddrAsyncEscapeChecker])
@@ -240,128 +247,45 @@ void StackAddrEscapeChecker::checkPreCall(const CallEvent &Call,
240247 }
241248}
242249
243- // / A visitor made for use with a ScanReachableSymbols scanner, used
244- // / for finding stack regions within an SVal that live on the current
245- // / stack frame of the given checker context. This visitor excludes
246- // / NonParamVarRegion that data is bound to in a BlockDataRegion's
247- // / bindings, since these are likely uninteresting, e.g., in case a
248- // / temporary is constructed on the stack, but it captures values
249- // / that would leak.
250- class FindStackRegionsSymbolVisitor final : public SymbolVisitor {
251- CheckerContext &Ctxt;
252- const StackFrameContext *StackFrameContext;
253- SmallVectorImpl<const MemRegion *> &EscapingStackRegions;
254-
255- public:
256- explicit FindStackRegionsSymbolVisitor (
257- CheckerContext &Ctxt,
258- SmallVectorImpl<const MemRegion *> &StorageForStackRegions)
259- : Ctxt(Ctxt), StackFrameContext(Ctxt.getStackFrame()),
260- EscapingStackRegions(StorageForStackRegions) {}
261-
262- bool VisitSymbol (SymbolRef sym) override { return true ; }
263-
264- bool VisitMemRegion (const MemRegion *MR) override {
265- SaveIfEscapes (MR);
266-
267- if (const BlockDataRegion *BDR = MR->getAs <BlockDataRegion>())
268- return VisitBlockDataRegionCaptures (BDR);
269-
270- return true ;
271- }
272-
273- private:
274- void SaveIfEscapes (const MemRegion *MR) {
275- const StackSpaceRegion *SSR =
276- MR->getMemorySpace ()->getAs <StackSpaceRegion>();
277- if (SSR && SSR->getStackFrame () == StackFrameContext)
278- EscapingStackRegions.push_back (MR);
279- }
280-
281- bool VisitBlockDataRegionCaptures (const BlockDataRegion *BDR) {
282- for (auto Var : BDR->referenced_vars ()) {
283- SVal Val = Ctxt.getState ()->getSVal (Var.getCapturedRegion ());
284- const MemRegion *Region = Val.getAsRegion ();
285- if (Region) {
286- SaveIfEscapes (Region);
287- VisitMemRegion (Region);
288- }
289- }
250+ void StackAddrEscapeChecker::checkPreStmt (const ReturnStmt *RS,
251+ CheckerContext &C) const {
252+ if (!ChecksEnabled[CK_StackAddrEscapeChecker])
253+ return ;
290254
291- return false ;
292- }
293- };
255+ const Expr *RetE = RS->getRetValue ();
256+ if (!RetE)
257+ return ;
258+ RetE = RetE->IgnoreParens ();
294259
295- // / Given some memory regions that are flagged by FindStackRegionsSymbolVisitor,
296- // / this function filters out memory regions that are being returned that are
297- // / likely not true leaks:
298- // / 1. If returning a block data region that has stack memory space
299- // / 2. If returning a constructed object that has stack memory space
300- static SmallVector<const MemRegion *> FilterReturnExpressionLeaks (
301- const SmallVectorImpl<const MemRegion *> &MaybeEscaped, CheckerContext &C,
302- const Expr *RetE, SVal &RetVal) {
260+ SVal V = C.getSVal (RetE);
261+ const MemRegion *R = V.getAsRegion ();
262+ if (!R)
263+ return ;
303264
304- SmallVector<const MemRegion *> WillEscape;
265+ if (const BlockDataRegion *B = dyn_cast<BlockDataRegion>(R))
266+ checkReturnedBlockCaptures (*B, C);
305267
306- const MemRegion *RetRegion = RetVal.getAsRegion ();
268+ if (!isa<StackSpaceRegion>(R->getMemorySpace ()) || isNotInCurrentFrame (R, C))
269+ return ;
307270
308271 // Returning a record by value is fine. (In this case, the returned
309272 // expression will be a copy-constructor, possibly wrapped in an
310273 // ExprWithCleanups node.)
311274 if (const ExprWithCleanups *Cleanup = dyn_cast<ExprWithCleanups>(RetE))
312275 RetE = Cleanup->getSubExpr ();
313- bool IsConstructExpr =
314- isa<CXXConstructExpr>(RetE) && RetE-> getType ()-> isRecordType () ;
276+ if (isa<CXXConstructExpr>(RetE) && RetE-> getType ()-> isRecordType ())
277+ return ;
315278
316279 // The CK_CopyAndAutoreleaseBlockObject cast causes the block to be copied
317280 // so the stack address is not escaping here.
318- bool IsCopyAndAutoreleaseBlockObj = false ;
319281 if (const auto *ICE = dyn_cast<ImplicitCastExpr>(RetE)) {
320- IsCopyAndAutoreleaseBlockObj =
321- isa_and_nonnull<BlockDataRegion>(RetRegion) &&
322- ICE->getCastKind () == CK_CopyAndAutoreleaseBlockObject;
323- }
324-
325- for (const MemRegion *MR : MaybeEscaped) {
326- if (RetRegion == MR && (IsCopyAndAutoreleaseBlockObj || IsConstructExpr))
327- continue ;
328-
329- WillEscape.push_back (MR);
282+ if (isa<BlockDataRegion>(R) &&
283+ ICE->getCastKind () == CK_CopyAndAutoreleaseBlockObject) {
284+ return ;
285+ }
330286 }
331287
332- return WillEscape;
333- }
334-
335- // / For use in finding regions that live on the checker context's current
336- // / stack frame, deep in the SVal representing the return value.
337- static SmallVector<const MemRegion *>
338- FindEscapingStackRegions (CheckerContext &C, const Expr *RetE, SVal RetVal) {
339- SmallVector<const MemRegion *> FoundStackRegions;
340-
341- FindStackRegionsSymbolVisitor Finder (C, FoundStackRegions);
342- ScanReachableSymbols Scanner (C.getState (), Finder);
343- Scanner.scan (RetVal);
344-
345- return FilterReturnExpressionLeaks (FoundStackRegions, C, RetE, RetVal);
346- }
347-
348- void StackAddrEscapeChecker::checkPreStmt (const ReturnStmt *RS,
349- CheckerContext &C) const {
350- if (!ChecksEnabled[CK_StackAddrEscapeChecker])
351- return ;
352-
353- const Expr *RetE = RS->getRetValue ();
354- if (!RetE)
355- return ;
356- RetE = RetE->IgnoreParens ();
357-
358- SVal V = C.getSVal (RetE);
359-
360- SmallVector<const MemRegion *> EscapedStackRegions =
361- FindEscapingStackRegions (C, RetE, V);
362-
363- for (const MemRegion *ER : EscapedStackRegions)
364- EmitReturnLeakError (C, ER, RetE);
288+ EmitStackError (C, R, RetE);
365289}
366290
367291static const MemSpaceRegion *getStackOrGlobalSpaceRegion (const MemRegion *R) {
0 commit comments