@@ -54,8 +54,8 @@ class StackAddrEscapeChecker
54
54
CheckerContext &C) const ;
55
55
void checkAsyncExecutedBlockCaptures (const BlockDataRegion &B,
56
56
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 ;
59
59
bool isSemaphoreCaptured (const BlockDecl &B) const ;
60
60
static SourceRange genName (raw_ostream &os, const MemRegion *R,
61
61
ASTContext &Ctx);
@@ -147,38 +147,21 @@ StackAddrEscapeChecker::getCapturedStackRegions(const BlockDataRegion &B,
147
147
return Regions;
148
148
}
149
149
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 {
166
153
ExplodedNode *N = C.generateNonFatalErrorNode ();
167
154
if (!N)
168
155
return ;
169
156
if (!BT_returnstack)
170
157
BT_returnstack = std::make_unique<BugType>(
171
158
CheckNames[CK_StackAddrEscapeChecker],
172
159
" Return of address to stack-allocated memory" );
173
-
174
160
// Generate a report for this bug.
175
161
SmallString<128 > buf;
176
162
llvm::raw_svector_ostream os (buf);
177
-
178
- // Error message formatting
179
163
SourceRange range = genName (os, R, C.getASTContext ());
180
- EmitReturnedAsPartOfError (os, C.getSVal (RetE), R);
181
-
164
+ os << " returned to caller" ;
182
165
auto report =
183
166
std::make_unique<PathSensitiveBugReport>(*BT_returnstack, os.str (), N);
184
167
report->addRange (RetE->getSourceRange ());
@@ -226,6 +209,30 @@ void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures(
226
209
}
227
210
}
228
211
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
+
229
236
void StackAddrEscapeChecker::checkPreCall (const CallEvent &Call,
230
237
CheckerContext &C) const {
231
238
if (!ChecksEnabled[CK_StackAddrAsyncEscapeChecker])
@@ -240,128 +247,45 @@ void StackAddrEscapeChecker::checkPreCall(const CallEvent &Call,
240
247
}
241
248
}
242
249
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 ;
290
254
291
- return false ;
292
- }
293
- };
255
+ const Expr *RetE = RS->getRetValue ();
256
+ if (!RetE)
257
+ return ;
258
+ RetE = RetE->IgnoreParens ();
294
259
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 ;
303
264
304
- SmallVector<const MemRegion *> WillEscape;
265
+ if (const BlockDataRegion *B = dyn_cast<BlockDataRegion>(R))
266
+ checkReturnedBlockCaptures (*B, C);
305
267
306
- const MemRegion *RetRegion = RetVal.getAsRegion ();
268
+ if (!isa<StackSpaceRegion>(R->getMemorySpace ()) || isNotInCurrentFrame (R, C))
269
+ return ;
307
270
308
271
// Returning a record by value is fine. (In this case, the returned
309
272
// expression will be a copy-constructor, possibly wrapped in an
310
273
// ExprWithCleanups node.)
311
274
if (const ExprWithCleanups *Cleanup = dyn_cast<ExprWithCleanups>(RetE))
312
275
RetE = Cleanup->getSubExpr ();
313
- bool IsConstructExpr =
314
- isa<CXXConstructExpr>(RetE) && RetE-> getType ()-> isRecordType () ;
276
+ if (isa<CXXConstructExpr>(RetE) && RetE-> getType ()-> isRecordType ())
277
+ return ;
315
278
316
279
// The CK_CopyAndAutoreleaseBlockObject cast causes the block to be copied
317
280
// so the stack address is not escaping here.
318
- bool IsCopyAndAutoreleaseBlockObj = false ;
319
281
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
+ }
330
286
}
331
287
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);
365
289
}
366
290
367
291
static const MemSpaceRegion *getStackOrGlobalSpaceRegion (const MemRegion *R) {
0 commit comments