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 bool DeallocSent) { 47 // Get the previous type state. 48 RefVal PrevV = *PrevT; 49 50 // Specially handle -dealloc. 51 if (DeallocSent) { 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 /// Finds argument index of the out paramter in the call {@code S} 117 /// corresponding to the symbol {@code Sym}. 118 /// If none found, returns None. 119 static Optional<unsigned> findArgIdxOfSymbol(ProgramStateRef CurrSt, 120 const LocationContext *LCtx, 121 SymbolRef &Sym, 122 Optional<CallEventRef<>> CE) { 123 if (!CE) 124 return None; 125 126 for (unsigned Idx = 0; Idx < (*CE)->getNumArgs(); Idx++) 127 if (const MemRegion *MR = (*CE)->getArgSVal(Idx).getAsRegion()) 128 if (const auto *TR = dyn_cast<TypedValueRegion>(MR)) 129 if (CurrSt->getSVal(MR, TR->getValueType()).getAsSymExpr() == Sym) 130 return Idx; 131 132 return None; 133 } 134 135 static void generateDiagnosticsForCallLike(ProgramStateRef CurrSt, 136 const LocationContext *LCtx, 137 const RefVal &CurrV, SymbolRef &Sym, 138 const Stmt *S, 139 llvm::raw_string_ostream &os) { 140 CallEventManager &Mgr = CurrSt->getStateManager().getCallEventManager(); 141 if (const CallExpr *CE = dyn_cast<CallExpr>(S)) { 142 // Get the name of the callee (if it is available) 143 // from the tracked SVal. 144 SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx); 145 const FunctionDecl *FD = X.getAsFunctionDecl(); 146 147 // If failed, try to get it from AST. 148 if (!FD) 149 FD = dyn_cast<FunctionDecl>(CE->getCalleeDecl()); 150 151 if (const auto *MD = dyn_cast<CXXMethodDecl>(CE->getCalleeDecl())) { 152 os << "Call to method '" << MD->getQualifiedNameAsString() << '\''; 153 } else if (FD) { 154 os << "Call to function '" << FD->getQualifiedNameAsString() << '\''; 155 } else { 156 os << "function call"; 157 } 158 } else if (isa<CXXNewExpr>(S)) { 159 os << "Operator 'new'"; 160 } else { 161 assert(isa<ObjCMessageExpr>(S)); 162 CallEventRef<ObjCMethodCall> Call = 163 Mgr.getObjCMethodCall(cast<ObjCMessageExpr>(S), CurrSt, LCtx); 164 165 switch (Call->getMessageKind()) { 166 case OCM_Message: 167 os << "Method"; 168 break; 169 case OCM_PropertyAccess: 170 os << "Property"; 171 break; 172 case OCM_Subscript: 173 os << "Subscript"; 174 break; 175 } 176 } 177 178 Optional<CallEventRef<>> CE = Mgr.getCall(S, CurrSt, LCtx); 179 auto Idx = findArgIdxOfSymbol(CurrSt, LCtx, Sym, CE); 180 181 // If index is not found, we assume that the symbol was returned. 182 if (!Idx) { 183 os << " returns "; 184 } else { 185 os << " writes "; 186 } 187 188 if (CurrV.getObjKind() == ObjKind::CF) { 189 os << "a Core Foundation object of type '" 190 << Sym->getType().getAsString() << "' with a "; 191 } else if (CurrV.getObjKind() == ObjKind::OS) { 192 os << "an OSObject of type '" << getPrettyTypeName(Sym->getType()) 193 << "' with a "; 194 } else if (CurrV.getObjKind() == ObjKind::Generalized) { 195 os << "an object of type '" << Sym->getType().getAsString() 196 << "' with a "; 197 } else { 198 assert(CurrV.getObjKind() == ObjKind::ObjC); 199 QualType T = Sym->getType(); 200 if (!isa<ObjCObjectPointerType>(T)) { 201 os << "an Objective-C object with a "; 202 } else { 203 const ObjCObjectPointerType *PT = cast<ObjCObjectPointerType>(T); 204 os << "an instance of " << PT->getPointeeType().getAsString() 205 << " with a "; 206 } 207 } 208 209 if (CurrV.isOwned()) { 210 os << "+1 retain count"; 211 } else { 212 assert(CurrV.isNotOwned()); 213 os << "+0 retain count"; 214 } 215 216 if (Idx) { 217 os << " into an out parameter '"; 218 const ParmVarDecl *PVD = (*CE)->parameters()[*Idx]; 219 PVD->getNameForDiagnostic(os, PVD->getASTContext().getPrintingPolicy(), 220 /*Qualified=*/false); 221 os << "'"; 222 223 QualType RT = (*CE)->getResultType(); 224 if (!RT.isNull() && !RT->isVoidType()) { 225 SVal RV = (*CE)->getReturnValue(); 226 if (CurrSt->isNull(RV).isConstrainedTrue()) { 227 os << " (assuming the call returns zero)"; 228 } else if (CurrSt->isNonNull(RV).isConstrainedTrue()) { 229 os << " (assuming the call returns non-zero)"; 230 } 231 232 } 233 } 234 } 235 236 namespace clang { 237 namespace ento { 238 namespace retaincountchecker { 239 240 class RefCountReportVisitor : public BugReporterVisitor { 241 protected: 242 SymbolRef Sym; 243 244 public: 245 RefCountReportVisitor(SymbolRef sym) : Sym(sym) {} 246 247 void Profile(llvm::FoldingSetNodeID &ID) const override { 248 static int x = 0; 249 ID.AddPointer(&x); 250 ID.AddPointer(Sym); 251 } 252 253 std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N, 254 BugReporterContext &BRC, 255 BugReport &BR) override; 256 257 std::shared_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC, 258 const ExplodedNode *N, 259 BugReport &BR) override; 260 }; 261 262 class RefLeakReportVisitor : public RefCountReportVisitor { 263 public: 264 RefLeakReportVisitor(SymbolRef sym) : RefCountReportVisitor(sym) {} 265 266 std::shared_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC, 267 const ExplodedNode *N, 268 BugReport &BR) override; 269 }; 270 271 } // end namespace retaincountchecker 272 } // end namespace ento 273 } // end namespace clang 274 275 276 /// Find the first node with the parent stack frame. 277 static const ExplodedNode *getCalleeNode(const ExplodedNode *Pred) { 278 const StackFrameContext *SC = Pred->getStackFrame(); 279 if (SC->inTopFrame()) 280 return nullptr; 281 const StackFrameContext *PC = SC->getParent()->getStackFrame(); 282 if (!PC) 283 return nullptr; 284 285 const ExplodedNode *N = Pred; 286 while (N && N->getStackFrame() != PC) { 287 N = N->getFirstPred(); 288 } 289 return N; 290 } 291 292 293 /// Insert a diagnostic piece at function exit 294 /// if a function parameter is annotated as "os_consumed", 295 /// but it does not actually consume the reference. 296 static std::shared_ptr<PathDiagnosticEventPiece> 297 annotateConsumedSummaryMismatch(const ExplodedNode *N, 298 CallExitBegin &CallExitLoc, 299 const SourceManager &SM, 300 CallEventManager &CEMgr) { 301 302 const ExplodedNode *CN = getCalleeNode(N); 303 if (!CN) 304 return nullptr; 305 306 CallEventRef<> Call = CEMgr.getCaller(N->getStackFrame(), N->getState()); 307 308 std::string sbuf; 309 llvm::raw_string_ostream os(sbuf); 310 ArrayRef<const ParmVarDecl *> Parameters = Call->parameters(); 311 for (unsigned I=0; I < Call->getNumArgs() && I < Parameters.size(); ++I) { 312 const ParmVarDecl *PVD = Parameters[I]; 313 314 if (!PVD->hasAttr<OSConsumedAttr>()) 315 continue; 316 317 if (SymbolRef SR = Call->getArgSVal(I).getAsLocSymbol()) { 318 const RefVal *CountBeforeCall = getRefBinding(CN->getState(), SR); 319 const RefVal *CountAtExit = getRefBinding(N->getState(), SR); 320 321 if (!CountBeforeCall || !CountAtExit) 322 continue; 323 324 unsigned CountBefore = CountBeforeCall->getCount(); 325 unsigned CountAfter = CountAtExit->getCount(); 326 327 bool AsExpected = CountBefore > 0 && CountAfter == CountBefore - 1; 328 if (!AsExpected) { 329 os << "Parameter '"; 330 PVD->getNameForDiagnostic(os, PVD->getASTContext().getPrintingPolicy(), 331 /*Qualified=*/false); 332 os << "' is marked as consuming, but the function did not consume " 333 << "the reference\n"; 334 } 335 } 336 } 337 338 if (os.str().empty()) 339 return nullptr; 340 341 // FIXME: remove the code duplication with NoStoreFuncVisitor. 342 PathDiagnosticLocation L; 343 if (const ReturnStmt *RS = CallExitLoc.getReturnStmt()) { 344 L = PathDiagnosticLocation::createBegin(RS, SM, N->getLocationContext()); 345 } else { 346 L = PathDiagnosticLocation( 347 Call->getRuntimeDefinition().getDecl()->getSourceRange().getEnd(), SM); 348 } 349 350 return std::make_shared<PathDiagnosticEventPiece>(L, os.str()); 351 } 352 353 std::shared_ptr<PathDiagnosticPiece> 354 RefCountReportVisitor::VisitNode(const ExplodedNode *N, 355 BugReporterContext &BRC, BugReport &BR) { 356 357 const SourceManager &SM = BRC.getSourceManager(); 358 CallEventManager &CEMgr = BRC.getStateManager().getCallEventManager(); 359 if (auto CE = N->getLocationAs<CallExitBegin>()) 360 if (auto PD = annotateConsumedSummaryMismatch(N, *CE, SM, CEMgr)) 361 return PD; 362 363 // FIXME: We will eventually need to handle non-statement-based events 364 // (__attribute__((cleanup))). 365 if (!N->getLocation().getAs<StmtPoint>()) 366 return nullptr; 367 368 // Check if the type state has changed. 369 const ExplodedNode *PrevNode = N->getFirstPred(); 370 ProgramStateRef PrevSt = PrevNode->getState(); 371 ProgramStateRef CurrSt = N->getState(); 372 const LocationContext *LCtx = N->getLocationContext(); 373 374 const RefVal* CurrT = getRefBinding(CurrSt, Sym); 375 if (!CurrT) return nullptr; 376 377 const RefVal &CurrV = *CurrT; 378 const RefVal *PrevT = getRefBinding(PrevSt, Sym); 379 380 // Create a string buffer to constain all the useful things we want 381 // to tell the user. 382 std::string sbuf; 383 llvm::raw_string_ostream os(sbuf); 384 385 // This is the allocation site since the previous node had no bindings 386 // for this symbol. 387 if (!PrevT) { 388 const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt(); 389 390 if (isa<ObjCIvarRefExpr>(S) && 391 isSynthesizedAccessor(LCtx->getStackFrame())) { 392 S = LCtx->getStackFrame()->getCallSite(); 393 } 394 395 if (isa<ObjCArrayLiteral>(S)) { 396 os << "NSArray literal is an object with a +0 retain count"; 397 } else if (isa<ObjCDictionaryLiteral>(S)) { 398 os << "NSDictionary literal is an object with a +0 retain count"; 399 } else if (const ObjCBoxedExpr *BL = dyn_cast<ObjCBoxedExpr>(S)) { 400 if (isNumericLiteralExpression(BL->getSubExpr())) 401 os << "NSNumber literal is an object with a +0 retain count"; 402 else { 403 const ObjCInterfaceDecl *BoxClass = nullptr; 404 if (const ObjCMethodDecl *Method = BL->getBoxingMethod()) 405 BoxClass = Method->getClassInterface(); 406 407 // We should always be able to find the boxing class interface, 408 // but consider this future-proofing. 409 if (BoxClass) { 410 os << *BoxClass << " b"; 411 } else { 412 os << "B"; 413 } 414 415 os << "oxed expression produces an object with a +0 retain count"; 416 } 417 } else if (isa<ObjCIvarRefExpr>(S)) { 418 os << "Object loaded from instance variable"; 419 } else { 420 generateDiagnosticsForCallLike(CurrSt, LCtx, CurrV, Sym, S, os); 421 } 422 423 PathDiagnosticLocation Pos(S, SM, N->getLocationContext()); 424 return std::make_shared<PathDiagnosticEventPiece>(Pos, os.str()); 425 } 426 427 // Gather up the effects that were performed on the object at this 428 // program point 429 bool DeallocSent = false; 430 431 if (N->getLocation().getTag() && 432 N->getLocation().getTag()->getTagDescription().contains( 433 RetainCountChecker::DeallocTagDescription)) { 434 // We only have summaries attached to nodes after evaluating CallExpr and 435 // ObjCMessageExprs. 436 const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt(); 437 438 if (const CallExpr *CE = dyn_cast<CallExpr>(S)) { 439 // Iterate through the parameter expressions and see if the symbol 440 // was ever passed as an argument. 441 unsigned i = 0; 442 443 for (auto AI=CE->arg_begin(), AE=CE->arg_end(); AI!=AE; ++AI, ++i) { 444 445 // Retrieve the value of the argument. Is it the symbol 446 // we are interested in? 447 if (CurrSt->getSValAsScalarOrLoc(*AI, LCtx).getAsLocSymbol() != Sym) 448 continue; 449 450 // We have an argument. Get the effect! 451 DeallocSent = true; 452 } 453 } else if (const ObjCMessageExpr *ME = dyn_cast<ObjCMessageExpr>(S)) { 454 if (const Expr *receiver = ME->getInstanceReceiver()) { 455 if (CurrSt->getSValAsScalarOrLoc(receiver, LCtx) 456 .getAsLocSymbol() == Sym) { 457 // The symbol we are tracking is the receiver. 458 DeallocSent = true; 459 } 460 } 461 } 462 } 463 464 if (!shouldGenerateNote(os, PrevT, CurrV, DeallocSent)) 465 return nullptr; 466 467 if (os.str().empty()) 468 return nullptr; // We have nothing to say! 469 470 const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt(); 471 PathDiagnosticLocation Pos(S, BRC.getSourceManager(), 472 N->getLocationContext()); 473 auto P = std::make_shared<PathDiagnosticEventPiece>(Pos, os.str()); 474 475 // Add the range by scanning the children of the statement for any bindings 476 // to Sym. 477 for (const Stmt *Child : S->children()) 478 if (const Expr *Exp = dyn_cast_or_null<Expr>(Child)) 479 if (CurrSt->getSValAsScalarOrLoc(Exp, LCtx).getAsLocSymbol() == Sym) { 480 P->addRange(Exp->getSourceRange()); 481 break; 482 } 483 484 return std::move(P); 485 } 486 487 static Optional<std::string> describeRegion(const MemRegion *MR) { 488 if (const auto *VR = dyn_cast_or_null<VarRegion>(MR)) 489 return std::string(VR->getDecl()->getName()); 490 // Once we support more storage locations for bindings, 491 // this would need to be improved. 492 return None; 493 } 494 495 namespace { 496 // Find the first node in the current function context that referred to the 497 // tracked symbol and the memory location that value was stored to. Note, the 498 // value is only reported if the allocation occurred in the same function as 499 // the leak. The function can also return a location context, which should be 500 // treated as interesting. 501 struct AllocationInfo { 502 const ExplodedNode* N; 503 const MemRegion *R; 504 const LocationContext *InterestingMethodContext; 505 AllocationInfo(const ExplodedNode *InN, 506 const MemRegion *InR, 507 const LocationContext *InInterestingMethodContext) : 508 N(InN), R(InR), InterestingMethodContext(InInterestingMethodContext) {} 509 }; 510 } // end anonymous namespace 511 512 static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr, 513 const ExplodedNode *N, SymbolRef Sym) { 514 const ExplodedNode *AllocationNode = N; 515 const ExplodedNode *AllocationNodeInCurrentOrParentContext = N; 516 const MemRegion *FirstBinding = nullptr; 517 const LocationContext *LeakContext = N->getLocationContext(); 518 519 // The location context of the init method called on the leaked object, if 520 // available. 521 const LocationContext *InitMethodContext = nullptr; 522 523 while (N) { 524 ProgramStateRef St = N->getState(); 525 const LocationContext *NContext = N->getLocationContext(); 526 527 if (!getRefBinding(St, Sym)) 528 break; 529 530 StoreManager::FindUniqueBinding FB(Sym); 531 StateMgr.iterBindings(St, FB); 532 533 if (FB) { 534 const MemRegion *R = FB.getRegion(); 535 // Do not show local variables belonging to a function other than 536 // where the error is reported. 537 if (auto MR = dyn_cast<StackSpaceRegion>(R->getMemorySpace())) 538 if (MR->getStackFrame() == LeakContext->getStackFrame()) 539 FirstBinding = R; 540 } 541 542 // AllocationNode is the last node in which the symbol was tracked. 543 AllocationNode = N; 544 545 // AllocationNodeInCurrentContext, is the last node in the current or 546 // parent context in which the symbol was tracked. 547 // 548 // Note that the allocation site might be in the parent context. For example, 549 // the case where an allocation happens in a block that captures a reference 550 // to it and that reference is overwritten/dropped by another call to 551 // the block. 552 if (NContext == LeakContext || NContext->isParentOf(LeakContext)) 553 AllocationNodeInCurrentOrParentContext = N; 554 555 // Find the last init that was called on the given symbol and store the 556 // init method's location context. 557 if (!InitMethodContext) 558 if (auto CEP = N->getLocation().getAs<CallEnter>()) { 559 const Stmt *CE = CEP->getCallExpr(); 560 if (const auto *ME = dyn_cast_or_null<ObjCMessageExpr>(CE)) { 561 const Stmt *RecExpr = ME->getInstanceReceiver(); 562 if (RecExpr) { 563 SVal RecV = St->getSVal(RecExpr, NContext); 564 if (ME->getMethodFamily() == OMF_init && RecV.getAsSymbol() == Sym) 565 InitMethodContext = CEP->getCalleeContext(); 566 } 567 } 568 } 569 570 N = N->getFirstPred(); 571 } 572 573 // If we are reporting a leak of the object that was allocated with alloc, 574 // mark its init method as interesting. 575 const LocationContext *InterestingMethodContext = nullptr; 576 if (InitMethodContext) { 577 const ProgramPoint AllocPP = AllocationNode->getLocation(); 578 if (Optional<StmtPoint> SP = AllocPP.getAs<StmtPoint>()) 579 if (const ObjCMessageExpr *ME = SP->getStmtAs<ObjCMessageExpr>()) 580 if (ME->getMethodFamily() == OMF_alloc) 581 InterestingMethodContext = InitMethodContext; 582 } 583 584 // If allocation happened in a function different from the leak node context, 585 // do not report the binding. 586 assert(N && "Could not find allocation node"); 587 588 if (AllocationNodeInCurrentOrParentContext && 589 AllocationNodeInCurrentOrParentContext->getLocationContext() != 590 LeakContext) 591 FirstBinding = nullptr; 592 593 return AllocationInfo(AllocationNodeInCurrentOrParentContext, 594 FirstBinding, 595 InterestingMethodContext); 596 } 597 598 std::shared_ptr<PathDiagnosticPiece> 599 RefCountReportVisitor::getEndPath(BugReporterContext &BRC, 600 const ExplodedNode *EndN, BugReport &BR) { 601 BR.markInteresting(Sym); 602 return BugReporterVisitor::getDefaultEndPath(BRC, EndN, BR); 603 } 604 605 std::shared_ptr<PathDiagnosticPiece> 606 RefLeakReportVisitor::getEndPath(BugReporterContext &BRC, 607 const ExplodedNode *EndN, BugReport &BR) { 608 609 // Tell the BugReporterContext to report cases when the tracked symbol is 610 // assigned to different variables, etc. 611 BR.markInteresting(Sym); 612 613 // We are reporting a leak. Walk up the graph to get to the first node where 614 // the symbol appeared, and also get the first VarDecl that tracked object 615 // is stored to. 616 AllocationInfo AllocI = GetAllocationSite(BRC.getStateManager(), EndN, Sym); 617 618 const MemRegion* FirstBinding = AllocI.R; 619 BR.markInteresting(AllocI.InterestingMethodContext); 620 621 SourceManager& SM = BRC.getSourceManager(); 622 623 // Compute an actual location for the leak. Sometimes a leak doesn't 624 // occur at an actual statement (e.g., transition between blocks; end 625 // of function) so we need to walk the graph and compute a real location. 626 const ExplodedNode *LeakN = EndN; 627 PathDiagnosticLocation L = PathDiagnosticLocation::createEndOfPath(LeakN, SM); 628 629 std::string sbuf; 630 llvm::raw_string_ostream os(sbuf); 631 632 os << "Object leaked: "; 633 634 Optional<std::string> RegionDescription = describeRegion(FirstBinding); 635 if (RegionDescription) { 636 os << "object allocated and stored into '" << *RegionDescription << '\''; 637 } else { 638 os << "allocated object of type '" << getPrettyTypeName(Sym->getType()) 639 << "'"; 640 } 641 642 // Get the retain count. 643 const RefVal* RV = getRefBinding(EndN->getState(), Sym); 644 assert(RV); 645 646 if (RV->getKind() == RefVal::ErrorLeakReturned) { 647 // FIXME: Per comments in rdar://6320065, "create" only applies to CF 648 // objects. Only "copy", "alloc", "retain" and "new" transfer ownership 649 // to the caller for NS objects. 650 const Decl *D = &EndN->getCodeDecl(); 651 652 os << (isa<ObjCMethodDecl>(D) ? " is returned from a method " 653 : " is returned from a function "); 654 655 if (D->hasAttr<CFReturnsNotRetainedAttr>()) { 656 os << "that is annotated as CF_RETURNS_NOT_RETAINED"; 657 } else if (D->hasAttr<NSReturnsNotRetainedAttr>()) { 658 os << "that is annotated as NS_RETURNS_NOT_RETAINED"; 659 } else if (D->hasAttr<OSReturnsNotRetainedAttr>()) { 660 os << "that is annotated as OS_RETURNS_NOT_RETAINED"; 661 } else { 662 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { 663 if (BRC.getASTContext().getLangOpts().ObjCAutoRefCount) { 664 os << "managed by Automatic Reference Counting"; 665 } else { 666 os << "whose name ('" << MD->getSelector().getAsString() 667 << "') does not start with " 668 "'copy', 'mutableCopy', 'alloc' or 'new'." 669 " This violates the naming convention rules" 670 " given in the Memory Management Guide for Cocoa"; 671 } 672 } else { 673 const FunctionDecl *FD = cast<FunctionDecl>(D); 674 os << "whose name ('" << *FD 675 << "') does not contain 'Copy' or 'Create'. This violates the naming" 676 " convention rules given in the Memory Management Guide for Core" 677 " Foundation"; 678 } 679 } 680 } else { 681 os << " is not referenced later in this execution path and has a retain " 682 "count of +" << RV->getCount(); 683 } 684 685 return std::make_shared<PathDiagnosticEventPiece>(L, os.str()); 686 } 687 688 RefCountReport::RefCountReport(RefCountBug &D, const LangOptions &LOpts, 689 ExplodedNode *n, SymbolRef sym, 690 bool registerVisitor) 691 : BugReport(D, D.getDescription(), n), Sym(sym) { 692 if (registerVisitor) 693 addVisitor(llvm::make_unique<RefCountReportVisitor>(sym)); 694 } 695 696 RefCountReport::RefCountReport(RefCountBug &D, const LangOptions &LOpts, 697 ExplodedNode *n, SymbolRef sym, 698 StringRef endText) 699 : BugReport(D, D.getDescription(), endText, n) { 700 701 addVisitor(llvm::make_unique<RefCountReportVisitor>(sym)); 702 } 703 704 void RefLeakReport::deriveParamLocation(CheckerContext &Ctx, SymbolRef sym) { 705 const SourceManager& SMgr = Ctx.getSourceManager(); 706 707 if (!sym->getOriginRegion()) 708 return; 709 710 auto *Region = dyn_cast<DeclRegion>(sym->getOriginRegion()); 711 if (Region) { 712 const Decl *PDecl = Region->getDecl(); 713 if (PDecl && isa<ParmVarDecl>(PDecl)) { 714 PathDiagnosticLocation ParamLocation = 715 PathDiagnosticLocation::create(PDecl, SMgr); 716 Location = ParamLocation; 717 UniqueingLocation = ParamLocation; 718 UniqueingDecl = Ctx.getLocationContext()->getDecl(); 719 } 720 } 721 } 722 723 void RefLeakReport::deriveAllocLocation(CheckerContext &Ctx, 724 SymbolRef sym) { 725 // Most bug reports are cached at the location where they occurred. 726 // With leaks, we want to unique them by the location where they were 727 // allocated, and only report a single path. To do this, we need to find 728 // the allocation site of a piece of tracked memory, which we do via a 729 // call to GetAllocationSite. This will walk the ExplodedGraph backwards. 730 // Note that this is *not* the trimmed graph; we are guaranteed, however, 731 // that all ancestor nodes that represent the allocation site have the 732 // same SourceLocation. 733 const ExplodedNode *AllocNode = nullptr; 734 735 const SourceManager& SMgr = Ctx.getSourceManager(); 736 737 AllocationInfo AllocI = 738 GetAllocationSite(Ctx.getStateManager(), getErrorNode(), sym); 739 740 AllocNode = AllocI.N; 741 AllocBinding = AllocI.R; 742 markInteresting(AllocI.InterestingMethodContext); 743 744 // Get the SourceLocation for the allocation site. 745 // FIXME: This will crash the analyzer if an allocation comes from an 746 // implicit call (ex: a destructor call). 747 // (Currently there are no such allocations in Cocoa, though.) 748 AllocStmt = PathDiagnosticLocation::getStmt(AllocNode); 749 750 if (!AllocStmt) { 751 AllocBinding = nullptr; 752 return; 753 } 754 755 PathDiagnosticLocation AllocLocation = 756 PathDiagnosticLocation::createBegin(AllocStmt, SMgr, 757 AllocNode->getLocationContext()); 758 Location = AllocLocation; 759 760 // Set uniqieing info, which will be used for unique the bug reports. The 761 // leaks should be uniqued on the allocation site. 762 UniqueingLocation = AllocLocation; 763 UniqueingDecl = AllocNode->getLocationContext()->getDecl(); 764 } 765 766 void RefLeakReport::createDescription(CheckerContext &Ctx) { 767 assert(Location.isValid() && UniqueingDecl && UniqueingLocation.isValid()); 768 Description.clear(); 769 llvm::raw_string_ostream os(Description); 770 os << "Potential leak of an object"; 771 772 Optional<std::string> RegionDescription = describeRegion(AllocBinding); 773 if (RegionDescription) { 774 os << " stored into '" << *RegionDescription << '\''; 775 } else { 776 777 // If we can't figure out the name, just supply the type information. 778 os << " of type '" << getPrettyTypeName(Sym->getType()) << "'"; 779 } 780 } 781 782 RefLeakReport::RefLeakReport(RefCountBug &D, const LangOptions &LOpts, 783 ExplodedNode *n, SymbolRef sym, 784 CheckerContext &Ctx) 785 : RefCountReport(D, LOpts, n, sym, false) { 786 787 deriveAllocLocation(Ctx, sym); 788 if (!AllocBinding) 789 deriveParamLocation(Ctx, sym); 790 791 createDescription(Ctx); 792 793 addVisitor(llvm::make_unique<RefLeakReportVisitor>(sym)); 794 } 795