xref: /llvm-project/clang/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.cpp (revision 936a9c978c8f6970ed57725994ada6dd5f9c3e07)
1 // RetainCountDiagnostics.cpp - Checks for leaks and other issues -*- C++ -*--//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  This file defines diagnostics for RetainCountChecker, which implements
11 //  a reference count checker for Core Foundation and Cocoa on (Mac OS X).
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "RetainCountDiagnostics.h"
16 #include "RetainCountChecker.h"
17 
18 using namespace clang;
19 using namespace ento;
20 using namespace retaincountchecker;
21 
22 static bool isNumericLiteralExpression(const Expr *E) {
23   // FIXME: This set of cases was copied from SemaExprObjC.
24   return isa<IntegerLiteral>(E) ||
25          isa<CharacterLiteral>(E) ||
26          isa<FloatingLiteral>(E) ||
27          isa<ObjCBoolLiteralExpr>(E) ||
28          isa<CXXBoolLiteralExpr>(E);
29 }
30 
31 /// If type represents a pointer to CXXRecordDecl,
32 /// and is not a typedef, return the decl name.
33 /// Otherwise, return the serialization of type.
34 static std::string getPrettyTypeName(QualType QT) {
35   QualType PT = QT->getPointeeType();
36   if (!PT.isNull() && !QT->getAs<TypedefType>())
37     if (const auto *RD = PT->getAsCXXRecordDecl())
38       return RD->getName();
39   return QT.getAsString();
40 }
41 
42 /// Write information about the type state change to {@code os},
43 /// return whether the note should be generated.
44 static bool shouldGenerateNote(llvm::raw_string_ostream &os,
45                                const RefVal *PrevT, const RefVal &CurrV,
46                                SmallVector<ArgEffect, 2> &AEffects) {
47   // Get the previous type state.
48   RefVal PrevV = *PrevT;
49 
50   // Specially handle -dealloc.
51   if (std::find(AEffects.begin(), AEffects.end(), Dealloc) != AEffects.end()) {
52     // Determine if the object's reference count was pushed to zero.
53     assert(!PrevV.hasSameState(CurrV) && "The state should have changed.");
54     // We may not have transitioned to 'release' if we hit an error.
55     // This case is handled elsewhere.
56     if (CurrV.getKind() == RefVal::Released) {
57       assert(CurrV.getCombinedCounts() == 0);
58       os << "Object released by directly sending the '-dealloc' message";
59       return true;
60     }
61   }
62 
63   // Determine if the typestate has changed.
64   if (!PrevV.hasSameState(CurrV))
65     switch (CurrV.getKind()) {
66     case RefVal::Owned:
67     case RefVal::NotOwned:
68       if (PrevV.getCount() == CurrV.getCount()) {
69         // Did an autorelease message get sent?
70         if (PrevV.getAutoreleaseCount() == CurrV.getAutoreleaseCount())
71           return false;
72 
73         assert(PrevV.getAutoreleaseCount() < CurrV.getAutoreleaseCount());
74         os << "Object autoreleased";
75         return true;
76       }
77 
78       if (PrevV.getCount() > CurrV.getCount())
79         os << "Reference count decremented.";
80       else
81         os << "Reference count incremented.";
82 
83       if (unsigned Count = CurrV.getCount())
84         os << " The object now has a +" << Count << " retain count.";
85 
86       return true;
87 
88     case RefVal::Released:
89       if (CurrV.getIvarAccessHistory() ==
90               RefVal::IvarAccessHistory::ReleasedAfterDirectAccess &&
91           CurrV.getIvarAccessHistory() != PrevV.getIvarAccessHistory()) {
92         os << "Strong instance variable relinquished. ";
93       }
94       os << "Object released.";
95       return true;
96 
97     case RefVal::ReturnedOwned:
98       // Autoreleases can be applied after marking a node ReturnedOwned.
99       if (CurrV.getAutoreleaseCount())
100         return false;
101 
102       os << "Object returned to caller as an owning reference (single "
103             "retain count transferred to caller)";
104       return true;
105 
106     case RefVal::ReturnedNotOwned:
107       os << "Object returned to caller with a +0 retain count";
108       return true;
109 
110     default:
111       return false;
112     }
113   return true;
114 }
115 
116 static void generateDiagnosticsForCallLike(
117   ProgramStateRef CurrSt,
118   const LocationContext *LCtx,
119   const RefVal &CurrV,
120   SymbolRef &Sym,
121   const Stmt *S,
122   llvm::raw_string_ostream &os) {
123   if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
124     // Get the name of the callee (if it is available)
125     // from the tracked SVal.
126     SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx);
127     const FunctionDecl *FD = X.getAsFunctionDecl();
128 
129     // If failed, try to get it from AST.
130     if (!FD)
131       FD = dyn_cast<FunctionDecl>(CE->getCalleeDecl());
132 
133     if (const auto *MD = dyn_cast<CXXMethodDecl>(CE->getCalleeDecl())) {
134       os << "Call to method '" << MD->getQualifiedNameAsString() << '\'';
135     } else if (FD) {
136       os << "Call to function '" << FD->getQualifiedNameAsString() << '\'';
137     } else {
138       os << "function call";
139     }
140   } else if (isa<CXXNewExpr>(S)){
141     os << "Operator new";
142   } else {
143     assert(isa<ObjCMessageExpr>(S));
144     CallEventManager &Mgr = CurrSt->getStateManager().getCallEventManager();
145     CallEventRef<ObjCMethodCall> Call =
146         Mgr.getObjCMethodCall(cast<ObjCMessageExpr>(S), CurrSt, LCtx);
147 
148     switch (Call->getMessageKind()) {
149     case OCM_Message:
150       os << "Method";
151       break;
152     case OCM_PropertyAccess:
153       os << "Property";
154       break;
155     case OCM_Subscript:
156       os << "Subscript";
157       break;
158     }
159   }
160 
161   if (CurrV.getObjKind() == RetEffect::CF) {
162     os << " returns a Core Foundation object of type "
163        << Sym->getType().getAsString() << " with a ";
164   } else if (CurrV.getObjKind() == RetEffect::OS) {
165     os << " returns an OSObject of type " << getPrettyTypeName(Sym->getType())
166        << " with a ";
167   } else if (CurrV.getObjKind() == RetEffect::Generalized) {
168     os << " returns an object of type " << Sym->getType().getAsString()
169        << " with a ";
170   } else {
171     assert(CurrV.getObjKind() == RetEffect::ObjC);
172     QualType T = Sym->getType();
173     if (!isa<ObjCObjectPointerType>(T)) {
174       os << " returns an Objective-C object with a ";
175     } else {
176       const ObjCObjectPointerType *PT = cast<ObjCObjectPointerType>(T);
177       os << " returns an instance of " << PT->getPointeeType().getAsString()
178          << " with a ";
179     }
180   }
181 
182   if (CurrV.isOwned()) {
183     os << "+1 retain count";
184   } else {
185     assert(CurrV.isNotOwned());
186     os << "+0 retain count";
187   }
188 }
189 
190 namespace clang {
191 namespace ento {
192 namespace retaincountchecker {
193 
194 class CFRefReportVisitor : public BugReporterVisitor {
195 protected:
196   SymbolRef Sym;
197   const SummaryLogTy &SummaryLog;
198 
199 public:
200   CFRefReportVisitor(SymbolRef sym, const SummaryLogTy &log)
201       : Sym(sym), SummaryLog(log) {}
202 
203   void Profile(llvm::FoldingSetNodeID &ID) const override {
204     static int x = 0;
205     ID.AddPointer(&x);
206     ID.AddPointer(Sym);
207   }
208 
209   std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
210                                                  BugReporterContext &BRC,
211                                                  BugReport &BR) override;
212 
213   std::shared_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
214                                                   const ExplodedNode *N,
215                                                   BugReport &BR) override;
216 };
217 
218 class CFRefLeakReportVisitor : public CFRefReportVisitor {
219 public:
220   CFRefLeakReportVisitor(SymbolRef sym,
221                          const SummaryLogTy &log)
222      : CFRefReportVisitor(sym, log) {}
223 
224   std::shared_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
225                                                   const ExplodedNode *N,
226                                                   BugReport &BR) override;
227 };
228 
229 } // end namespace retaincountchecker
230 } // end namespace ento
231 } // end namespace clang
232 
233 std::shared_ptr<PathDiagnosticPiece>
234 CFRefReportVisitor::VisitNode(const ExplodedNode *N,
235                               BugReporterContext &BRC, BugReport &BR) {
236   // FIXME: We will eventually need to handle non-statement-based events
237   // (__attribute__((cleanup))).
238   if (!N->getLocation().getAs<StmtPoint>())
239     return nullptr;
240 
241   // Check if the type state has changed.
242   const ExplodedNode *PrevNode = N->getFirstPred();
243   ProgramStateRef PrevSt = PrevNode->getState();
244   ProgramStateRef CurrSt = N->getState();
245   const LocationContext *LCtx = N->getLocationContext();
246 
247   const RefVal* CurrT = getRefBinding(CurrSt, Sym);
248   if (!CurrT) return nullptr;
249 
250   const RefVal &CurrV = *CurrT;
251   const RefVal *PrevT = getRefBinding(PrevSt, Sym);
252 
253   // Create a string buffer to constain all the useful things we want
254   // to tell the user.
255   std::string sbuf;
256   llvm::raw_string_ostream os(sbuf);
257 
258   // This is the allocation site since the previous node had no bindings
259   // for this symbol.
260   if (!PrevT) {
261     const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
262 
263     if (isa<ObjCIvarRefExpr>(S) &&
264         isSynthesizedAccessor(LCtx->getStackFrame())) {
265       S = LCtx->getStackFrame()->getCallSite();
266     }
267 
268     if (isa<ObjCArrayLiteral>(S)) {
269       os << "NSArray literal is an object with a +0 retain count";
270     } else if (isa<ObjCDictionaryLiteral>(S)) {
271       os << "NSDictionary literal is an object with a +0 retain count";
272     } else if (const ObjCBoxedExpr *BL = dyn_cast<ObjCBoxedExpr>(S)) {
273       if (isNumericLiteralExpression(BL->getSubExpr()))
274         os << "NSNumber literal is an object with a +0 retain count";
275       else {
276         const ObjCInterfaceDecl *BoxClass = nullptr;
277         if (const ObjCMethodDecl *Method = BL->getBoxingMethod())
278           BoxClass = Method->getClassInterface();
279 
280         // We should always be able to find the boxing class interface,
281         // but consider this future-proofing.
282         if (BoxClass) {
283           os << *BoxClass << " b";
284         } else {
285           os << "B";
286         }
287 
288         os << "oxed expression produces an object with a +0 retain count";
289       }
290     } else if (isa<ObjCIvarRefExpr>(S)) {
291       os << "Object loaded from instance variable";
292     } else {
293       generateDiagnosticsForCallLike(CurrSt, LCtx, CurrV, Sym, S, os);
294     }
295 
296     PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
297                                   N->getLocationContext());
298     return std::make_shared<PathDiagnosticEventPiece>(Pos, os.str());
299   }
300 
301   // Gather up the effects that were performed on the object at this
302   // program point
303   SmallVector<ArgEffect, 2> AEffects;
304 
305   const ExplodedNode *OrigNode = BRC.getNodeResolver().getOriginalNode(N);
306   if (const RetainSummary *Summ = SummaryLog.lookup(OrigNode)) {
307     // We only have summaries attached to nodes after evaluating CallExpr and
308     // ObjCMessageExprs.
309     const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
310 
311     if (const CallExpr *CE = dyn_cast<CallExpr>(S)) {
312       // Iterate through the parameter expressions and see if the symbol
313       // was ever passed as an argument.
314       unsigned i = 0;
315 
316       for (auto AI=CE->arg_begin(), AE=CE->arg_end(); AI!=AE; ++AI, ++i) {
317 
318         // Retrieve the value of the argument.  Is it the symbol
319         // we are interested in?
320         if (CurrSt->getSValAsScalarOrLoc(*AI, LCtx).getAsLocSymbol() != Sym)
321           continue;
322 
323         // We have an argument.  Get the effect!
324         AEffects.push_back(Summ->getArg(i));
325       }
326     } else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) {
327       if (const Expr *receiver = ME->getInstanceReceiver()) {
328         if (CurrSt->getSValAsScalarOrLoc(receiver, LCtx)
329               .getAsLocSymbol() == Sym) {
330           // The symbol we are tracking is the receiver.
331           AEffects.push_back(Summ->getReceiverEffect());
332         }
333       }
334     }
335   }
336 
337   if (!shouldGenerateNote(os, PrevT, CurrV, AEffects))
338     return nullptr;
339 
340   if (os.str().empty())
341     return nullptr; // We have nothing to say!
342 
343   const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt();
344   PathDiagnosticLocation Pos(S, BRC.getSourceManager(),
345                                 N->getLocationContext());
346   auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, os.str());
347 
348   // Add the range by scanning the children of the statement for any bindings
349   // to Sym.
350   for (const Stmt *Child : S->children())
351     if (const Expr *Exp = dyn_cast_or_null<Expr>(Child))
352       if (CurrSt->getSValAsScalarOrLoc(Exp, LCtx).getAsLocSymbol() == Sym) {
353         P->addRange(Exp->getSourceRange());
354         break;
355       }
356 
357   return std::move(P);
358 }
359 
360 static Optional<std::string> describeRegion(const MemRegion *MR) {
361   if (const auto *VR = dyn_cast_or_null<VarRegion>(MR))
362     return std::string(VR->getDecl()->getName());
363   // Once we support more storage locations for bindings,
364   // this would need to be improved.
365   return None;
366 }
367 
368 namespace {
369 // Find the first node in the current function context that referred to the
370 // tracked symbol and the memory location that value was stored to. Note, the
371 // value is only reported if the allocation occurred in the same function as
372 // the leak. The function can also return a location context, which should be
373 // treated as interesting.
374 struct AllocationInfo {
375   const ExplodedNode* N;
376   const MemRegion *R;
377   const LocationContext *InterestingMethodContext;
378   AllocationInfo(const ExplodedNode *InN,
379                  const MemRegion *InR,
380                  const LocationContext *InInterestingMethodContext) :
381     N(InN), R(InR), InterestingMethodContext(InInterestingMethodContext) {}
382 };
383 } // end anonymous namespace
384 
385 static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr,
386                                         const ExplodedNode *N, SymbolRef Sym) {
387   const ExplodedNode *AllocationNode = N;
388   const ExplodedNode *AllocationNodeInCurrentOrParentContext = N;
389   const MemRegion *FirstBinding = nullptr;
390   const LocationContext *LeakContext = N->getLocationContext();
391 
392   // The location context of the init method called on the leaked object, if
393   // available.
394   const LocationContext *InitMethodContext = nullptr;
395 
396   while (N) {
397     ProgramStateRef St = N->getState();
398     const LocationContext *NContext = N->getLocationContext();
399 
400     if (!getRefBinding(St, Sym))
401       break;
402 
403     StoreManager::FindUniqueBinding FB(Sym);
404     StateMgr.iterBindings(St, FB);
405 
406     if (FB) {
407       const MemRegion *R = FB.getRegion();
408       const VarRegion *VR = R->getBaseRegion()->getAs<VarRegion>();
409       // Do not show local variables belonging to a function other than
410       // where the error is reported.
411       if (!VR || VR->getStackFrame() == LeakContext->getStackFrame())
412         FirstBinding = R;
413     }
414 
415     // AllocationNode is the last node in which the symbol was tracked.
416     AllocationNode = N;
417 
418     // AllocationNodeInCurrentContext, is the last node in the current or
419     // parent context in which the symbol was tracked.
420     //
421     // Note that the allocation site might be in the parent conext. For example,
422     // the case where an allocation happens in a block that captures a reference
423     // to it and that reference is overwritten/dropped by another call to
424     // the block.
425     if (NContext == LeakContext || NContext->isParentOf(LeakContext))
426       AllocationNodeInCurrentOrParentContext = N;
427 
428     // Find the last init that was called on the given symbol and store the
429     // init method's location context.
430     if (!InitMethodContext)
431       if (auto CEP = N->getLocation().getAs<CallEnter>()) {
432         const Stmt *CE = CEP->getCallExpr();
433         if (const auto *ME = dyn_cast_or_null<ObjCMessageExpr>(CE)) {
434           const Stmt *RecExpr = ME->getInstanceReceiver();
435           if (RecExpr) {
436             SVal RecV = St->getSVal(RecExpr, NContext);
437             if (ME->getMethodFamily() == OMF_init && RecV.getAsSymbol() == Sym)
438               InitMethodContext = CEP->getCalleeContext();
439           }
440         }
441       }
442 
443     N = N->getFirstPred();
444   }
445 
446   // If we are reporting a leak of the object that was allocated with alloc,
447   // mark its init method as interesting.
448   const LocationContext *InterestingMethodContext = nullptr;
449   if (InitMethodContext) {
450     const ProgramPoint AllocPP = AllocationNode->getLocation();
451     if (Optional<StmtPoint> SP = AllocPP.getAs<StmtPoint>())
452       if (const ObjCMessageExpr *ME = SP->getStmtAs<ObjCMessageExpr>())
453         if (ME->getMethodFamily() == OMF_alloc)
454           InterestingMethodContext = InitMethodContext;
455   }
456 
457   // If allocation happened in a function different from the leak node context,
458   // do not report the binding.
459   assert(N && "Could not find allocation node");
460 
461   if (AllocationNodeInCurrentOrParentContext &&
462       AllocationNodeInCurrentOrParentContext->getLocationContext() !=
463           LeakContext)
464     FirstBinding = nullptr;
465 
466   return AllocationInfo(AllocationNodeInCurrentOrParentContext,
467                         FirstBinding,
468                         InterestingMethodContext);
469 }
470 
471 std::shared_ptr<PathDiagnosticPiece>
472 CFRefReportVisitor::getEndPath(BugReporterContext &BRC,
473                                const ExplodedNode *EndN, BugReport &BR) {
474   BR.markInteresting(Sym);
475   return BugReporterVisitor::getDefaultEndPath(BRC, EndN, BR);
476 }
477 
478 std::shared_ptr<PathDiagnosticPiece>
479 CFRefLeakReportVisitor::getEndPath(BugReporterContext &BRC,
480                                    const ExplodedNode *EndN, BugReport &BR) {
481 
482   // Tell the BugReporterContext to report cases when the tracked symbol is
483   // assigned to different variables, etc.
484   BR.markInteresting(Sym);
485 
486   // We are reporting a leak.  Walk up the graph to get to the first node where
487   // the symbol appeared, and also get the first VarDecl that tracked object
488   // is stored to.
489   AllocationInfo AllocI = GetAllocationSite(BRC.getStateManager(), EndN, Sym);
490 
491   const MemRegion* FirstBinding = AllocI.R;
492   BR.markInteresting(AllocI.InterestingMethodContext);
493 
494   SourceManager& SM = BRC.getSourceManager();
495 
496   // Compute an actual location for the leak.  Sometimes a leak doesn't
497   // occur at an actual statement (e.g., transition between blocks; end
498   // of function) so we need to walk the graph and compute a real location.
499   const ExplodedNode *LeakN = EndN;
500   PathDiagnosticLocation L = PathDiagnosticLocation::createEndOfPath(LeakN, SM);
501 
502   std::string sbuf;
503   llvm::raw_string_ostream os(sbuf);
504 
505   os << "Object leaked: ";
506 
507   Optional<std::string> RegionDescription = describeRegion(FirstBinding);
508   if (RegionDescription) {
509     os << "object allocated and stored into '" << *RegionDescription << '\'';
510   } else {
511     os << "allocated object of type " << getPrettyTypeName(Sym->getType());
512   }
513 
514   // Get the retain count.
515   const RefVal* RV = getRefBinding(EndN->getState(), Sym);
516   assert(RV);
517 
518   if (RV->getKind() == RefVal::ErrorLeakReturned) {
519     // FIXME: Per comments in rdar://6320065, "create" only applies to CF
520     // objects.  Only "copy", "alloc", "retain" and "new" transfer ownership
521     // to the caller for NS objects.
522     const Decl *D = &EndN->getCodeDecl();
523 
524     os << (isa<ObjCMethodDecl>(D) ? " is returned from a method "
525                                   : " is returned from a function ");
526 
527     if (D->hasAttr<CFReturnsNotRetainedAttr>()) {
528       os << "that is annotated as CF_RETURNS_NOT_RETAINED";
529     } else if (D->hasAttr<NSReturnsNotRetainedAttr>()) {
530       os << "that is annotated as NS_RETURNS_NOT_RETAINED";
531     } else if (D->hasAttr<OSReturnsNotRetainedAttr>()) {
532       os << "that is annotated as OS_RETURNS_NOT_RETAINED";
533     } else {
534       if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) {
535         if (BRC.getASTContext().getLangOpts().ObjCAutoRefCount) {
536           os << "managed by Automatic Reference Counting";
537         } else {
538           os << "whose name ('" << MD->getSelector().getAsString()
539              << "') does not start with "
540                 "'copy', 'mutableCopy', 'alloc' or 'new'."
541                 "  This violates the naming convention rules"
542                 " given in the Memory Management Guide for Cocoa";
543         }
544       } else {
545         const FunctionDecl *FD = cast<FunctionDecl>(D);
546         os << "whose name ('" << *FD
547            << "') does not contain 'Copy' or 'Create'.  This violates the naming"
548               " convention rules given in the Memory Management Guide for Core"
549               " Foundation";
550       }
551     }
552   } else {
553     os << " is not referenced later in this execution path and has a retain "
554           "count of +" << RV->getCount();
555   }
556 
557   return std::make_shared<PathDiagnosticEventPiece>(L, os.str());
558 }
559 
560 CFRefReport::CFRefReport(CFRefBug &D, const LangOptions &LOpts,
561                          const SummaryLogTy &Log, ExplodedNode *n,
562                          SymbolRef sym, bool registerVisitor)
563     : BugReport(D, D.getDescription(), n), Sym(sym) {
564   if (registerVisitor)
565     addVisitor(llvm::make_unique<CFRefReportVisitor>(sym, Log));
566 }
567 
568 CFRefReport::CFRefReport(CFRefBug &D, const LangOptions &LOpts,
569                          const SummaryLogTy &Log, ExplodedNode *n,
570                          SymbolRef sym, StringRef endText)
571     : BugReport(D, D.getDescription(), endText, n) {
572 
573   addVisitor(llvm::make_unique<CFRefReportVisitor>(sym, Log));
574 }
575 
576 void CFRefLeakReport::deriveParamLocation(CheckerContext &Ctx, SymbolRef sym) {
577   const SourceManager& SMgr = Ctx.getSourceManager();
578 
579   if (!sym->getOriginRegion())
580     return;
581 
582   auto *Region = dyn_cast<DeclRegion>(sym->getOriginRegion());
583   if (Region) {
584     const Decl *PDecl = Region->getDecl();
585     if (PDecl && isa<ParmVarDecl>(PDecl)) {
586       PathDiagnosticLocation ParamLocation = PathDiagnosticLocation::create(PDecl, SMgr);
587       Location = ParamLocation;
588       UniqueingLocation = ParamLocation;
589       UniqueingDecl = Ctx.getLocationContext()->getDecl();
590     }
591   }
592 }
593 
594 void CFRefLeakReport::deriveAllocLocation(CheckerContext &Ctx,
595                                           SymbolRef sym) {
596   // Most bug reports are cached at the location where they occurred.
597   // With leaks, we want to unique them by the location where they were
598   // allocated, and only report a single path.  To do this, we need to find
599   // the allocation site of a piece of tracked memory, which we do via a
600   // call to GetAllocationSite.  This will walk the ExplodedGraph backwards.
601   // Note that this is *not* the trimmed graph; we are guaranteed, however,
602   // that all ancestor nodes that represent the allocation site have the
603   // same SourceLocation.
604   const ExplodedNode *AllocNode = nullptr;
605 
606   const SourceManager& SMgr = Ctx.getSourceManager();
607 
608   AllocationInfo AllocI =
609       GetAllocationSite(Ctx.getStateManager(), getErrorNode(), sym);
610 
611   AllocNode = AllocI.N;
612   AllocBinding = AllocI.R;
613   markInteresting(AllocI.InterestingMethodContext);
614 
615   // Get the SourceLocation for the allocation site.
616   // FIXME: This will crash the analyzer if an allocation comes from an
617   // implicit call (ex: a destructor call).
618   // (Currently there are no such allocations in Cocoa, though.)
619   AllocStmt = PathDiagnosticLocation::getStmt(AllocNode);
620 
621   if (!AllocStmt) {
622     AllocBinding = nullptr;
623     return;
624   }
625 
626   PathDiagnosticLocation AllocLocation =
627     PathDiagnosticLocation::createBegin(AllocStmt, SMgr,
628                                         AllocNode->getLocationContext());
629   Location = AllocLocation;
630 
631   // Set uniqieing info, which will be used for unique the bug reports. The
632   // leaks should be uniqued on the allocation site.
633   UniqueingLocation = AllocLocation;
634   UniqueingDecl = AllocNode->getLocationContext()->getDecl();
635 }
636 
637 void CFRefLeakReport::createDescription(CheckerContext &Ctx) {
638   assert(Location.isValid() && UniqueingDecl && UniqueingLocation.isValid());
639   Description.clear();
640   llvm::raw_string_ostream os(Description);
641   os << "Potential leak of an object";
642 
643   Optional<std::string> RegionDescription = describeRegion(AllocBinding);
644   if (RegionDescription) {
645     os << " stored into '" << *RegionDescription << '\'';
646   } else {
647 
648     // If we can't figure out the name, just supply the type information.
649     os << " of type " << getPrettyTypeName(Sym->getType());
650   }
651 }
652 
653 CFRefLeakReport::CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
654                                  const SummaryLogTy &Log,
655                                  ExplodedNode *n, SymbolRef sym,
656                                  CheckerContext &Ctx)
657   : CFRefReport(D, LOpts, Log, n, sym, false) {
658 
659   deriveAllocLocation(Ctx, sym);
660   if (!AllocBinding)
661     deriveParamLocation(Ctx, sym);
662 
663   createDescription(Ctx);
664 
665   addVisitor(llvm::make_unique<CFRefLeakReportVisitor>(sym, Log));
666 }
667