clang 22.0.0git
StackAddrEscapeChecker.cpp
Go to the documentation of this file.
1//=== StackAddrEscapeChecker.cpp ----------------------------------*- C++ -*--//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file defines stack address leak checker, which checks if an invalid
10// stack address is stored into a global or heap location. See CERT DCL30-C.
11//
12//===----------------------------------------------------------------------===//
13
14#include "clang/AST/ExprCXX.h"
24#include "llvm/ADT/STLExtras.h"
25#include "llvm/Support/raw_ostream.h"
26using namespace clang;
27using namespace ento;
28
29namespace {
30class StackAddrEscapeChecker
31 : public CheckerFamily<check::PreCall, check::PreStmt<ReturnStmt>,
32 check::EndFunction> {
33 mutable IdentifierInfo *dispatch_semaphore_tII = nullptr;
34
35public:
36 StringRef getDebugTag() const override { return "StackAddrEscapeChecker"; }
37
38 CheckerFrontend StackAddrEscape;
39 CheckerFrontend StackAddrAsyncEscape;
40
41 const BugType StackLeak{&StackAddrEscape,
42 "Stack address leaks outside of stack frame"};
43 const BugType ReturnStack{&StackAddrEscape,
44 "Return of address to stack-allocated memory"};
45 const BugType CapturedStackAsync{
46 &StackAddrAsyncEscape, "Address of stack-allocated memory is captured"};
47
48 void checkPreCall(const CallEvent &Call, CheckerContext &C) const;
49 void checkPreStmt(const ReturnStmt *RS, CheckerContext &C) const;
50 void checkEndFunction(const ReturnStmt *RS, CheckerContext &Ctx) const;
51
52private:
53 void checkAsyncExecutedBlockCaptures(const BlockDataRegion &B,
54 CheckerContext &C) const;
55 void EmitReturnLeakError(CheckerContext &C, const MemRegion *LeakedRegion,
56 const Expr *RetE) const;
57 bool isSemaphoreCaptured(const BlockDecl &B) const;
58 static SourceRange genName(raw_ostream &os, const MemRegion *R,
59 ASTContext &Ctx);
60 static SmallVector<std::pair<const MemRegion *, const StackSpaceRegion *>, 4>
61 getCapturedStackRegions(const BlockDataRegion &B, CheckerContext &C);
62 static bool isNotInCurrentFrame(const StackSpaceRegion *MS,
63 CheckerContext &C);
64};
65} // namespace
66
67SourceRange StackAddrEscapeChecker::genName(raw_ostream &os, const MemRegion *R,
68 ASTContext &Ctx) {
69 // Get the base region, stripping away fields and elements.
70 R = R->getBaseRegion();
71 SourceManager &SM = Ctx.getSourceManager();
72 SourceRange range;
73 os << "Address of ";
74
75 // Check if the region is a compound literal.
76 if (const auto *CR = dyn_cast<CompoundLiteralRegion>(R)) {
77 const CompoundLiteralExpr *CL = CR->getLiteralExpr();
78 os << "stack memory associated with a compound literal "
79 "declared on line "
80 << SM.getExpansionLineNumber(CL->getBeginLoc());
81 range = CL->getSourceRange();
82 } else if (const auto *AR = dyn_cast<AllocaRegion>(R)) {
83 const Expr *ARE = AR->getExpr();
84 SourceLocation L = ARE->getBeginLoc();
85 range = ARE->getSourceRange();
86 os << "stack memory allocated by call to alloca() on line "
87 << SM.getExpansionLineNumber(L);
88 } else if (const auto *BR = dyn_cast<BlockDataRegion>(R)) {
89 const BlockDecl *BD = BR->getCodeRegion()->getDecl();
90 SourceLocation L = BD->getBeginLoc();
91 range = BD->getSourceRange();
92 os << "stack-allocated block declared on line "
93 << SM.getExpansionLineNumber(L);
94 } else if (const auto *VR = dyn_cast<VarRegion>(R)) {
95 os << "stack memory associated with local variable '" << VR->getString()
96 << '\'';
97 range = VR->getDecl()->getSourceRange();
98 } else if (const auto *LER = dyn_cast<CXXLifetimeExtendedObjectRegion>(R)) {
99 QualType Ty = LER->getValueType().getLocalUnqualifiedType();
100 os << "stack memory associated with temporary object of type '";
101 Ty.print(os, Ctx.getPrintingPolicy());
102 os << "' lifetime extended by local variable";
103 if (const IdentifierInfo *ID = LER->getExtendingDecl()->getIdentifier())
104 os << " '" << ID->getName() << '\'';
105 range = LER->getExpr()->getSourceRange();
106 } else if (const auto *TOR = dyn_cast<CXXTempObjectRegion>(R)) {
107 QualType Ty = TOR->getValueType().getLocalUnqualifiedType();
108 os << "stack memory associated with temporary object of type '";
109 Ty.print(os, Ctx.getPrintingPolicy());
110 os << "'";
111 range = TOR->getExpr()->getSourceRange();
112 } else {
113 llvm_unreachable("Invalid region in ReturnStackAddressChecker.");
114 }
115
116 return range;
117}
118
119bool StackAddrEscapeChecker::isNotInCurrentFrame(const StackSpaceRegion *MS,
120 CheckerContext &C) {
121 return MS->getStackFrame() != C.getStackFrame();
122}
123
124bool StackAddrEscapeChecker::isSemaphoreCaptured(const BlockDecl &B) const {
125 if (!dispatch_semaphore_tII)
126 dispatch_semaphore_tII = &B.getASTContext().Idents.get("dispatch_semaphore_t");
127 for (const auto &C : B.captures()) {
128 const auto *T = C.getVariable()->getType()->getAs<TypedefType>();
129 if (T && T->getDecl()->getIdentifier() == dispatch_semaphore_tII)
130 return true;
131 }
132 return false;
133}
134
135SmallVector<std::pair<const MemRegion *, const StackSpaceRegion *>, 4>
136StackAddrEscapeChecker::getCapturedStackRegions(const BlockDataRegion &B,
137 CheckerContext &C) {
138 SmallVector<std::pair<const MemRegion *, const StackSpaceRegion *>, 4>
139 Regions;
140 ProgramStateRef State = C.getState();
141 for (auto Var : B.referenced_vars()) {
142 SVal Val = State->getSVal(Var.getCapturedRegion());
143 if (const MemRegion *Region = Val.getAsRegion()) {
144 if (const auto *Space =
145 Region->getMemorySpaceAs<StackSpaceRegion>(State)) {
146 Regions.emplace_back(Region, Space);
147 }
148 }
149 }
150 return Regions;
151}
152
153static void EmitReturnedAsPartOfError(llvm::raw_ostream &OS, SVal ReturnedVal,
154 const MemRegion *LeakedRegion) {
155 if (const MemRegion *ReturnedRegion = ReturnedVal.getAsRegion()) {
156 if (isa<BlockDataRegion>(ReturnedRegion)) {
157 OS << " is captured by a returned block";
158 return;
159 }
160 }
161
162 // Generic message
163 OS << " returned to caller";
164}
165
166void StackAddrEscapeChecker::EmitReturnLeakError(CheckerContext &C,
167 const MemRegion *R,
168 const Expr *RetE) const {
169 ExplodedNode *N = C.generateNonFatalErrorNode();
170 if (!N)
171 return;
172
173 // Generate a report for this bug.
174 SmallString<128> buf;
175 llvm::raw_svector_ostream os(buf);
176
177 // Error message formatting
178 SourceRange range = genName(os, R, C.getASTContext());
179 EmitReturnedAsPartOfError(os, C.getSVal(RetE), R);
180
181 auto report =
182 std::make_unique<PathSensitiveBugReport>(ReturnStack, os.str(), N);
183 report->addRange(RetE->getSourceRange());
184 if (range.isValid())
185 report->addRange(range);
186 C.emitReport(std::move(report));
187}
188
189void StackAddrEscapeChecker::checkAsyncExecutedBlockCaptures(
190 const BlockDataRegion &B, CheckerContext &C) const {
191 // There is a not-too-uncommon idiom
192 // where a block passed to dispatch_async captures a semaphore
193 // and then the thread (which called dispatch_async) is blocked on waiting
194 // for the completion of the execution of the block
195 // via dispatch_semaphore_wait. To avoid false-positives (for now)
196 // we ignore all the blocks which have captured
197 // a variable of the type "dispatch_semaphore_t".
198 if (isSemaphoreCaptured(*B.getDecl()))
199 return;
200 auto Regions = getCapturedStackRegions(B, C);
201 for (const MemRegion *Region : llvm::make_first_range(Regions)) {
202 // The block passed to dispatch_async may capture another block
203 // created on the stack. However, there is no leak in this situaton,
204 // no matter if ARC or no ARC is enabled:
205 // dispatch_async copies the passed "outer" block (via Block_copy)
206 // and if the block has captured another "inner" block,
207 // the "inner" block will be copied as well.
208 if (isa<BlockDataRegion>(Region))
209 continue;
210 ExplodedNode *N = C.generateNonFatalErrorNode();
211 if (!N)
212 continue;
213 SmallString<128> Buf;
214 llvm::raw_svector_ostream Out(Buf);
215 SourceRange Range = genName(Out, Region, C.getASTContext());
216 Out << " is captured by an asynchronously-executed block";
217 auto Report = std::make_unique<PathSensitiveBugReport>(CapturedStackAsync,
218 Out.str(), N);
219 if (Range.isValid())
220 Report->addRange(Range);
221 C.emitReport(std::move(Report));
222 }
223}
224
225void StackAddrEscapeChecker::checkPreCall(const CallEvent &Call,
226 CheckerContext &C) const {
227 if (!StackAddrAsyncEscape.isEnabled())
228 return;
229 if (!Call.isGlobalCFunction("dispatch_after") &&
230 !Call.isGlobalCFunction("dispatch_async"))
231 return;
232 for (unsigned Idx = 0, NumArgs = Call.getNumArgs(); Idx < NumArgs; ++Idx) {
233 if (const BlockDataRegion *B = dyn_cast_or_null<BlockDataRegion>(
234 Call.getArgSVal(Idx).getAsRegion()))
235 checkAsyncExecutedBlockCaptures(*B, C);
236 }
237}
238
239/// A visitor made for use with a ScanReachableSymbols scanner, used
240/// for finding stack regions within an SVal that live on the current
241/// stack frame of the given checker context. This visitor excludes
242/// NonParamVarRegion that data is bound to in a BlockDataRegion's
243/// bindings, since these are likely uninteresting, e.g., in case a
244/// temporary is constructed on the stack, but it captures values
245/// that would leak.
247 CheckerContext &Ctxt;
248 const StackFrameContext *PoppedStackFrame;
249 SmallVectorImpl<const MemRegion *> &EscapingStackRegions;
250
251public:
253 CheckerContext &Ctxt,
254 SmallVectorImpl<const MemRegion *> &StorageForStackRegions)
255 : Ctxt(Ctxt), PoppedStackFrame(Ctxt.getStackFrame()),
256 EscapingStackRegions(StorageForStackRegions) {}
257
258 bool VisitSymbol(SymbolRef sym) override { return true; }
259
260 bool VisitMemRegion(const MemRegion *MR) override {
261 SaveIfEscapes(MR);
262
263 if (const BlockDataRegion *BDR = MR->getAs<BlockDataRegion>())
264 return VisitBlockDataRegionCaptures(BDR);
265
266 return true;
267 }
268
269private:
270 void SaveIfEscapes(const MemRegion *MR) {
271 const auto *SSR = MR->getMemorySpaceAs<StackSpaceRegion>(Ctxt.getState());
272
273 if (!SSR)
274 return;
275
276 const StackFrameContext *CapturedSFC = SSR->getStackFrame();
277 if (CapturedSFC == PoppedStackFrame ||
278 PoppedStackFrame->isParentOf(CapturedSFC))
279 EscapingStackRegions.push_back(MR);
280 }
281
282 bool VisitBlockDataRegionCaptures(const BlockDataRegion *BDR) {
283 for (auto Var : BDR->referenced_vars()) {
284 SVal Val = Ctxt.getState()->getSVal(Var.getCapturedRegion());
285 const MemRegion *Region = Val.getAsRegion();
286 if (Region) {
287 SaveIfEscapes(Region);
288 VisitMemRegion(Region);
289 }
290 }
291
292 return false;
293 }
294};
295
296/// Given some memory regions that are flagged by FindStackRegionsSymbolVisitor,
297/// this function filters out memory regions that are being returned that are
298/// likely not true leaks:
299/// 1. If returning a block data region that has stack memory space
300/// 2. If returning a constructed object that has stack memory space
303 const Expr *RetE, SVal &RetVal) {
304
306
307 const MemRegion *RetRegion = RetVal.getAsRegion();
308
309 // Returning a record by value is fine. (In this case, the returned
310 // expression will be a copy-constructor, possibly wrapped in an
311 // ExprWithCleanups node.)
312 if (const ExprWithCleanups *Cleanup = dyn_cast<ExprWithCleanups>(RetE))
313 RetE = Cleanup->getSubExpr();
314 bool IsConstructExpr =
315 isa<CXXConstructExpr>(RetE) && RetE->getType()->isRecordType();
316
317 // The CK_CopyAndAutoreleaseBlockObject cast causes the block to be copied
318 // so the stack address is not escaping here.
319 bool IsCopyAndAutoreleaseBlockObj = false;
320 if (const auto *ICE = dyn_cast<ImplicitCastExpr>(RetE)) {
321 IsCopyAndAutoreleaseBlockObj =
322 isa_and_nonnull<BlockDataRegion>(RetRegion) &&
323 ICE->getCastKind() == CK_CopyAndAutoreleaseBlockObject;
324 }
325
326 for (const MemRegion *MR : MaybeEscaped) {
327 if (RetRegion == MR && (IsCopyAndAutoreleaseBlockObj || IsConstructExpr))
328 continue;
329
330 WillEscape.push_back(MR);
331 }
332
333 return WillEscape;
334}
335
336/// For use in finding regions that live on the checker context's current
337/// stack frame, deep in the SVal representing the return value.
338static SmallVector<const MemRegion *>
340 SmallVector<const MemRegion *> FoundStackRegions;
341
342 FindStackRegionsSymbolVisitor Finder(C, FoundStackRegions);
343 ScanReachableSymbols Scanner(C.getState(), Finder);
344 Scanner.scan(RetVal);
345
346 return FilterReturnExpressionLeaks(FoundStackRegions, C, RetE, RetVal);
347}
348
349void StackAddrEscapeChecker::checkPreStmt(const ReturnStmt *RS,
350 CheckerContext &C) const {
351 if (!StackAddrEscape.isEnabled())
352 return;
353
354 const Expr *RetE = RS->getRetValue();
355 if (!RetE)
356 return;
357 RetE = RetE->IgnoreParens();
358
359 SVal V = C.getSVal(RetE);
360
361 SmallVector<const MemRegion *> EscapedStackRegions =
363
364 for (const MemRegion *ER : EscapedStackRegions)
365 EmitReturnLeakError(C, ER, RetE);
366}
367
369 const MemRegion *R) {
370 assert(R);
371 if (const auto *MemSpace = R->getMemorySpace(State);
373 return MemSpace;
374
375 // If R describes a lambda capture, it will be a symbolic region
376 // referring to a field region of another symbolic region.
377 if (const auto *SymReg = R->getBaseRegion()->getAs<SymbolicRegion>()) {
378 if (const auto *OriginReg = SymReg->getSymbol()->getOriginRegion())
379 return getStackOrGlobalSpaceRegion(State, OriginReg);
380 }
381 return nullptr;
382}
383
384static const MemRegion *getOriginBaseRegion(const MemRegion *Reg) {
385 Reg = Reg->getBaseRegion();
386 while (const auto *SymReg = dyn_cast<SymbolicRegion>(Reg)) {
387 const auto *OriginReg = SymReg->getSymbol()->getOriginRegion();
388 if (!OriginReg)
389 break;
390 Reg = OriginReg->getBaseRegion();
391 }
392 return Reg;
393}
394
395static std::optional<std::string> printReferrer(ProgramStateRef State,
396 const MemRegion *Referrer) {
397 assert(Referrer);
398 const StringRef ReferrerMemorySpace = [](const MemSpaceRegion *Space) {
400 return "static";
401 if (isa<GlobalsSpaceRegion>(Space))
402 return "global";
403 assert(isa<StackSpaceRegion>(Space));
404 // This case covers top-level and inlined analyses.
405 return "caller";
406 }(getStackOrGlobalSpaceRegion(State, Referrer));
407
408 while (!Referrer->canPrintPretty()) {
409 if (const auto *SymReg = dyn_cast<SymbolicRegion>(Referrer);
410 SymReg && SymReg->getSymbol()->getOriginRegion()) {
411 Referrer = SymReg->getSymbol()->getOriginRegion()->getBaseRegion();
412 } else if (isa<CXXThisRegion>(Referrer)) {
413 // Skip members of a class, it is handled in CheckExprLifetime.cpp as
414 // warn_bind_ref_member_to_parameter or
415 // warn_init_ptr_member_to_parameter_addr
416 return std::nullopt;
417 } else if (isa<AllocaRegion>(Referrer)) {
418 // Skip alloca() regions, they indicate advanced memory management
419 // and higher likelihood of CSA false positives.
420 return std::nullopt;
421 } else {
422 assert(false && "Unexpected referrer region type.");
423 return std::nullopt;
424 }
425 }
426 assert(Referrer);
427 assert(Referrer->canPrintPretty());
428
429 std::string buf;
430 llvm::raw_string_ostream os(buf);
431 os << ReferrerMemorySpace << " variable ";
432 Referrer->printPretty(os);
433 return buf;
434}
435
436/// Check whether \p Region refers to a freshly minted symbol after an opaque
437/// function call.
438static bool isInvalidatedSymbolRegion(const MemRegion *Region) {
439 const auto *SymReg = Region->getAs<SymbolicRegion>();
440 if (!SymReg)
441 return false;
442 SymbolRef Symbol = SymReg->getSymbol();
443
444 const auto *DerS = dyn_cast<SymbolDerived>(Symbol);
445 return DerS && isa_and_nonnull<SymbolConjured>(DerS->getParentSymbol());
446}
447
448void StackAddrEscapeChecker::checkEndFunction(const ReturnStmt *RS,
449 CheckerContext &Ctx) const {
450 if (!StackAddrEscape.isEnabled())
451 return;
452
453 ExplodedNode *Node = Ctx.getPredecessor();
454
455 bool ExitingTopFrame =
457
458 if (ExitingTopFrame &&
460 Node->getFirstPred()) {
461 // When finishing analysis of a top-level function, engine proactively
462 // removes dead symbols thus preventing this checker from looking through
463 // the output parameters. Take 1 step back, to the node where these symbols
464 // and their bindings are still present
465 Node = Node->getFirstPred();
466 }
467
468 // Iterate over all bindings to global variables and see if it contains
469 // a memory region in the stack space.
470 class CallBack : public StoreManager::BindingsHandler {
471 private:
472 CheckerContext &Ctx;
473 ProgramStateRef State;
474 const StackFrameContext *PoppedFrame;
475 const bool TopFrame;
476
477 /// Look for stack variables referring to popped stack variables.
478 /// Returns true only if it found some dangling stack variables
479 /// referred by an other stack variable from different stack frame.
480 bool checkForDanglingStackVariable(const MemRegion *Referrer,
481 const MemRegion *Referred) {
482 const auto *ReferrerMemSpace =
483 getStackOrGlobalSpaceRegion(State, Referrer);
484 const auto *ReferredMemSpace =
485 Referred->getMemorySpaceAs<StackSpaceRegion>(State);
486
487 if (!ReferrerMemSpace || !ReferredMemSpace)
488 return false;
489
490 const auto *ReferrerStackSpace =
491 ReferrerMemSpace->getAs<StackSpaceRegion>();
492
493 if (!ReferrerStackSpace)
494 return false;
495
496 if (const auto *ReferredFrame = ReferredMemSpace->getStackFrame();
497 ReferredFrame != PoppedFrame) {
498 return false;
499 }
500
501 if (ReferrerStackSpace->getStackFrame()->isParentOf(PoppedFrame)) {
502 V.emplace_back(Referrer, Referred);
503 return true;
504 }
505 if (isa<StackArgumentsSpaceRegion>(ReferrerMemSpace) &&
506 // Not a simple ptr (int*) but something deeper, e.g. int**
507 isa<SymbolicRegion>(Referrer->getBaseRegion()) &&
508 ReferrerStackSpace->getStackFrame() == PoppedFrame && TopFrame) {
509 // Output parameter of a top-level function
510 V.emplace_back(Referrer, Referred);
511 return true;
512 }
513 return false;
514 }
515
516 // Keep track of the variables that were invalidated through an opaque
517 // function call. Even if the initial values of such variables were bound to
518 // an address of a local variable, we cannot claim anything now, at the
519 // function exit, so skip them to avoid false positives.
520 void recordInInvalidatedRegions(const MemRegion *Region) {
521 if (isInvalidatedSymbolRegion(Region))
522 ExcludedRegions.insert(getOriginBaseRegion(Region));
523 }
524
525 public:
526 SmallVector<std::pair<const MemRegion *, const MemRegion *>, 10> V;
527 // ExcludedRegions are skipped from reporting.
528 // I.e., if a referrer in this set, skip the related bug report.
529 // It is useful to avoid false positive for the variables that were
530 // reset to a conjured value after an opaque function call.
531 llvm::SmallPtrSet<const MemRegion *, 4> ExcludedRegions;
532
533 CallBack(CheckerContext &CC, bool TopFrame)
534 : Ctx(CC), State(CC.getState()), PoppedFrame(CC.getStackFrame()),
535 TopFrame(TopFrame) {}
536
537 bool HandleBinding(StoreManager &SMgr, Store S, const MemRegion *Region,
538 SVal Val) override {
539 recordInInvalidatedRegions(Region);
540 const MemRegion *VR = Val.getAsRegion();
541 if (!VR)
542 return true;
543
544 if (checkForDanglingStackVariable(Region, VR))
545 return true;
546
547 // Check the globals for the same.
548 if (!isa_and_nonnull<GlobalsSpaceRegion>(
549 getStackOrGlobalSpaceRegion(State, Region)))
550 return true;
551
552 if (VR) {
553 if (const auto *S = VR->getMemorySpaceAs<StackSpaceRegion>(State);
554 S && !isNotInCurrentFrame(S, Ctx)) {
555 V.emplace_back(Region, VR);
556 }
557 }
558 return true;
559 }
560 };
561
562 CallBack Cb(Ctx, ExitingTopFrame);
563 ProgramStateRef State = Node->getState();
564 State->getStateManager().getStoreManager().iterBindings(State->getStore(),
565 Cb);
566
567 if (Cb.V.empty())
568 return;
569
570 // Generate an error node.
571 ExplodedNode *N = Ctx.generateNonFatalErrorNode(State, Node);
572 if (!N)
573 return;
574
575 for (const auto &P : Cb.V) {
576 const MemRegion *Referrer = P.first->getBaseRegion();
577 const MemRegion *Referred = P.second;
578 if (Cb.ExcludedRegions.contains(getOriginBaseRegion(Referrer))) {
579 continue;
580 }
581
582 // Generate a report for this bug.
583 const StringRef CommonSuffix =
584 " upon returning to the caller. This will be a dangling reference";
585 SmallString<128> Buf;
586 llvm::raw_svector_ostream Out(Buf);
587 const SourceRange Range = genName(Out, Referred, Ctx.getASTContext());
588
590 Out << " is still referred to by a temporary object on the stack"
591 << CommonSuffix;
592 auto Report =
593 std::make_unique<PathSensitiveBugReport>(StackLeak, Out.str(), N);
594 if (Range.isValid())
595 Report->addRange(Range);
596 Ctx.emitReport(std::move(Report));
597 return;
598 }
599
600 auto ReferrerVariable = printReferrer(State, Referrer);
601 if (!ReferrerVariable) {
602 continue;
603 }
604
605 Out << " is still referred to by the " << *ReferrerVariable << CommonSuffix;
606 auto Report =
607 std::make_unique<PathSensitiveBugReport>(StackLeak, Out.str(), N);
608 if (Range.isValid())
609 Report->addRange(Range);
610
611 Ctx.emitReport(std::move(Report));
612 }
613}
614
615#define REGISTER_CHECKER(NAME) \
616 void ento::register##NAME##Checker(CheckerManager &Mgr) { \
617 Mgr.getChecker<StackAddrEscapeChecker>()->NAME.enable(Mgr); \
618 } \
619 \
620 bool ento::shouldRegister##NAME##Checker(const CheckerManager &) { \
621 return true; \
622 }
623
624REGISTER_CHECKER(StackAddrEscape)
625REGISTER_CHECKER(StackAddrAsyncEscape)
#define V(N, I)
#define REGISTER_CHECKER(name)
Defines the clang::Expr interface and subclasses for C++ expressions.
#define SM(sm)
Defines the SourceManager interface.
static SmallVector< const MemRegion * > FilterReturnExpressionLeaks(const SmallVectorImpl< const MemRegion * > &MaybeEscaped, CheckerContext &C, const Expr *RetE, SVal &RetVal)
Given some memory regions that are flagged by FindStackRegionsSymbolVisitor, this function filters ou...
static bool isInvalidatedSymbolRegion(const MemRegion *Region)
Check whether Region refers to a freshly minted symbol after an opaque function call.
static void EmitReturnedAsPartOfError(llvm::raw_ostream &OS, SVal ReturnedVal, const MemRegion *LeakedRegion)
static std::optional< std::string > printReferrer(ProgramStateRef State, const MemRegion *Referrer)
static const MemSpaceRegion * getStackOrGlobalSpaceRegion(ProgramStateRef State, const MemRegion *R)
static const MemRegion * getOriginBaseRegion(const MemRegion *Reg)
static SmallVector< const MemRegion * > FindEscapingStackRegions(CheckerContext &C, const Expr *RetE, SVal RetVal)
For use in finding regions that live on the checker context's current stack frame,...
A visitor made for use with a ScanReachableSymbols scanner, used for finding stack regions within an ...
bool VisitMemRegion(const MemRegion *MR) override
FindStackRegionsSymbolVisitor(CheckerContext &Ctxt, SmallVectorImpl< const MemRegion * > &StorageForStackRegions)
bool VisitSymbol(SymbolRef sym) override
A visitor method invoked by ProgramStateManager::scanReachableSymbols.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition ASTContext.h:188
SourceManager & getSourceManager()
Definition ASTContext.h:798
IdentifierTable & Idents
Definition ASTContext.h:737
const clang::PrintingPolicy & getPrintingPolicy() const
Definition ASTContext.h:790
ArrayRef< Capture > captures() const
Definition Decl.h:4761
SourceRange getSourceRange() const override LLVM_READONLY
Source range that this declaration covers.
Definition Decl.cpp:5347
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Expr.h:3590
ASTContext & getASTContext() const LLVM_READONLY
Definition DeclBase.cpp:524
SourceLocation getBeginLoc() const LLVM_READONLY
Definition DeclBase.h:431
Represents an expression – generally a full-expression – that introduces cleanups to be run at the en...
Definition ExprCXX.h:3655
This represents one expression.
Definition Expr.h:112
Expr * IgnoreParens() LLVM_READONLY
Skip past any parentheses which might surround this expression until reaching a fixed point.
Definition Expr.cpp:3069
QualType getType() const
Definition Expr.h:144
IdentifierInfo & get(StringRef Name)
Return the identifier token info for the specified named identifier.
bool isParentOf(const LocationContext *LC) const
const StackFrameContext * getStackFrame() const
virtual bool inTopFrame() const
const ProgramPointTag * getTag() const
void print(raw_ostream &OS, const PrintingPolicy &Policy, const Twine &PlaceHolder=Twine(), unsigned Indentation=0) const
Expr * getRetValue()
Definition Stmt.h:3187
A trivial tuple used to represent a source range.
It represents a stack frame of the call stack (based on CallEvent).
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:334
SourceLocation getBeginLoc() const LLVM_READONLY
Definition Stmt.cpp:346
const T * getAs() const
Member-template getAs<specific type>'.
Definition TypeBase.h:9101
bool isRecordType() const
Definition TypeBase.h:8649
BlockDataRegion - A region that represents a block instance.
Definition MemRegion.h:706
LLVM_ATTRIBUTE_RETURNS_NONNULL const BlockDecl * getDecl() const
Definition MemRegion.h:736
llvm::iterator_range< referenced_vars_iterator > referenced_vars() const
ExplodedNode * getPredecessor()
Returns the previous node in the exploded graph, which includes the state of the program before the c...
ExplodedNode * generateNonFatalErrorNode(ProgramStateRef State=nullptr, const ProgramPointTag *Tag=nullptr)
Generate a transition to a node that will be used to report an error.
void emitReport(std::unique_ptr< BugReport > R)
Emit the diagnostics report.
Checker families (where a single backend class implements multiple related frontends) should derive f...
Definition Checker.h:584
const ProgramStateRef & getState() const
ProgramPoint getLocation() const
getLocation - Returns the edge associated with the given node.
const LocationContext * getLocationContext() const
ExplodedNode * getFirstPred()
static const ProgramPointTag * cleanupNodeTag()
A tag to track convenience transitions, which can be removed at cleanup.
MemRegion - The root abstract class for all memory regions.
Definition MemRegion.h:98
const MemSpace * getMemorySpaceAs(ProgramStateRef State) const
Definition MemRegion.h:143
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemSpaceRegion * getMemorySpace(ProgramStateRef State) const
Returns the most specific memory space for this memory region in the given ProgramStateRef.
LLVM_ATTRIBUTE_RETURNS_NONNULL const MemRegion * getBaseRegion() const
virtual void printPretty(raw_ostream &os) const
Print the region for use in diagnostics.
const RegionTy * getAs() const
Definition MemRegion.h:1416
virtual bool canPrintPretty() const
Returns true if this region can be printed in a user-friendly way.
MemSpaceRegion - A memory region that represents a "memory space"; for example, the set of global var...
Definition MemRegion.h:236
SVal - This represents a symbolic expression, which can be either an L-value or an R-value.
Definition SVals.h:56
const MemRegion * getAsRegion() const
Definition SVals.cpp:119
A utility class that visits the reachable symbols using a custom SymbolVisitor.
LLVM_ATTRIBUTE_RETURNS_NONNULL const StackFrameContext * getStackFrame() const
Definition MemRegion.h:433
SymbolicRegion - A special, "non-concrete" region.
Definition MemRegion.h:808
IntrusiveRefCntPtr< const ProgramState > ProgramStateRef
const SymExpr * SymbolRef
Definition SymExpr.h:133
@ OS
Indicates that the tracking object is a descendant of a referenced-counted OSObject,...
const void * Store
Store - This opaque type encapsulates an immutable mapping from locations to values.
Definition StoreRef.h:27
RangeSelector range(RangeSelector Begin, RangeSelector End)
DEPRECATED. Use enclose.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
const FunctionProtoType * T