1 // RetainCountDiagnostics.cpp - Checks for leaks and other issues -*- C++ -*--// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file defines diagnostics for RetainCountChecker, which implements 10 // a reference count checker for Core Foundation and Cocoa on (Mac OS X). 11 // 12 //===----------------------------------------------------------------------===// 13 14 #include "RetainCountDiagnostics.h" 15 #include "RetainCountChecker.h" 16 #include "llvm/ADT/STLExtras.h" 17 #include "llvm/ADT/SmallVector.h" 18 #include <optional> 19 20 using namespace clang; 21 using namespace ento; 22 using namespace retaincountchecker; 23 24 StringRef RefCountBug::bugTypeToName(RefCountBug::RefCountBugKind BT) { 25 switch (BT) { 26 case UseAfterRelease: 27 return "Use-after-release"; 28 case ReleaseNotOwned: 29 return "Bad release"; 30 case DeallocNotOwned: 31 return "-dealloc sent to non-exclusively owned object"; 32 case FreeNotOwned: 33 return "freeing non-exclusively owned object"; 34 case OverAutorelease: 35 return "Object autoreleased too many times"; 36 case ReturnNotOwnedForOwned: 37 return "Method should return an owned object"; 38 case LeakWithinFunction: 39 return "Leak"; 40 case LeakAtReturn: 41 return "Leak of returned object"; 42 } 43 llvm_unreachable("Unknown RefCountBugKind"); 44 } 45 46 StringRef RefCountBug::getDescription() const { 47 switch (BT) { 48 case UseAfterRelease: 49 return "Reference-counted object is used after it is released"; 50 case ReleaseNotOwned: 51 return "Incorrect decrement of the reference count of an object that is " 52 "not owned at this point by the caller"; 53 case DeallocNotOwned: 54 return "-dealloc sent to object that may be referenced elsewhere"; 55 case FreeNotOwned: 56 return "'free' called on an object that may be referenced elsewhere"; 57 case OverAutorelease: 58 return "Object autoreleased too many times"; 59 case ReturnNotOwnedForOwned: 60 return "Object with a +0 retain count returned to caller where a +1 " 61 "(owning) retain count is expected"; 62 case LeakWithinFunction: 63 case LeakAtReturn: 64 return ""; 65 } 66 llvm_unreachable("Unknown RefCountBugKind"); 67 } 68 69 RefCountBug::RefCountBug(CheckerNameRef Checker, RefCountBugKind BT) 70 : BugType(Checker, bugTypeToName(BT), categories::MemoryRefCount, 71 /*SuppressOnSink=*/BT == LeakWithinFunction || 72 BT == LeakAtReturn), 73 BT(BT) {} 74 75 static bool isNumericLiteralExpression(const Expr *E) { 76 // FIXME: This set of cases was copied from SemaExprObjC. 77 return isa<IntegerLiteral, CharacterLiteral, FloatingLiteral, 78 ObjCBoolLiteralExpr, CXXBoolLiteralExpr>(E); 79 } 80 81 /// If type represents a pointer to CXXRecordDecl, 82 /// and is not a typedef, return the decl name. 83 /// Otherwise, return the serialization of type. 84 static std::string getPrettyTypeName(QualType QT) { 85 QualType PT = QT->getPointeeType(); 86 if (!PT.isNull() && !QT->getAs<TypedefType>()) 87 if (const auto *RD = PT->getAsCXXRecordDecl()) 88 return std::string(RD->getName()); 89 return QT.getAsString(); 90 } 91 92 /// Write information about the type state change to @c os, 93 /// return whether the note should be generated. 94 static bool shouldGenerateNote(llvm::raw_string_ostream &os, 95 const RefVal *PrevT, 96 const RefVal &CurrV, 97 bool DeallocSent) { 98 // Get the previous type state. 99 RefVal PrevV = *PrevT; 100 101 // Specially handle -dealloc. 102 if (DeallocSent) { 103 // Determine if the object's reference count was pushed to zero. 104 assert(!PrevV.hasSameState(CurrV) && "The state should have changed."); 105 // We may not have transitioned to 'release' if we hit an error. 106 // This case is handled elsewhere. 107 if (CurrV.getKind() == RefVal::Released) { 108 assert(CurrV.getCombinedCounts() == 0); 109 os << "Object released by directly sending the '-dealloc' message"; 110 return true; 111 } 112 } 113 114 // Determine if the typestate has changed. 115 if (!PrevV.hasSameState(CurrV)) 116 switch (CurrV.getKind()) { 117 case RefVal::Owned: 118 case RefVal::NotOwned: 119 if (PrevV.getCount() == CurrV.getCount()) { 120 // Did an autorelease message get sent? 121 if (PrevV.getAutoreleaseCount() == CurrV.getAutoreleaseCount()) 122 return false; 123 124 assert(PrevV.getAutoreleaseCount() < CurrV.getAutoreleaseCount()); 125 os << "Object autoreleased"; 126 return true; 127 } 128 129 if (PrevV.getCount() > CurrV.getCount()) 130 os << "Reference count decremented."; 131 else 132 os << "Reference count incremented."; 133 134 if (unsigned Count = CurrV.getCount()) 135 os << " The object now has a +" << Count << " retain count."; 136 137 return true; 138 139 case RefVal::Released: 140 if (CurrV.getIvarAccessHistory() == 141 RefVal::IvarAccessHistory::ReleasedAfterDirectAccess && 142 CurrV.getIvarAccessHistory() != PrevV.getIvarAccessHistory()) { 143 os << "Strong instance variable relinquished. "; 144 } 145 os << "Object released."; 146 return true; 147 148 case RefVal::ReturnedOwned: 149 // Autoreleases can be applied after marking a node ReturnedOwned. 150 if (CurrV.getAutoreleaseCount()) 151 return false; 152 153 os << "Object returned to caller as an owning reference (single " 154 "retain count transferred to caller)"; 155 return true; 156 157 case RefVal::ReturnedNotOwned: 158 os << "Object returned to caller with a +0 retain count"; 159 return true; 160 161 default: 162 return false; 163 } 164 return true; 165 } 166 167 /// Finds argument index of the out paramter in the call @c S 168 /// corresponding to the symbol @c Sym. 169 /// If none found, returns std::nullopt. 170 static std::optional<unsigned> findArgIdxOfSymbol(ProgramStateRef CurrSt, 171 const LocationContext *LCtx, 172 SymbolRef &Sym, 173 Optional<CallEventRef<>> CE) { 174 if (!CE) 175 return std::nullopt; 176 177 for (unsigned Idx = 0; Idx < (*CE)->getNumArgs(); Idx++) 178 if (const MemRegion *MR = (*CE)->getArgSVal(Idx).getAsRegion()) 179 if (const auto *TR = dyn_cast<TypedValueRegion>(MR)) 180 if (CurrSt->getSVal(MR, TR->getValueType()).getAsSymbol() == Sym) 181 return Idx; 182 183 return std::nullopt; 184 } 185 186 static std::optional<std::string> findMetaClassAlloc(const Expr *Callee) { 187 if (const auto *ME = dyn_cast<MemberExpr>(Callee)) { 188 if (ME->getMemberDecl()->getNameAsString() != "alloc") 189 return std::nullopt; 190 const Expr *This = ME->getBase()->IgnoreParenImpCasts(); 191 if (const auto *DRE = dyn_cast<DeclRefExpr>(This)) { 192 const ValueDecl *VD = DRE->getDecl(); 193 if (VD->getNameAsString() != "metaClass") 194 return std::nullopt; 195 196 if (const auto *RD = dyn_cast<CXXRecordDecl>(VD->getDeclContext())) 197 return RD->getNameAsString(); 198 199 } 200 } 201 return std::nullopt; 202 } 203 204 static std::string findAllocatedObjectName(const Stmt *S, QualType QT) { 205 if (const auto *CE = dyn_cast<CallExpr>(S)) 206 if (auto Out = findMetaClassAlloc(CE->getCallee())) 207 return *Out; 208 return getPrettyTypeName(QT); 209 } 210 211 static void generateDiagnosticsForCallLike(ProgramStateRef CurrSt, 212 const LocationContext *LCtx, 213 const RefVal &CurrV, SymbolRef &Sym, 214 const Stmt *S, 215 llvm::raw_string_ostream &os) { 216 CallEventManager &Mgr = CurrSt->getStateManager().getCallEventManager(); 217 if (const CallExpr *CE = dyn_cast<CallExpr>(S)) { 218 // Get the name of the callee (if it is available) 219 // from the tracked SVal. 220 SVal X = CurrSt->getSValAsScalarOrLoc(CE->getCallee(), LCtx); 221 const FunctionDecl *FD = X.getAsFunctionDecl(); 222 223 // If failed, try to get it from AST. 224 if (!FD) 225 FD = dyn_cast<FunctionDecl>(CE->getCalleeDecl()); 226 227 if (const auto *MD = dyn_cast<CXXMethodDecl>(CE->getCalleeDecl())) { 228 os << "Call to method '" << MD->getQualifiedNameAsString() << '\''; 229 } else if (FD) { 230 os << "Call to function '" << FD->getQualifiedNameAsString() << '\''; 231 } else { 232 os << "function call"; 233 } 234 } else if (isa<CXXNewExpr>(S)) { 235 os << "Operator 'new'"; 236 } else { 237 assert(isa<ObjCMessageExpr>(S)); 238 CallEventRef<ObjCMethodCall> Call = 239 Mgr.getObjCMethodCall(cast<ObjCMessageExpr>(S), CurrSt, LCtx); 240 241 switch (Call->getMessageKind()) { 242 case OCM_Message: 243 os << "Method"; 244 break; 245 case OCM_PropertyAccess: 246 os << "Property"; 247 break; 248 case OCM_Subscript: 249 os << "Subscript"; 250 break; 251 } 252 } 253 254 Optional<CallEventRef<>> CE = Mgr.getCall(S, CurrSt, LCtx); 255 auto Idx = findArgIdxOfSymbol(CurrSt, LCtx, Sym, CE); 256 257 // If index is not found, we assume that the symbol was returned. 258 if (!Idx) { 259 os << " returns "; 260 } else { 261 os << " writes "; 262 } 263 264 if (CurrV.getObjKind() == ObjKind::CF) { 265 os << "a Core Foundation object of type '" << Sym->getType() << "' with a "; 266 } else if (CurrV.getObjKind() == ObjKind::OS) { 267 os << "an OSObject of type '" << findAllocatedObjectName(S, Sym->getType()) 268 << "' with a "; 269 } else if (CurrV.getObjKind() == ObjKind::Generalized) { 270 os << "an object of type '" << Sym->getType() << "' with a "; 271 } else { 272 assert(CurrV.getObjKind() == ObjKind::ObjC); 273 QualType T = Sym->getType(); 274 if (!isa<ObjCObjectPointerType>(T)) { 275 os << "an Objective-C object with a "; 276 } else { 277 const ObjCObjectPointerType *PT = cast<ObjCObjectPointerType>(T); 278 os << "an instance of " << PT->getPointeeType() << " with a "; 279 } 280 } 281 282 if (CurrV.isOwned()) { 283 os << "+1 retain count"; 284 } else { 285 assert(CurrV.isNotOwned()); 286 os << "+0 retain count"; 287 } 288 289 if (Idx) { 290 os << " into an out parameter '"; 291 const ParmVarDecl *PVD = (*CE)->parameters()[*Idx]; 292 PVD->getNameForDiagnostic(os, PVD->getASTContext().getPrintingPolicy(), 293 /*Qualified=*/false); 294 os << "'"; 295 296 QualType RT = (*CE)->getResultType(); 297 if (!RT.isNull() && !RT->isVoidType()) { 298 SVal RV = (*CE)->getReturnValue(); 299 if (CurrSt->isNull(RV).isConstrainedTrue()) { 300 os << " (assuming the call returns zero)"; 301 } else if (CurrSt->isNonNull(RV).isConstrainedTrue()) { 302 os << " (assuming the call returns non-zero)"; 303 } 304 305 } 306 } 307 } 308 309 namespace clang { 310 namespace ento { 311 namespace retaincountchecker { 312 313 class RefCountReportVisitor : public BugReporterVisitor { 314 protected: 315 SymbolRef Sym; 316 317 public: 318 RefCountReportVisitor(SymbolRef sym) : Sym(sym) {} 319 320 void Profile(llvm::FoldingSetNodeID &ID) const override { 321 static int x = 0; 322 ID.AddPointer(&x); 323 ID.AddPointer(Sym); 324 } 325 326 PathDiagnosticPieceRef VisitNode(const ExplodedNode *N, 327 BugReporterContext &BRC, 328 PathSensitiveBugReport &BR) override; 329 330 PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC, 331 const ExplodedNode *N, 332 PathSensitiveBugReport &BR) override; 333 }; 334 335 class RefLeakReportVisitor : public RefCountReportVisitor { 336 public: 337 RefLeakReportVisitor(SymbolRef Sym, const MemRegion *LastBinding) 338 : RefCountReportVisitor(Sym), LastBinding(LastBinding) {} 339 340 PathDiagnosticPieceRef getEndPath(BugReporterContext &BRC, 341 const ExplodedNode *N, 342 PathSensitiveBugReport &BR) override; 343 344 private: 345 const MemRegion *LastBinding; 346 }; 347 348 } // end namespace retaincountchecker 349 } // end namespace ento 350 } // end namespace clang 351 352 353 /// Find the first node with the parent stack frame. 354 static const ExplodedNode *getCalleeNode(const ExplodedNode *Pred) { 355 const StackFrameContext *SC = Pred->getStackFrame(); 356 if (SC->inTopFrame()) 357 return nullptr; 358 const StackFrameContext *PC = SC->getParent()->getStackFrame(); 359 if (!PC) 360 return nullptr; 361 362 const ExplodedNode *N = Pred; 363 while (N && N->getStackFrame() != PC) { 364 N = N->getFirstPred(); 365 } 366 return N; 367 } 368 369 370 /// Insert a diagnostic piece at function exit 371 /// if a function parameter is annotated as "os_consumed", 372 /// but it does not actually consume the reference. 373 static std::shared_ptr<PathDiagnosticEventPiece> 374 annotateConsumedSummaryMismatch(const ExplodedNode *N, 375 CallExitBegin &CallExitLoc, 376 const SourceManager &SM, 377 CallEventManager &CEMgr) { 378 379 const ExplodedNode *CN = getCalleeNode(N); 380 if (!CN) 381 return nullptr; 382 383 CallEventRef<> Call = CEMgr.getCaller(N->getStackFrame(), N->getState()); 384 385 std::string sbuf; 386 llvm::raw_string_ostream os(sbuf); 387 ArrayRef<const ParmVarDecl *> Parameters = Call->parameters(); 388 for (unsigned I=0; I < Call->getNumArgs() && I < Parameters.size(); ++I) { 389 const ParmVarDecl *PVD = Parameters[I]; 390 391 if (!PVD->hasAttr<OSConsumedAttr>()) 392 continue; 393 394 if (SymbolRef SR = Call->getArgSVal(I).getAsLocSymbol()) { 395 const RefVal *CountBeforeCall = getRefBinding(CN->getState(), SR); 396 const RefVal *CountAtExit = getRefBinding(N->getState(), SR); 397 398 if (!CountBeforeCall || !CountAtExit) 399 continue; 400 401 unsigned CountBefore = CountBeforeCall->getCount(); 402 unsigned CountAfter = CountAtExit->getCount(); 403 404 bool AsExpected = CountBefore > 0 && CountAfter == CountBefore - 1; 405 if (!AsExpected) { 406 os << "Parameter '"; 407 PVD->getNameForDiagnostic(os, PVD->getASTContext().getPrintingPolicy(), 408 /*Qualified=*/false); 409 os << "' is marked as consuming, but the function did not consume " 410 << "the reference\n"; 411 } 412 } 413 } 414 415 if (os.str().empty()) 416 return nullptr; 417 418 PathDiagnosticLocation L = PathDiagnosticLocation::create(CallExitLoc, SM); 419 return std::make_shared<PathDiagnosticEventPiece>(L, os.str()); 420 } 421 422 /// Annotate the parameter at the analysis entry point. 423 static std::shared_ptr<PathDiagnosticEventPiece> 424 annotateStartParameter(const ExplodedNode *N, SymbolRef Sym, 425 const SourceManager &SM) { 426 auto PP = N->getLocationAs<BlockEdge>(); 427 if (!PP) 428 return nullptr; 429 430 const CFGBlock *Src = PP->getSrc(); 431 const RefVal *CurrT = getRefBinding(N->getState(), Sym); 432 433 if (&Src->getParent()->getEntry() != Src || !CurrT || 434 getRefBinding(N->getFirstPred()->getState(), Sym)) 435 return nullptr; 436 437 const auto *VR = cast<VarRegion>(cast<SymbolRegionValue>(Sym)->getRegion()); 438 const auto *PVD = cast<ParmVarDecl>(VR->getDecl()); 439 PathDiagnosticLocation L = PathDiagnosticLocation(PVD, SM); 440 441 std::string s; 442 llvm::raw_string_ostream os(s); 443 os << "Parameter '" << PVD->getDeclName() << "' starts at +"; 444 if (CurrT->getCount() == 1) { 445 os << "1, as it is marked as consuming"; 446 } else { 447 assert(CurrT->getCount() == 0); 448 os << "0"; 449 } 450 return std::make_shared<PathDiagnosticEventPiece>(L, os.str()); 451 } 452 453 PathDiagnosticPieceRef 454 RefCountReportVisitor::VisitNode(const ExplodedNode *N, BugReporterContext &BRC, 455 PathSensitiveBugReport &BR) { 456 457 const auto &BT = static_cast<const RefCountBug&>(BR.getBugType()); 458 459 bool IsFreeUnowned = BT.getBugType() == RefCountBug::FreeNotOwned || 460 BT.getBugType() == RefCountBug::DeallocNotOwned; 461 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)) 466 return PD; 467 468 if (auto PD = annotateStartParameter(N, Sym, SM)) 469 return PD; 470 471 // FIXME: We will eventually need to handle non-statement-based events 472 // (__attribute__((cleanup))). 473 if (!N->getLocation().getAs<StmtPoint>()) 474 return nullptr; 475 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(); 481 482 const RefVal* CurrT = getRefBinding(CurrSt, Sym); 483 if (!CurrT) 484 return nullptr; 485 486 const RefVal &CurrV = *CurrT; 487 const RefVal *PrevT = getRefBinding(PrevSt, Sym); 488 489 // Create a string buffer to constain all the useful things we want 490 // to tell the user. 491 std::string sbuf; 492 llvm::raw_string_ostream os(sbuf); 493 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()); 498 } 499 500 // This is the allocation site since the previous node had no bindings 501 // for this symbol. 502 if (!PrevT) { 503 const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt(); 504 505 if (isa<ObjCIvarRefExpr>(S) && 506 isSynthesizedAccessor(LCtx->getStackFrame())) { 507 S = LCtx->getStackFrame()->getCallSite(); 508 } 509 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"; 517 else { 518 const ObjCInterfaceDecl *BoxClass = nullptr; 519 if (const ObjCMethodDecl *Method = BL->getBoxingMethod()) 520 BoxClass = Method->getClassInterface(); 521 522 // We should always be able to find the boxing class interface, 523 // but consider this future-proofing. 524 if (BoxClass) { 525 os << *BoxClass << " b"; 526 } else { 527 os << "B"; 528 } 529 530 os << "oxed expression produces an object with a +0 retain count"; 531 } 532 } else if (isa<ObjCIvarRefExpr>(S)) { 533 os << "Object loaded from instance variable"; 534 } else { 535 generateDiagnosticsForCallLike(CurrSt, LCtx, CurrV, Sym, S, os); 536 } 537 538 PathDiagnosticLocation Pos(S, SM, N->getLocationContext()); 539 return std::make_shared<PathDiagnosticEventPiece>(Pos, os.str()); 540 } 541 542 // Gather up the effects that were performed on the object at this 543 // program point 544 bool DeallocSent = false; 545 546 const ProgramPointTag *Tag = N->getLocation().getTag(); 547 548 if (Tag == &RetainCountChecker::getCastFailTag()) { 549 os << "Assuming dynamic cast returns null due to type mismatch"; 550 } 551 552 if (Tag == &RetainCountChecker::getDeallocSentTag()) { 553 // We only have summaries attached to nodes after evaluating CallExpr and 554 // ObjCMessageExprs. 555 const Stmt *S = N->getLocation().castAs<StmtPoint>().getStmt(); 556 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. 560 unsigned i = 0; 561 562 for (auto AI=CE->arg_begin(), AE=CE->arg_end(); AI!=AE; ++AI, ++i) { 563 564 // Retrieve the value of the argument. Is it the symbol 565 // we are interested in? 566 if (CurrSt->getSValAsScalarOrLoc(*AI, LCtx).getAsLocSymbol() != Sym) 567 continue; 568 569 // We have an argument. Get the effect! 570 DeallocSent = true; 571 } 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. 577 DeallocSent = true; 578 } 579 } 580 } 581 } 582 583 if (!shouldGenerateNote(os, PrevT, CurrV, DeallocSent)) 584 return nullptr; 585 586 if (os.str().empty()) 587 return nullptr; // We have nothing to say! 588 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()); 593 594 // Add the range by scanning the children of the statement for any bindings 595 // to Sym. 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()); 600 break; 601 } 602 603 return std::move(P); 604 } 605 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. 611 return std::nullopt; 612 } 613 614 using Bindings = llvm::SmallVector<std::pair<const MemRegion *, SVal>, 4>; 615 616 class VarBindingsCollector : public StoreManager::BindingsHandler { 617 SymbolRef Sym; 618 Bindings &Result; 619 620 public: 621 VarBindingsCollector(SymbolRef Sym, Bindings &ToFill) 622 : Sym(Sym), Result(ToFill) {} 623 624 bool HandleBinding(StoreManager &SMgr, Store Store, const MemRegion *R, 625 SVal Val) override { 626 SymbolRef SymV = Val.getAsLocSymbol(); 627 if (!SymV || SymV != Sym) 628 return true; 629 630 if (isa<NonParamVarRegion>(R)) 631 Result.emplace_back(R, Val); 632 633 return true; 634 } 635 }; 636 637 Bindings getAllVarBindingsForSymbol(ProgramStateManager &Manager, 638 const ExplodedNode *Node, SymbolRef Sym) { 639 Bindings Result; 640 VarBindingsCollector Collector{Sym, Result}; 641 while (Result.empty() && Node) { 642 Manager.iterBindings(Node->getState(), Collector); 643 Node = Node->getFirstPred(); 644 } 645 646 return Result; 647 } 648 649 namespace { 650 // Find the first node in the current function context that referred to the 651 // tracked symbol and the memory location that value was stored to. Note, the 652 // value is only reported if the allocation occurred in the same function as 653 // the leak. The function can also return a location context, which should be 654 // treated as interesting. 655 struct AllocationInfo { 656 const ExplodedNode* N; 657 const MemRegion *R; 658 const LocationContext *InterestingMethodContext; 659 AllocationInfo(const ExplodedNode *InN, 660 const MemRegion *InR, 661 const LocationContext *InInterestingMethodContext) : 662 N(InN), R(InR), InterestingMethodContext(InInterestingMethodContext) {} 663 }; 664 } // end anonymous namespace 665 666 static AllocationInfo GetAllocationSite(ProgramStateManager &StateMgr, 667 const ExplodedNode *N, SymbolRef Sym) { 668 const ExplodedNode *AllocationNode = N; 669 const ExplodedNode *AllocationNodeInCurrentOrParentContext = N; 670 const MemRegion *FirstBinding = nullptr; 671 const LocationContext *LeakContext = N->getLocationContext(); 672 673 // The location context of the init method called on the leaked object, if 674 // available. 675 const LocationContext *InitMethodContext = nullptr; 676 677 while (N) { 678 ProgramStateRef St = N->getState(); 679 const LocationContext *NContext = N->getLocationContext(); 680 681 if (!getRefBinding(St, Sym)) 682 break; 683 684 StoreManager::FindUniqueBinding FB(Sym); 685 StateMgr.iterBindings(St, FB); 686 687 if (FB) { 688 const MemRegion *R = FB.getRegion(); 689 // Do not show local variables belonging to a function other than 690 // where the error is reported. 691 if (auto MR = dyn_cast<StackSpaceRegion>(R->getMemorySpace())) 692 if (MR->getStackFrame() == LeakContext->getStackFrame()) 693 FirstBinding = R; 694 } 695 696 // AllocationNode is the last node in which the symbol was tracked. 697 AllocationNode = N; 698 699 // AllocationNodeInCurrentContext, is the last node in the current or 700 // parent context in which the symbol was tracked. 701 // 702 // Note that the allocation site might be in the parent context. For example, 703 // the case where an allocation happens in a block that captures a reference 704 // to it and that reference is overwritten/dropped by another call to 705 // the block. 706 if (NContext == LeakContext || NContext->isParentOf(LeakContext)) 707 AllocationNodeInCurrentOrParentContext = N; 708 709 // Find the last init that was called on the given symbol and store the 710 // init method's location context. 711 if (!InitMethodContext) 712 if (auto CEP = N->getLocation().getAs<CallEnter>()) { 713 const Stmt *CE = CEP->getCallExpr(); 714 if (const auto *ME = dyn_cast_or_null<ObjCMessageExpr>(CE)) { 715 const Stmt *RecExpr = ME->getInstanceReceiver(); 716 if (RecExpr) { 717 SVal RecV = St->getSVal(RecExpr, NContext); 718 if (ME->getMethodFamily() == OMF_init && RecV.getAsSymbol() == Sym) 719 InitMethodContext = CEP->getCalleeContext(); 720 } 721 } 722 } 723 724 N = N->getFirstPred(); 725 } 726 727 // If we are reporting a leak of the object that was allocated with alloc, 728 // mark its init method as interesting. 729 const LocationContext *InterestingMethodContext = nullptr; 730 if (InitMethodContext) { 731 const ProgramPoint AllocPP = AllocationNode->getLocation(); 732 if (Optional<StmtPoint> SP = AllocPP.getAs<StmtPoint>()) 733 if (const ObjCMessageExpr *ME = SP->getStmtAs<ObjCMessageExpr>()) 734 if (ME->getMethodFamily() == OMF_alloc) 735 InterestingMethodContext = InitMethodContext; 736 } 737 738 // If allocation happened in a function different from the leak node context, 739 // do not report the binding. 740 assert(N && "Could not find allocation node"); 741 742 if (AllocationNodeInCurrentOrParentContext && 743 AllocationNodeInCurrentOrParentContext->getLocationContext() != 744 LeakContext) 745 FirstBinding = nullptr; 746 747 return AllocationInfo(AllocationNodeInCurrentOrParentContext, FirstBinding, 748 InterestingMethodContext); 749 } 750 751 PathDiagnosticPieceRef 752 RefCountReportVisitor::getEndPath(BugReporterContext &BRC, 753 const ExplodedNode *EndN, 754 PathSensitiveBugReport &BR) { 755 BR.markInteresting(Sym); 756 return BugReporterVisitor::getDefaultEndPath(BRC, EndN, BR); 757 } 758 759 PathDiagnosticPieceRef 760 RefLeakReportVisitor::getEndPath(BugReporterContext &BRC, 761 const ExplodedNode *EndN, 762 PathSensitiveBugReport &BR) { 763 764 // Tell the BugReporterContext to report cases when the tracked symbol is 765 // assigned to different variables, etc. 766 BR.markInteresting(Sym); 767 768 PathDiagnosticLocation L = cast<RefLeakReport>(BR).getEndOfPath(); 769 770 std::string sbuf; 771 llvm::raw_string_ostream os(sbuf); 772 773 os << "Object leaked: "; 774 775 Optional<std::string> RegionDescription = describeRegion(LastBinding); 776 if (RegionDescription) { 777 os << "object allocated and stored into '" << *RegionDescription << '\''; 778 } else { 779 os << "allocated object of type '" << getPrettyTypeName(Sym->getType()) 780 << "'"; 781 } 782 783 // Get the retain count. 784 const RefVal *RV = getRefBinding(EndN->getState(), Sym); 785 assert(RV); 786 787 if (RV->getKind() == RefVal::ErrorLeakReturned) { 788 // FIXME: Per comments in rdar://6320065, "create" only applies to CF 789 // objects. Only "copy", "alloc", "retain" and "new" transfer ownership 790 // to the caller for NS objects. 791 const Decl *D = &EndN->getCodeDecl(); 792 793 os << (isa<ObjCMethodDecl>(D) ? " is returned from a method " 794 : " is returned from a function "); 795 796 if (D->hasAttr<CFReturnsNotRetainedAttr>()) { 797 os << "that is annotated as CF_RETURNS_NOT_RETAINED"; 798 } else if (D->hasAttr<NSReturnsNotRetainedAttr>()) { 799 os << "that is annotated as NS_RETURNS_NOT_RETAINED"; 800 } else if (D->hasAttr<OSReturnsNotRetainedAttr>()) { 801 os << "that is annotated as OS_RETURNS_NOT_RETAINED"; 802 } else { 803 if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { 804 if (BRC.getASTContext().getLangOpts().ObjCAutoRefCount) { 805 os << "managed by Automatic Reference Counting"; 806 } else { 807 os << "whose name ('" << MD->getSelector().getAsString() 808 << "') does not start with " 809 "'copy', 'mutableCopy', 'alloc' or 'new'." 810 " This violates the naming convention rules" 811 " given in the Memory Management Guide for Cocoa"; 812 } 813 } else { 814 const FunctionDecl *FD = cast<FunctionDecl>(D); 815 ObjKind K = RV->getObjKind(); 816 if (K == ObjKind::ObjC || K == ObjKind::CF) { 817 os << "whose name ('" << *FD 818 << "') does not contain 'Copy' or 'Create'. This violates the " 819 "naming" 820 " convention rules given in the Memory Management Guide for " 821 "Core" 822 " Foundation"; 823 } else if (RV->getObjKind() == ObjKind::OS) { 824 std::string FuncName = FD->getNameAsString(); 825 os << "whose name ('" << FuncName << "') starts with '" 826 << StringRef(FuncName).substr(0, 3) << "'"; 827 } 828 } 829 } 830 } else { 831 os << " is not referenced later in this execution path and has a retain " 832 "count of +" 833 << RV->getCount(); 834 } 835 836 return std::make_shared<PathDiagnosticEventPiece>(L, os.str()); 837 } 838 839 RefCountReport::RefCountReport(const RefCountBug &D, const LangOptions &LOpts, 840 ExplodedNode *n, SymbolRef sym, bool isLeak) 841 : PathSensitiveBugReport(D, D.getDescription(), n), Sym(sym), 842 isLeak(isLeak) { 843 if (!isLeak) 844 addVisitor<RefCountReportVisitor>(sym); 845 } 846 847 RefCountReport::RefCountReport(const RefCountBug &D, const LangOptions &LOpts, 848 ExplodedNode *n, SymbolRef sym, 849 StringRef endText) 850 : PathSensitiveBugReport(D, D.getDescription(), endText, n) { 851 852 addVisitor<RefCountReportVisitor>(sym); 853 } 854 855 void RefLeakReport::deriveParamLocation(CheckerContext &Ctx) { 856 const SourceManager &SMgr = Ctx.getSourceManager(); 857 858 if (!Sym->getOriginRegion()) 859 return; 860 861 auto *Region = dyn_cast<DeclRegion>(Sym->getOriginRegion()); 862 if (Region) { 863 const Decl *PDecl = Region->getDecl(); 864 if (isa_and_nonnull<ParmVarDecl>(PDecl)) { 865 PathDiagnosticLocation ParamLocation = 866 PathDiagnosticLocation::create(PDecl, SMgr); 867 Location = ParamLocation; 868 UniqueingLocation = ParamLocation; 869 UniqueingDecl = Ctx.getLocationContext()->getDecl(); 870 } 871 } 872 } 873 874 void RefLeakReport::deriveAllocLocation(CheckerContext &Ctx) { 875 // Most bug reports are cached at the location where they occurred. 876 // With leaks, we want to unique them by the location where they were 877 // allocated, and only report a single path. To do this, we need to find 878 // the allocation site of a piece of tracked memory, which we do via a 879 // call to GetAllocationSite. This will walk the ExplodedGraph backwards. 880 // Note that this is *not* the trimmed graph; we are guaranteed, however, 881 // that all ancestor nodes that represent the allocation site have the 882 // same SourceLocation. 883 const ExplodedNode *AllocNode = nullptr; 884 885 const SourceManager &SMgr = Ctx.getSourceManager(); 886 887 AllocationInfo AllocI = 888 GetAllocationSite(Ctx.getStateManager(), getErrorNode(), Sym); 889 890 AllocNode = AllocI.N; 891 AllocFirstBinding = AllocI.R; 892 markInteresting(AllocI.InterestingMethodContext); 893 894 // Get the SourceLocation for the allocation site. 895 // FIXME: This will crash the analyzer if an allocation comes from an 896 // implicit call (ex: a destructor call). 897 // (Currently there are no such allocations in Cocoa, though.) 898 AllocStmt = AllocNode->getStmtForDiagnostics(); 899 900 if (!AllocStmt) { 901 AllocFirstBinding = nullptr; 902 return; 903 } 904 905 PathDiagnosticLocation AllocLocation = PathDiagnosticLocation::createBegin( 906 AllocStmt, SMgr, AllocNode->getLocationContext()); 907 Location = AllocLocation; 908 909 // Set uniqieing info, which will be used for unique the bug reports. The 910 // leaks should be uniqued on the allocation site. 911 UniqueingLocation = AllocLocation; 912 UniqueingDecl = AllocNode->getLocationContext()->getDecl(); 913 } 914 915 void RefLeakReport::createDescription(CheckerContext &Ctx) { 916 assert(Location.isValid() && UniqueingDecl && UniqueingLocation.isValid()); 917 Description.clear(); 918 llvm::raw_string_ostream os(Description); 919 os << "Potential leak of an object"; 920 921 Optional<std::string> RegionDescription = 922 describeRegion(AllocBindingToReport); 923 if (RegionDescription) { 924 os << " stored into '" << *RegionDescription << '\''; 925 } else { 926 927 // If we can't figure out the name, just supply the type information. 928 os << " of type '" << getPrettyTypeName(Sym->getType()) << "'"; 929 } 930 } 931 932 void RefLeakReport::findBindingToReport(CheckerContext &Ctx, 933 ExplodedNode *Node) { 934 if (!AllocFirstBinding) 935 // If we don't have any bindings, we won't be able to find any 936 // better binding to report. 937 return; 938 939 // If the original region still contains the leaking symbol... 940 if (Node->getState()->getSVal(AllocFirstBinding).getAsSymbol() == Sym) { 941 // ...it is the best binding to report. 942 AllocBindingToReport = AllocFirstBinding; 943 return; 944 } 945 946 // At this point, we know that the original region doesn't contain the leaking 947 // when the actual leak happens. It means that it can be confusing for the 948 // user to see such description in the message. 949 // 950 // Let's consider the following example: 951 // Object *Original = allocate(...); 952 // Object *New = Original; 953 // Original = allocate(...); 954 // Original->release(); 955 // 956 // Complaining about a leaking object "stored into Original" might cause a 957 // rightful confusion because 'Original' is actually released. 958 // We should complain about 'New' instead. 959 Bindings AllVarBindings = 960 getAllVarBindingsForSymbol(Ctx.getStateManager(), Node, Sym); 961 962 // While looking for the last var bindings, we can still find 963 // `AllocFirstBinding` to be one of them. In situations like this, 964 // it would still be the easiest case to explain to our users. 965 if (!AllVarBindings.empty() && 966 llvm::count_if(AllVarBindings, 967 [this](const std::pair<const MemRegion *, SVal> Binding) { 968 return Binding.first == AllocFirstBinding; 969 }) == 0) { 970 // Let's pick one of them at random (if there is something to pick from). 971 AllocBindingToReport = AllVarBindings[0].first; 972 973 // Because 'AllocBindingToReport' is not the same as 974 // 'AllocFirstBinding', we need to explain how the leaking object 975 // got from one to another. 976 // 977 // NOTE: We use the actual SVal stored in AllocBindingToReport here because 978 // trackStoredValue compares SVal's and it can get trickier for 979 // something like derived regions if we want to construct SVal from 980 // Sym. Instead, we take the value that is definitely stored in that 981 // region, thus guaranteeing that trackStoredValue will work. 982 bugreporter::trackStoredValue(AllVarBindings[0].second.castAs<KnownSVal>(), 983 AllocBindingToReport, *this); 984 } else { 985 AllocBindingToReport = AllocFirstBinding; 986 } 987 } 988 989 RefLeakReport::RefLeakReport(const RefCountBug &D, const LangOptions &LOpts, 990 ExplodedNode *N, SymbolRef Sym, 991 CheckerContext &Ctx) 992 : RefCountReport(D, LOpts, N, Sym, /*isLeak=*/true) { 993 994 deriveAllocLocation(Ctx); 995 findBindingToReport(Ctx, N); 996 997 if (!AllocFirstBinding) 998 deriveParamLocation(Ctx); 999 1000 createDescription(Ctx); 1001 1002 addVisitor<RefLeakReportVisitor>(Sym, AllocBindingToReport); 1003 } 1004