1 // RetainCountDiagnostics.cpp - Checks for leaks and other issues -*- C++ -*--//
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
7 //===----------------------------------------------------------------------===//
9 // This file defines diagnostics for RetainCountChecker, which implements
10 // a reference count checker for Core Foundation and Cocoa on (Mac OS X).
12 //===----------------------------------------------------------------------===//
14 #include "RetainCountDiagnostics.h"
15 #include "RetainCountChecker.h"
17 using namespace clang;
19 using namespace retaincountchecker;
21 StringRef RefCountBug::bugTypeToName(RefCountBug::RefCountBugType BT) {
24 return "Use-after-release";
28 return "-dealloc sent to non-exclusively owned object";
30 return "freeing non-exclusively owned object";
32 return "Object autoreleased too many times";
33 case ReturnNotOwnedForOwned:
34 return "Method should return an owned object";
35 case LeakWithinFunction:
38 return "Leak of returned object";
40 llvm_unreachable("Unknown RefCountBugType");
43 StringRef RefCountBug::getDescription() const {
46 return "Reference-counted object is used after it is released";
48 return "Incorrect decrement of the reference count of an object that is "
49 "not owned at this point by the caller";
51 return "-dealloc sent to object that may be referenced elsewhere";
53 return "'free' called on an object that may be referenced elsewhere";
55 return "Object autoreleased too many times";
56 case ReturnNotOwnedForOwned:
57 return "Object with a +0 retain count returned to caller where a +1 "
58 "(owning) retain count is expected";
59 case LeakWithinFunction:
63 llvm_unreachable("Unknown RefCountBugType");
66 RefCountBug::RefCountBug(const CheckerBase *Checker, RefCountBugType BT)
67 : BugType(Checker, bugTypeToName(BT), categories::MemoryRefCount,
68 /*SuppressOnSink=*/BT == LeakWithinFunction || BT == LeakAtReturn),
69 BT(BT), Checker(Checker) {}
71 static bool isNumericLiteralExpression(const Expr *E) {
72 // FIXME: This set of cases was copied from SemaExprObjC.
73 return isa<IntegerLiteral>(E) ||
74 isa<CharacterLiteral>(E) ||
75 isa<FloatingLiteral>(E) ||
76 isa<ObjCBoolLiteralExpr>(E) ||
77 isa<CXXBoolLiteralExpr>(E);
80 /// If type represents a pointer to CXXRecordDecl,
81 /// and is not a typedef, return the decl name.
82 /// Otherwise, return the serialization of type.
83 static std::string getPrettyTypeName(QualType QT) {
84 QualType PT = QT->getPointeeType();
85 if (!PT.isNull() && !QT->getAs<TypedefType>())
86 if (const auto *RD = PT->getAsCXXRecordDecl())
88 return QT.getAsString();
91 /// Write information about the type state change to {@code os},
92 /// return whether the note should be generated.
93 static bool shouldGenerateNote(llvm::raw_string_ostream &os,
97 // Get the previous type state.
98 RefVal PrevV = *PrevT;
100 // Specially handle -dealloc.
102 // Determine if the object's reference count was pushed to zero.
103 assert(!PrevV.hasSameState(CurrV) && "The state should have changed.");
104 // We may not have transitioned to 'release' if we hit an error.
105 // This case is handled elsewhere.
106 if (CurrV.getKind() == RefVal::Released) {
107 assert(CurrV.getCombinedCounts() == 0);
108 os << "Object released by directly sending the '-dealloc' message";
113 // Determine if the typestate has changed.
114 if (!PrevV.hasSameState(CurrV))
115 switch (CurrV.getKind()) {
117 case RefVal::NotOwned:
118 if (PrevV.getCount() == CurrV.getCount()) {
119 // Did an autorelease message get sent?
120 if (PrevV.getAutoreleaseCount() == CurrV.getAutoreleaseCount())
123 assert(PrevV.getAutoreleaseCount() < CurrV.getAutoreleaseCount());
124 os << "Object autoreleased";
128 if (PrevV.getCount() > CurrV.getCount())
129 os << "Reference count decremented.";
131 os << "Reference count incremented.";
133 if (unsigned Count = CurrV.getCount())
134 os << " The object now has a +" << Count << " retain count.";
138 case RefVal::Released:
139 if (CurrV.getIvarAccessHistory() ==
140 RefVal::IvarAccessHistory::ReleasedAfterDirectAccess &&
141 CurrV.getIvarAccessHistory() != PrevV.getIvarAccessHistory()) {
142 os << "Strong instance variable relinquished. ";
144 os << "Object released.";
147 case RefVal::ReturnedOwned:
148 // Autoreleases can be applied after marking a node ReturnedOwned.
149 if (CurrV.getAutoreleaseCount())
152 os << "Object returned to caller as an owning reference (single "
153 "retain count transferred to caller)";
156 case RefVal::ReturnedNotOwned:
157 os << "Object returned to caller with a +0 retain count";
166 /// Finds argument index of the out paramter in the call {@code S}
167 /// corresponding to the symbol {@code Sym}.
168 /// If none found, returns None.
169 static Optional<unsigned> findArgIdxOfSymbol(ProgramStateRef CurrSt,
170 const LocationContext *LCtx,
172 Optional<CallEventRef<>> CE) {
176 for (unsigned Idx = 0; Idx < (*CE)->getNumArgs(); Idx++)
177 if (const MemRegion *MR = (*CE)->getArgSVal(Idx).getAsRegion())
178 if (const auto *TR = dyn_cast<TypedValueRegion>(MR))
179 if (CurrSt->getSVal(MR, TR->getValueType()).getAsSymExpr() == Sym)
185 static Optional<std::string> findMetaClassAlloc(const Expr *Callee) {
186 if (const auto *ME = dyn_cast<MemberExpr>(Callee)) {
187 if (ME->getMemberDecl()->getNameAsString() != "alloc")
189 const Expr *This = ME->getBase()->IgnoreParenImpCasts();
190 if (const auto *DRE = dyn_cast<DeclRefExpr>(This)) {
191 const ValueDecl *VD = DRE->getDecl();
192 if (VD->getNameAsString() != "metaClass")
195 if (const auto *RD = dyn_cast<CXXRecordDecl>(VD->getDeclContext()))
196 return RD->getNameAsString();
203 static std::string findAllocatedObjectName(const Stmt *S, QualType QT) {
204 if (const auto *CE = dyn_cast<CallExpr>(S))
205 if (auto Out = findMetaClassAlloc(CE->getCallee()))
207 return getPrettyTypeName(QT);
210 static void generateDiagnosticsForCallLike(ProgramStateRef CurrSt,
211 const LocationContext *LCtx,
212 const RefVal &CurrV, SymbolRef &Sym,
214 llvm::raw_string_ostream &os) {
215 CallEventManager &Mgr = CurrSt->getStateManager().getCallEventManager();
216 if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
217 // Get the name of the callee (if it is available)
218 // from the tracked SVal.
219 SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx);
220 const FunctionDecl *FD = X.getAsFunctionDecl();
222 // If failed, try to get it from AST.
224 FD = dyn_cast<FunctionDecl>(CE->getCalleeDecl());
226 if (const auto *MD = dyn_cast<CXXMethodDecl>(CE->getCalleeDecl())) {
227 os << "Call to method '" << MD->getQualifiedNameAsString() << '\'';
229 os << "Call to function '" << FD->getQualifiedNameAsString() << '\'';
231 os << "function call";
233 } else if (isa<CXXNewExpr>(S)) {
234 os << "Operator 'new'";
236 assert(isa<ObjCMessageExpr>(S));
237 CallEventRef<ObjCMethodCall> Call =
238 Mgr.getObjCMethodCall(cast<ObjCMessageExpr>(S), CurrSt, LCtx);
240 switch (Call->getMessageKind()) {
244 case OCM_PropertyAccess:
253 Optional<CallEventRef<>> CE = Mgr.getCall(S, CurrSt, LCtx);
254 auto Idx = findArgIdxOfSymbol(CurrSt, LCtx, Sym, CE);
256 // If index is not found, we assume that the symbol was returned.
263 if (CurrV.getObjKind() == ObjKind::CF) {
264 os << "a Core Foundation object of type '"
265 << Sym->getType().getAsString() << "' with a ";
266 } else if (CurrV.getObjKind() == ObjKind::OS) {
267 os << "an OSObject of type '" << findAllocatedObjectName(S, Sym->getType())
269 } else if (CurrV.getObjKind() == ObjKind::Generalized) {
270 os << "an object of type '" << Sym->getType().getAsString()
273 assert(CurrV.getObjKind() == ObjKind::ObjC);
274 QualType T = Sym->getType();
275 if (!isa<ObjCObjectPointerType>(T)) {
276 os << "an Objective-C object with a ";
278 const ObjCObjectPointerType *PT = cast<ObjCObjectPointerType>(T);
279 os << "an instance of " << PT->getPointeeType().getAsString()
284 if (CurrV.isOwned()) {
285 os << "+1 retain count";
287 assert(CurrV.isNotOwned());
288 os << "+0 retain count";
292 os << " into an out parameter '";
293 const ParmVarDecl *PVD = (*CE)->parameters()[*Idx];
294 PVD->getNameForDiagnostic(os, PVD->getASTContext().getPrintingPolicy(),
295 /*Qualified=*/false);
298 QualType RT = (*CE)->getResultType();
299 if (!RT.isNull() && !RT->isVoidType()) {
300 SVal RV = (*CE)->getReturnValue();
301 if (CurrSt->isNull(RV).isConstrainedTrue()) {
302 os << " (assuming the call returns zero)";
303 } else if (CurrSt->isNonNull(RV).isConstrainedTrue()) {
304 os << " (assuming the call returns non-zero)";
313 namespace retaincountchecker {
315 class RefCountReportVisitor : public BugReporterVisitor {
320 RefCountReportVisitor(SymbolRef sym) : Sym(sym) {}
322 void Profile(llvm::FoldingSetNodeID &ID) const override {
328 std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
329 BugReporterContext &BRC,
330 BugReport &BR) override;
332 std::shared_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
333 const ExplodedNode *N,
334 BugReport &BR) override;
337 class RefLeakReportVisitor : public RefCountReportVisitor {
339 RefLeakReportVisitor(SymbolRef sym) : RefCountReportVisitor(sym) {}
341 std::shared_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
342 const ExplodedNode *N,
343 BugReport &BR) override;
346 } // end namespace retaincountchecker
347 } // end namespace ento
348 } // end namespace clang
351 /// Find the first node with the parent stack frame.
352 static const ExplodedNode *getCalleeNode(const ExplodedNode *Pred) {
353 const StackFrameContext *SC = Pred->getStackFrame();
354 if (SC->inTopFrame())
356 const StackFrameContext *PC = SC->getParent()->getStackFrame();
360 const ExplodedNode *N = Pred;
361 while (N && N->getStackFrame() != PC) {
362 N = N->getFirstPred();
368 /// Insert a diagnostic piece at function exit
369 /// if a function parameter is annotated as "os_consumed",
370 /// but it does not actually consume the reference.
371 static std::shared_ptr<PathDiagnosticEventPiece>
372 annotateConsumedSummaryMismatch(const ExplodedNode *N,
373 CallExitBegin &CallExitLoc,
374 const SourceManager &SM,
375 CallEventManager &CEMgr) {
377 const ExplodedNode *CN = getCalleeNode(N);
381 CallEventRef<> Call = CEMgr.getCaller(N->getStackFrame(), N->getState());
384 llvm::raw_string_ostream os(sbuf);
385 ArrayRef<const ParmVarDecl *> Parameters = Call->parameters();
386 for (unsigned I=0; I < Call->getNumArgs() && I < Parameters.size(); ++I) {
387 const ParmVarDecl *PVD = Parameters[I];
389 if (!PVD->hasAttr<OSConsumedAttr>())
392 if (SymbolRef SR = Call->getArgSVal(I).getAsLocSymbol()) {
393 const RefVal *CountBeforeCall = getRefBinding(CN->getState(), SR);
394 const RefVal *CountAtExit = getRefBinding(N->getState(), SR);
396 if (!CountBeforeCall || !CountAtExit)
399 unsigned CountBefore = CountBeforeCall->getCount();
400 unsigned CountAfter = CountAtExit->getCount();
402 bool AsExpected = CountBefore > 0 && CountAfter == CountBefore - 1;
405 PVD->getNameForDiagnostic(os, PVD->getASTContext().getPrintingPolicy(),
406 /*Qualified=*/false);
407 os << "' is marked as consuming, but the function did not consume "
408 << "the reference\n";
413 if (os.str().empty())
416 PathDiagnosticLocation L = PathDiagnosticLocation::create(CallExitLoc, SM);
417 return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
420 /// Annotate the parameter at the analysis entry point.
421 static std::shared_ptr<PathDiagnosticEventPiece>
422 annotateStartParameter(const ExplodedNode *N, SymbolRef Sym,
423 const SourceManager &SM) {
424 auto PP = N->getLocationAs<BlockEdge>();
428 const CFGBlock *Src = PP->getSrc();
429 const RefVal *CurrT = getRefBinding(N->getState(), Sym);
431 if (&Src->getParent()->getEntry() != Src || !CurrT ||
432 getRefBinding(N->getFirstPred()->getState(), Sym))
435 const auto *VR = cast<VarRegion>(cast<SymbolRegionValue>(Sym)->getRegion());
436 const auto *PVD = cast<ParmVarDecl>(VR->getDecl());
437 PathDiagnosticLocation L = PathDiagnosticLocation(PVD, SM);
440 llvm::raw_string_ostream os(s);
441 os << "Parameter '" << PVD->getNameAsString() << "' starts at +";
442 if (CurrT->getCount() == 1) {
443 os << "1, as it is marked as consuming";
445 assert(CurrT->getCount() == 0);
448 return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
451 std::shared_ptr<PathDiagnosticPiece>
452 RefCountReportVisitor::VisitNode(const ExplodedNode *N,
453 BugReporterContext &BRC, BugReport &BR) {
455 const auto &BT = static_cast<const RefCountBug&>(BR.getBugType());
456 const auto *Checker =
457 static_cast<const RetainCountChecker *>(BT.getChecker());
459 bool IsFreeUnowned = BT.getBugType() == RefCountBug::FreeNotOwned ||
460 BT.getBugType() == RefCountBug::DeallocNotOwned;
462 const SourceManager &SM = BRC.getSourceManager();
463 CallEventManager &CEMgr = BRC.getStateManager().getCallEventManager();
464 if (auto CE = N->getLocationAs<CallExitBegin>())
465 if (auto PD = annotateConsumedSummaryMismatch(N, *CE, SM, CEMgr))
468 if (auto PD = annotateStartParameter(N, Sym, SM))
471 // FIXME: We will eventually need to handle non-statement-based events
472 // (__attribute__((cleanup))).
473 if (!N->getLocation().getAs<StmtPoint>())
476 // Check if the type state has changed.
477 const ExplodedNode *PrevNode = N->getFirstPred();
478 ProgramStateRef PrevSt = PrevNode->getState();
479 ProgramStateRef CurrSt = N->getState();
480 const LocationContext *LCtx = N->getLocationContext();
482 const RefVal* CurrT = getRefBinding(CurrSt, Sym);
486 const RefVal &CurrV = *CurrT;
487 const RefVal *PrevT = getRefBinding(PrevSt, Sym);
489 // Create a string buffer to constain all the useful things we want
492 llvm::raw_string_ostream os(sbuf);
494 if (PrevT && IsFreeUnowned && CurrV.isNotOwned() && PrevT->isOwned()) {
495 os << "Object is now not exclusively owned";
496 auto Pos = PathDiagnosticLocation::create(N->getLocation(), SM);
497 return std::make_shared<PathDiagnosticEventPiece>(Pos, os.str());
500 // This is the allocation site since the previous node had no bindings
503 const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
505 if (isa<ObjCIvarRefExpr>(S) &&
506 isSynthesizedAccessor(LCtx->getStackFrame())) {
507 S = LCtx->getStackFrame()->getCallSite();
510 if (isa<ObjCArrayLiteral>(S)) {
511 os << "NSArray literal is an object with a +0 retain count";
512 } else if (isa<ObjCDictionaryLiteral>(S)) {
513 os << "NSDictionary literal is an object with a +0 retain count";
514 } else if (const ObjCBoxedExpr *BL = dyn_cast<ObjCBoxedExpr>(S)) {
515 if (isNumericLiteralExpression(BL->getSubExpr()))
516 os << "NSNumber literal is an object with a +0 retain count";
518 const ObjCInterfaceDecl *BoxClass = nullptr;
519 if (const ObjCMethodDecl *Method = BL->getBoxingMethod())
520 BoxClass = Method->getClassInterface();
522 // We should always be able to find the boxing class interface,
523 // but consider this future-proofing.
525 os << *BoxClass << " b";
530 os << "oxed expression produces an object with a +0 retain count";
532 } else if (isa<ObjCIvarRefExpr>(S)) {
533 os << "Object loaded from instance variable";
535 generateDiagnosticsForCallLike(CurrSt, LCtx, CurrV, Sym, S, os);
538 PathDiagnosticLocation Pos(S, SM, N->getLocationContext());
539 return std::make_shared<PathDiagnosticEventPiece>(Pos, os.str());
542 // Gather up the effects that were performed on the object at this
544 bool DeallocSent = false;
546 const ProgramPointTag *Tag = N->getLocation().getTag();
548 if (Tag == &Checker->getCastFailTag()) {
549 os << "Assuming dynamic cast returns null due to type mismatch";
552 if (Tag == &Checker->getDeallocSentTag()) {
553 // We only have summaries attached to nodes after evaluating CallExpr and
555 const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
557 if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
558 // Iterate through the parameter expressions and see if the symbol
559 // was ever passed as an argument.
562 for (auto AI=CE->arg_begin(), AE=CE->arg_end(); AI!=AE; ++AI, ++i) {
564 // Retrieve the value of the argument. Is it the symbol
565 // we are interested in?
566 if (CurrSt->getSValAsScalarOrLoc(*AI, LCtx).getAsLocSymbol() != Sym)
569 // We have an argument. Get the effect!
572 } else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {
573 if (const Expr *receiver = ME->getInstanceReceiver()) {
574 if (CurrSt->getSValAsScalarOrLoc(receiver, LCtx)
575 .getAsLocSymbol() == Sym) {
576 // The symbol we are tracking is the receiver.
583 if (!shouldGenerateNote(os, PrevT, CurrV, DeallocSent))
586 if (os.str().empty())
587 return nullptr; // We have nothing to say!
589 const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
590 PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
591 N->getLocationContext());
592 auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, os.str());
594 // Add the range by scanning the children of the statement for any bindings
596 for (const Stmt *Child : S->children())
597 if (const Expr *Exp = dyn_cast_or_null<Expr>(Child))
598 if (CurrSt->getSValAsScalarOrLoc(Exp, LCtx).getAsLocSymbol() == Sym) {
599 P->addRange(Exp->getSourceRange());
606 static Optional<std::string> describeRegion(const MemRegion *MR) {
607 if (const auto *VR = dyn_cast_or_null<VarRegion>(MR))
608 return std::string(VR->getDecl()->getName());
609 // Once we support more storage locations for bindings,
610 // this would need to be improved.
615 // Find the first node in the current function context that referred to the
616 // tracked symbol and the memory location that value was stored to. Note, the
617 // value is only reported if the allocation occurred in the same function as
618 // the leak. The function can also return a location context, which should be
619 // treated as interesting.
620 struct AllocationInfo {
621 const ExplodedNode* N;
623 const LocationContext *InterestingMethodContext;
624 AllocationInfo(const ExplodedNode *InN,
625 const MemRegion *InR,
626 const LocationContext *InInterestingMethodContext) :
627 N(InN), R(InR), InterestingMethodContext(InInterestingMethodContext) {}
629 } // end anonymous namespace
631 static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
632 const ExplodedNode *N, SymbolRef Sym) {
633 const ExplodedNode *AllocationNode = N;
634 const ExplodedNode *AllocationNodeInCurrentOrParentContext = N;
635 const MemRegion *FirstBinding = nullptr;
636 const LocationContext *LeakContext = N->getLocationContext();
638 // The location context of the init method called on the leaked object, if
640 const LocationContext *InitMethodContext = nullptr;
643 ProgramStateRef St = N->getState();
644 const LocationContext *NContext = N->getLocationContext();
646 if (!getRefBinding(St, Sym))
649 StoreManager::FindUniqueBinding FB(Sym);
650 StateMgr.iterBindings(St, FB);
653 const MemRegion *R = FB.getRegion();
654 // Do not show local variables belonging to a function other than
655 // where the error is reported.
656 if (auto MR = dyn_cast<StackSpaceRegion>(R->getMemorySpace()))
657 if (MR->getStackFrame() == LeakContext->getStackFrame())
661 // AllocationNode is the last node in which the symbol was tracked.
664 // AllocationNodeInCurrentContext, is the last node in the current or
665 // parent context in which the symbol was tracked.
667 // Note that the allocation site might be in the parent context. For example,
668 // the case where an allocation happens in a block that captures a reference
669 // to it and that reference is overwritten/dropped by another call to
671 if (NContext == LeakContext || NContext->isParentOf(LeakContext))
672 AllocationNodeInCurrentOrParentContext = N;
674 // Find the last init that was called on the given symbol and store the
675 // init method's location context.
676 if (!InitMethodContext)
677 if (auto CEP = N->getLocation().getAs<CallEnter>()) {
678 const Stmt *CE = CEP->getCallExpr();
679 if (const auto *ME = dyn_cast_or_null<ObjCMessageExpr>(CE)) {
680 const Stmt *RecExpr = ME->getInstanceReceiver();
682 SVal RecV = St->getSVal(RecExpr, NContext);
683 if (ME->getMethodFamily() == OMF_init && RecV.getAsSymbol() == Sym)
684 InitMethodContext = CEP->getCalleeContext();
689 N = N->getFirstPred();
692 // If we are reporting a leak of the object that was allocated with alloc,
693 // mark its init method as interesting.
694 const LocationContext *InterestingMethodContext = nullptr;
695 if (InitMethodContext) {
696 const ProgramPoint AllocPP = AllocationNode->getLocation();
697 if (Optional<StmtPoint> SP = AllocPP.getAs<StmtPoint>())
698 if (const ObjCMessageExpr *ME = SP->getStmtAs<ObjCMessageExpr>())
699 if (ME->getMethodFamily() == OMF_alloc)
700 InterestingMethodContext = InitMethodContext;
703 // If allocation happened in a function different from the leak node context,
704 // do not report the binding.
705 assert(N && "Could not find allocation node");
707 if (AllocationNodeInCurrentOrParentContext &&
708 AllocationNodeInCurrentOrParentContext->getLocationContext() !=
710 FirstBinding = nullptr;
712 return AllocationInfo(AllocationNodeInCurrentOrParentContext,
714 InterestingMethodContext);
717 std::shared_ptr<PathDiagnosticPiece>
718 RefCountReportVisitor::getEndPath(BugReporterContext &BRC,
719 const ExplodedNode *EndN, BugReport &BR) {
720 BR.markInteresting(Sym);
721 return BugReporterVisitor::getDefaultEndPath(BRC, EndN, BR);
724 std::shared_ptr<PathDiagnosticPiece>
725 RefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
726 const ExplodedNode *EndN, BugReport &BR) {
728 // Tell the BugReporterContext to report cases when the tracked symbol is
729 // assigned to different variables, etc.
730 BR.markInteresting(Sym);
732 // We are reporting a leak. Walk up the graph to get to the first node where
733 // the symbol appeared, and also get the first VarDecl that tracked object
735 AllocationInfo AllocI = GetAllocationSite(BRC.getStateManager(), EndN, Sym);
737 const MemRegion* FirstBinding = AllocI.R;
738 BR.markInteresting(AllocI.InterestingMethodContext);
740 SourceManager& SM = BRC.getSourceManager();
742 // Compute an actual location for the leak. Sometimes a leak doesn't
743 // occur at an actual statement (e.g., transition between blocks; end
744 // of function) so we need to walk the graph and compute a real location.
745 const ExplodedNode *LeakN = EndN;
746 PathDiagnosticLocation L = PathDiagnosticLocation::createEndOfPath(LeakN, SM);
749 llvm::raw_string_ostream os(sbuf);
751 os << "Object leaked: ";
753 Optional<std::string> RegionDescription = describeRegion(FirstBinding);
754 if (RegionDescription) {
755 os << "object allocated and stored into '" << *RegionDescription << '\'';
757 os << "allocated object of type '" << getPrettyTypeName(Sym->getType())
761 // Get the retain count.
762 const RefVal* RV = getRefBinding(EndN->getState(), Sym);
765 if (RV->getKind() == RefVal::ErrorLeakReturned) {
766 // FIXME: Per comments in rdar://6320065, "create" only applies to CF
767 // objects. Only "copy", "alloc", "retain" and "new" transfer ownership
768 // to the caller for NS objects.
769 const Decl *D = &EndN->getCodeDecl();
771 os << (isa<ObjCMethodDecl>(D) ? " is returned from a method "
772 : " is returned from a function ");
774 if (D->hasAttr<CFReturnsNotRetainedAttr>()) {
775 os << "that is annotated as CF_RETURNS_NOT_RETAINED";
776 } else if (D->hasAttr<NSReturnsNotRetainedAttr>()) {
777 os << "that is annotated as NS_RETURNS_NOT_RETAINED";
778 } else if (D->hasAttr<OSReturnsNotRetainedAttr>()) {
779 os << "that is annotated as OS_RETURNS_NOT_RETAINED";
781 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
782 if (BRC.getASTContext().getLangOpts().ObjCAutoRefCount) {
783 os << "managed by Automatic Reference Counting";
785 os << "whose name ('" << MD->getSelector().getAsString()
786 << "') does not start with "
787 "'copy', 'mutableCopy', 'alloc' or 'new'."
788 " This violates the naming convention rules"
789 " given in the Memory Management Guide for Cocoa";
792 const FunctionDecl *FD = cast<FunctionDecl>(D);
793 ObjKind K = RV->getObjKind();
794 if (K == ObjKind::ObjC || K == ObjKind::CF) {
795 os << "whose name ('" << *FD
796 << "') does not contain 'Copy' or 'Create'. This violates the "
798 " convention rules given in the Memory Management Guide for "
801 } else if (RV->getObjKind() == ObjKind::OS) {
802 std::string FuncName = FD->getNameAsString();
803 os << "whose name ('" << FuncName
804 << "') starts with '" << StringRef(FuncName).substr(0, 3) << "'";
809 os << " is not referenced later in this execution path and has a retain "
810 "count of +" << RV->getCount();
813 return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
816 RefCountReport::RefCountReport(const RefCountBug &D, const LangOptions &LOpts,
817 ExplodedNode *n, SymbolRef sym,
819 : BugReport(D, D.getDescription(), n), Sym(sym), isLeak(isLeak) {
821 addVisitor(llvm::make_unique<RefCountReportVisitor>(sym));
824 RefCountReport::RefCountReport(const RefCountBug &D, const LangOptions &LOpts,
825 ExplodedNode *n, SymbolRef sym,
827 : BugReport(D, D.getDescription(), endText, n) {
829 addVisitor(llvm::make_unique<RefCountReportVisitor>(sym));
832 void RefLeakReport::deriveParamLocation(CheckerContext &Ctx, SymbolRef sym) {
833 const SourceManager& SMgr = Ctx.getSourceManager();
835 if (!sym->getOriginRegion())
838 auto *Region = dyn_cast<DeclRegion>(sym->getOriginRegion());
840 const Decl *PDecl = Region->getDecl();
841 if (PDecl && isa<ParmVarDecl>(PDecl)) {
842 PathDiagnosticLocation ParamLocation =
843 PathDiagnosticLocation::create(PDecl, SMgr);
844 Location = ParamLocation;
845 UniqueingLocation = ParamLocation;
846 UniqueingDecl = Ctx.getLocationContext()->getDecl();
851 void RefLeakReport::deriveAllocLocation(CheckerContext &Ctx,
853 // Most bug reports are cached at the location where they occurred.
854 // With leaks, we want to unique them by the location where they were
855 // allocated, and only report a single path. To do this, we need to find
856 // the allocation site of a piece of tracked memory, which we do via a
857 // call to GetAllocationSite. This will walk the ExplodedGraph backwards.
858 // Note that this is *not* the trimmed graph; we are guaranteed, however,
859 // that all ancestor nodes that represent the allocation site have the
860 // same SourceLocation.
861 const ExplodedNode *AllocNode = nullptr;
863 const SourceManager& SMgr = Ctx.getSourceManager();
865 AllocationInfo AllocI =
866 GetAllocationSite(Ctx.getStateManager(), getErrorNode(), sym);
868 AllocNode = AllocI.N;
869 AllocBinding = AllocI.R;
870 markInteresting(AllocI.InterestingMethodContext);
872 // Get the SourceLocation for the allocation site.
873 // FIXME: This will crash the analyzer if an allocation comes from an
874 // implicit call (ex: a destructor call).
875 // (Currently there are no such allocations in Cocoa, though.)
876 AllocStmt = PathDiagnosticLocation::getStmt(AllocNode);
879 AllocBinding = nullptr;
883 PathDiagnosticLocation AllocLocation =
884 PathDiagnosticLocation::createBegin(AllocStmt, SMgr,
885 AllocNode->getLocationContext());
886 Location = AllocLocation;
888 // Set uniqieing info, which will be used for unique the bug reports. The
889 // leaks should be uniqued on the allocation site.
890 UniqueingLocation = AllocLocation;
891 UniqueingDecl = AllocNode->getLocationContext()->getDecl();
894 void RefLeakReport::createDescription(CheckerContext &Ctx) {
895 assert(Location.isValid() && UniqueingDecl && UniqueingLocation.isValid());
897 llvm::raw_string_ostream os(Description);
898 os << "Potential leak of an object";
900 Optional<std::string> RegionDescription = describeRegion(AllocBinding);
901 if (RegionDescription) {
902 os << " stored into '" << *RegionDescription << '\'';
905 // If we can't figure out the name, just supply the type information.
906 os << " of type '" << getPrettyTypeName(Sym->getType()) << "'";
910 RefLeakReport::RefLeakReport(const RefCountBug &D, const LangOptions &LOpts,
911 ExplodedNode *n, SymbolRef sym,
913 : RefCountReport(D, LOpts, n, sym, /*isLeak=*/true) {
915 deriveAllocLocation(Ctx, sym);
917 deriveParamLocation(Ctx, sym);
919 createDescription(Ctx);
921 addVisitor(llvm::make_unique<RefLeakReportVisitor>(sym));