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