1 //=======- RetainPtrCtorAdoptChecker.cpp -------------------------*- 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 #include "ASTUtils.h" 10 #include "PtrTypesSemantics.h" 11 #include "clang/AST/RecursiveASTVisitor.h" 12 #include "clang/Analysis/DomainSpecific/CocoaConventions.h" 13 #include "clang/Analysis/RetainSummaryManager.h" 14 #include "clang/StaticAnalyzer/Checkers/BuiltinCheckerRegistration.h" 15 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 16 #include "clang/StaticAnalyzer/Core/BugReporter/BugType.h" 17 #include "clang/StaticAnalyzer/Core/Checker.h" 18 #include "llvm/ADT/DenseSet.h" 19 #include <optional> 20 21 using namespace clang; 22 using namespace ento; 23 24 namespace { 25 26 class RetainPtrCtorAdoptChecker 27 : public Checker<check::ASTDecl<TranslationUnitDecl>> { 28 private: 29 BugType Bug; 30 mutable BugReporter *BR = nullptr; 31 mutable std::unique_ptr<RetainSummaryManager> Summaries; 32 mutable llvm::DenseSet<const ValueDecl *> CreateOrCopyOutArguments; 33 mutable llvm::DenseSet<const Expr *> CreateOrCopyFnCall; 34 mutable RetainTypeChecker RTC; 35 36 public: 37 RetainPtrCtorAdoptChecker() 38 : Bug(this, "Correct use of RetainPtr, adoptNS, and adoptCF", 39 "WebKit coding guidelines") {} 40 41 void checkASTDecl(const TranslationUnitDecl *TUD, AnalysisManager &MGR, 42 BugReporter &BRArg) const { 43 BR = &BRArg; 44 45 // The calls to checkAST* from AnalysisConsumer don't 46 // visit template instantiations or lambda classes. We 47 // want to visit those, so we make our own RecursiveASTVisitor. 48 struct LocalVisitor : public RecursiveASTVisitor<LocalVisitor> { 49 const RetainPtrCtorAdoptChecker *Checker; 50 Decl *DeclWithIssue{nullptr}; 51 52 using Base = RecursiveASTVisitor<LocalVisitor>; 53 54 explicit LocalVisitor(const RetainPtrCtorAdoptChecker *Checker) 55 : Checker(Checker) { 56 assert(Checker); 57 } 58 59 bool shouldVisitTemplateInstantiations() const { return true; } 60 bool shouldVisitImplicitCode() const { return false; } 61 62 bool TraverseDecl(Decl *D) { 63 llvm::SaveAndRestore SavedDecl(DeclWithIssue); 64 if (D && (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D))) 65 DeclWithIssue = D; 66 return Base::TraverseDecl(D); 67 } 68 69 bool TraverseClassTemplateDecl(ClassTemplateDecl *CTD) { 70 if (isRetainPtr(safeGetName(CTD))) 71 return true; // Skip the contents of RetainPtr. 72 return Base::TraverseClassTemplateDecl(CTD); 73 } 74 75 bool VisitTypedefDecl(TypedefDecl *TD) { 76 Checker->RTC.visitTypedef(TD); 77 return true; 78 } 79 80 bool VisitCallExpr(const CallExpr *CE) { 81 Checker->visitCallExpr(CE, DeclWithIssue); 82 return true; 83 } 84 85 bool VisitCXXConstructExpr(const CXXConstructExpr *CE) { 86 Checker->visitConstructExpr(CE, DeclWithIssue); 87 return true; 88 } 89 90 bool VisitObjCMessageExpr(const ObjCMessageExpr *ObjCMsgExpr) { 91 Checker->visitObjCMessageExpr(ObjCMsgExpr, DeclWithIssue); 92 return true; 93 } 94 95 bool VisitReturnStmt(const ReturnStmt *RS) { 96 Checker->visitReturnStmt(RS, DeclWithIssue); 97 return true; 98 } 99 100 bool VisitVarDecl(const VarDecl *VD) { 101 Checker->visitVarDecl(VD); 102 return true; 103 } 104 105 bool VisitBinaryOperator(const BinaryOperator *BO) { 106 Checker->visitBinaryOperator(BO); 107 return true; 108 } 109 }; 110 111 LocalVisitor visitor(this); 112 Summaries = std::make_unique<RetainSummaryManager>( 113 TUD->getASTContext(), true /* trackObjCAndCFObjects */, 114 false /* trackOSObjects */); 115 RTC.visitTranslationUnitDecl(TUD); 116 visitor.TraverseDecl(const_cast<TranslationUnitDecl *>(TUD)); 117 } 118 119 bool isAdoptFn(const Decl *FnDecl) const { 120 return isAdoptFnName(safeGetName(FnDecl)); 121 } 122 123 bool isAdoptFnName(const std::string &Name) const { 124 return isAdoptNS(Name) || Name == "adoptCF" || Name == "adoptCFArc"; 125 } 126 127 bool isAdoptNS(const std::string &Name) const { 128 return Name == "adoptNS" || Name == "adoptNSArc"; 129 } 130 131 void visitCallExpr(const CallExpr *CE, const Decl *DeclWithIssue) const { 132 assert(BR && "expected nonnull BugReporter"); 133 if (BR->getSourceManager().isInSystemHeader(CE->getExprLoc())) 134 return; 135 136 std::string FnName; 137 if (auto *F = CE->getDirectCallee()) { 138 FnName = safeGetName(F); 139 if (isAdoptFnName(FnName)) 140 checkAdoptCall(CE, FnName, DeclWithIssue); 141 else { 142 checkCreateOrCopyFunction(CE, DeclWithIssue); 143 checkBridgingRelease(CE, F, DeclWithIssue); 144 } 145 return; 146 } 147 148 auto *CalleeExpr = CE->getCallee(); 149 if (!CalleeExpr) 150 return; 151 CalleeExpr = CalleeExpr->IgnoreParenCasts(); 152 if (auto *UnresolvedExpr = dyn_cast<UnresolvedLookupExpr>(CalleeExpr)) { 153 auto Name = UnresolvedExpr->getName(); 154 if (!Name.isIdentifier()) 155 return; 156 FnName = Name.getAsString(); 157 if (isAdoptFnName(FnName)) 158 checkAdoptCall(CE, FnName, DeclWithIssue); 159 } 160 checkCreateOrCopyFunction(CE, DeclWithIssue); 161 } 162 163 void checkAdoptCall(const CallExpr *CE, const std::string &FnName, 164 const Decl *DeclWithIssue) const { 165 if (!CE->getNumArgs()) 166 return; 167 168 auto *Arg = CE->getArg(0)->IgnoreParenCasts(); 169 auto Result = isOwned(Arg); 170 if (Result == IsOwnedResult::Unknown) 171 Result = IsOwnedResult::NotOwned; 172 173 const Expr *Inner = nullptr; 174 if (isAllocInit(Arg, &Inner) || isCreateOrCopy(Arg)) { 175 if (Inner) 176 CreateOrCopyFnCall.insert(Inner); 177 CreateOrCopyFnCall.insert(Arg); // Avoid double reporting. 178 return; 179 } 180 if (Result == IsOwnedResult::Owned || Result == IsOwnedResult::Skip) { 181 CreateOrCopyFnCall.insert(Arg); 182 return; 183 } 184 185 if (auto *DRE = dyn_cast<DeclRefExpr>(Arg)) { 186 if (CreateOrCopyOutArguments.contains(DRE->getDecl())) 187 return; 188 } 189 if (RTC.isARCEnabled() && isAdoptFnName(FnName)) 190 reportUseAfterFree(FnName, CE, DeclWithIssue, "when ARC is disabled"); 191 else 192 reportUseAfterFree(FnName, CE, DeclWithIssue); 193 } 194 195 void visitObjCMessageExpr(const ObjCMessageExpr *ObjCMsgExpr, 196 const Decl *DeclWithIssue) const { 197 if (BR->getSourceManager().isInSystemHeader(ObjCMsgExpr->getExprLoc())) 198 return; 199 200 auto Selector = ObjCMsgExpr->getSelector(); 201 if (Selector.getAsString() == "autorelease") { 202 auto *Receiver = ObjCMsgExpr->getInstanceReceiver()->IgnoreParenCasts(); 203 if (!Receiver) 204 return; 205 ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(Receiver); 206 if (!ObjCMsgExpr) 207 return; 208 const Expr *Inner = nullptr; 209 if (!isAllocInit(ObjCMsgExpr, &Inner)) 210 return; 211 CreateOrCopyFnCall.insert(ObjCMsgExpr); 212 if (Inner) 213 CreateOrCopyFnCall.insert(Inner); 214 return; 215 } 216 217 const Expr *Inner = nullptr; 218 if (!isAllocInit(ObjCMsgExpr, &Inner)) 219 return; 220 if (RTC.isARCEnabled()) 221 return; // ARC never leaks. 222 if (CreateOrCopyFnCall.contains(ObjCMsgExpr)) 223 return; 224 if (Inner) 225 CreateOrCopyFnCall.insert(Inner); // Avoid double reporting. 226 reportLeak(ObjCMsgExpr, DeclWithIssue); 227 } 228 229 void checkCreateOrCopyFunction(const CallExpr *CE, 230 const Decl *DeclWithIssue) const { 231 unsigned ArgCount = CE->getNumArgs(); 232 auto *CalleeDecl = CE->getCalleeDecl(); 233 auto *FnDecl = CalleeDecl ? CalleeDecl->getAsFunction() : nullptr; 234 for (unsigned ArgIndex = 0; ArgIndex < ArgCount; ++ArgIndex) { 235 auto *Arg = CE->getArg(ArgIndex)->IgnoreParenCasts(); 236 auto *Unary = dyn_cast<UnaryOperator>(Arg); 237 if (!Unary) 238 continue; 239 if (Unary->getOpcode() != UO_AddrOf) 240 continue; 241 auto *SubExpr = Unary->getSubExpr(); 242 if (!SubExpr) 243 continue; 244 auto *DRE = dyn_cast<DeclRefExpr>(SubExpr->IgnoreParenCasts()); 245 if (!DRE) 246 continue; 247 auto *Decl = DRE->getDecl(); 248 if (!Decl) 249 continue; 250 if (FnDecl && ArgIndex < FnDecl->getNumParams()) { 251 // Manually check attributes on argumenet since RetainSummaryManager 252 // basically ignores CF_RETRUNS_RETAINED on out arguments. 253 auto *ParamDecl = FnDecl->getParamDecl(ArgIndex); 254 if (ParamDecl->hasAttr<CFReturnsRetainedAttr>()) 255 CreateOrCopyOutArguments.insert(Decl); 256 } else { 257 // No callee or a variadic argument. 258 // Conservatively assume it's an out argument. 259 if (RTC.isUnretained(Decl->getType())) 260 CreateOrCopyOutArguments.insert(Decl); 261 } 262 } 263 auto Summary = Summaries->getSummary(AnyCall(CE)); 264 switch (Summary->getRetEffect().getKind()) { 265 case RetEffect::OwnedSymbol: 266 case RetEffect::OwnedWhenTrackedReceiver: 267 if (!CreateOrCopyFnCall.contains(CE)) 268 reportLeak(CE, DeclWithIssue); 269 break; 270 default: 271 break; 272 } 273 } 274 275 void checkBridgingRelease(const CallExpr *CE, const FunctionDecl *Callee, 276 const Decl *DeclWithIssue) const { 277 if (safeGetName(Callee) != "CFBridgingRelease" || CE->getNumArgs() != 1) 278 return; 279 280 auto *Arg = CE->getArg(0)->IgnoreParenCasts(); 281 auto *InnerCE = dyn_cast<CallExpr>(Arg); 282 if (!InnerCE) 283 return; 284 285 auto *InnerF = InnerCE->getDirectCallee(); 286 if (!InnerF || !isCreateOrCopyFunction(InnerF)) 287 return; 288 289 CreateOrCopyFnCall.insert(InnerCE); 290 } 291 292 void visitConstructExpr(const CXXConstructExpr *CE, 293 const Decl *DeclWithIssue) const { 294 assert(BR && "expected nonnull BugReporter"); 295 if (BR->getSourceManager().isInSystemHeader(CE->getExprLoc())) 296 return; 297 298 auto *Ctor = CE->getConstructor(); 299 if (!Ctor) 300 return; 301 302 auto *Cls = Ctor->getParent(); 303 if (!Cls) 304 return; 305 306 if (!isRetainPtr(safeGetName(Cls)) || !CE->getNumArgs()) 307 return; 308 309 // Ignore RetainPtr construction inside adoptNS, adoptCF, and retainPtr. 310 if (isAdoptFn(DeclWithIssue) || safeGetName(DeclWithIssue) == "retainPtr") 311 return; 312 313 std::string Name = "RetainPtr constructor"; 314 auto *Arg = CE->getArg(0)->IgnoreParenCasts(); 315 auto Result = isOwned(Arg); 316 317 if (isCreateOrCopy(Arg)) 318 CreateOrCopyFnCall.insert(Arg); // Avoid double reporting. 319 320 const Expr *Inner = nullptr; 321 if (isAllocInit(Arg, &Inner)) { 322 CreateOrCopyFnCall.insert(Arg); 323 if (Inner) 324 CreateOrCopyFnCall.insert(Inner); 325 } 326 327 if (Result == IsOwnedResult::Skip) 328 return; 329 330 if (Result == IsOwnedResult::Unknown) 331 Result = IsOwnedResult::NotOwned; 332 if (Result == IsOwnedResult::Owned) 333 reportLeak(Name, CE, DeclWithIssue); 334 else if (RTC.isARCEnabled() && isAllocInit(Arg)) 335 reportLeak(Name, CE, DeclWithIssue, "when ARC is disabled"); 336 else if (isCreateOrCopy(Arg)) 337 reportLeak(Name, CE, DeclWithIssue); 338 } 339 340 void visitVarDecl(const VarDecl *VD) const { 341 auto *Init = VD->getInit(); 342 if (!Init || !RTC.isARCEnabled()) 343 return; 344 Init = Init->IgnoreParenCasts(); 345 const Expr *Inner = nullptr; 346 if (isAllocInit(Init, &Inner)) { 347 CreateOrCopyFnCall.insert(Init); 348 if (Inner) 349 CreateOrCopyFnCall.insert(Inner); 350 } 351 } 352 353 void visitBinaryOperator(const BinaryOperator *BO) const { 354 if (!BO->isAssignmentOp()) 355 return; 356 if (!isa<ObjCIvarRefExpr>(BO->getLHS())) 357 return; 358 auto *RHS = BO->getRHS()->IgnoreParenCasts(); 359 const Expr *Inner = nullptr; 360 if (isAllocInit(RHS, &Inner)) { 361 CreateOrCopyFnCall.insert(RHS); 362 if (Inner) 363 CreateOrCopyFnCall.insert(Inner); 364 } 365 } 366 367 void visitReturnStmt(const ReturnStmt *RS, const Decl *DeclWithIssue) const { 368 if (!DeclWithIssue) 369 return; 370 auto *RetValue = RS->getRetValue(); 371 if (!RetValue) 372 return; 373 RetValue = RetValue->IgnoreParenCasts(); 374 std::optional<bool> retainsRet; 375 if (auto *FnDecl = dyn_cast<FunctionDecl>(DeclWithIssue)) 376 retainsRet = retainsReturnValue(FnDecl); 377 else if (auto *MethodDecl = dyn_cast<ObjCMethodDecl>(DeclWithIssue)) 378 retainsRet = retainsReturnValue(MethodDecl); 379 else 380 return; 381 if (!retainsRet || !*retainsRet) { 382 // Under ARC, returning [[X alloc] init] doesn't leak X. 383 if (RTC.isUnretained(RetValue->getType())) 384 return; 385 } 386 if (auto *CE = dyn_cast<CallExpr>(RetValue)) { 387 auto *Callee = CE->getDirectCallee(); 388 if (!Callee || !isCreateOrCopyFunction(Callee)) 389 return; 390 CreateOrCopyFnCall.insert(CE); 391 return; 392 } 393 const Expr *Inner = nullptr; 394 if (isAllocInit(RetValue, &Inner)) { 395 CreateOrCopyFnCall.insert(RetValue); 396 if (Inner) 397 CreateOrCopyFnCall.insert(Inner); 398 } 399 } 400 401 template <typename CallableType> 402 std::optional<bool> retainsReturnValue(const CallableType *FnDecl) const { 403 auto Summary = Summaries->getSummary(AnyCall(FnDecl)); 404 auto RetEffect = Summary->getRetEffect(); 405 switch (RetEffect.getKind()) { 406 case RetEffect::NoRet: 407 return std::nullopt; 408 case RetEffect::OwnedSymbol: 409 return true; 410 case RetEffect::NotOwnedSymbol: 411 return false; 412 case RetEffect::OwnedWhenTrackedReceiver: 413 return std::nullopt; 414 case RetEffect::NoRetHard: 415 return std::nullopt; 416 } 417 return std::nullopt; 418 } 419 420 bool isAllocInit(const Expr *E, const Expr **InnerExpr = nullptr) const { 421 auto *ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(E); 422 if (auto *POE = dyn_cast<PseudoObjectExpr>(E)) { 423 if (unsigned ExprCount = POE->getNumSemanticExprs()) { 424 auto *Expr = POE->getSemanticExpr(ExprCount - 1)->IgnoreParenCasts(); 425 ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(Expr); 426 if (InnerExpr) 427 *InnerExpr = ObjCMsgExpr; 428 } 429 } 430 if (!ObjCMsgExpr) 431 return false; 432 auto Selector = ObjCMsgExpr->getSelector(); 433 auto NameForFirstSlot = Selector.getNameForSlot(0); 434 if (NameForFirstSlot == "alloc" || NameForFirstSlot.starts_with("copy") || 435 NameForFirstSlot.starts_with("mutableCopy")) 436 return true; 437 if (!NameForFirstSlot.starts_with("init") && 438 !NameForFirstSlot.starts_with("_init")) 439 return false; 440 if (!ObjCMsgExpr->isInstanceMessage()) 441 return false; 442 auto *Receiver = ObjCMsgExpr->getInstanceReceiver(); 443 if (!Receiver) 444 return false; 445 Receiver = Receiver->IgnoreParenCasts(); 446 if (auto *Inner = dyn_cast<ObjCMessageExpr>(Receiver)) { 447 if (InnerExpr) 448 *InnerExpr = Inner; 449 auto InnerSelector = Inner->getSelector(); 450 return InnerSelector.getNameForSlot(0) == "alloc"; 451 } else if (auto *CE = dyn_cast<CallExpr>(Receiver)) { 452 if (InnerExpr) 453 *InnerExpr = CE; 454 if (auto *Callee = CE->getDirectCallee()) { 455 if (Callee->getDeclName().isIdentifier()) { 456 auto CalleeName = Callee->getName(); 457 return CalleeName.starts_with("alloc"); 458 } 459 } 460 } 461 return false; 462 } 463 464 bool isCreateOrCopy(const Expr *E) const { 465 auto *CE = dyn_cast<CallExpr>(E); 466 if (!CE) 467 return false; 468 auto *Callee = CE->getDirectCallee(); 469 if (!Callee) 470 return false; 471 return isCreateOrCopyFunction(Callee); 472 } 473 474 bool isCreateOrCopyFunction(const FunctionDecl *FnDecl) const { 475 auto CalleeName = safeGetName(FnDecl); 476 return CalleeName.find("Create") != std::string::npos || 477 CalleeName.find("Copy") != std::string::npos; 478 } 479 480 enum class IsOwnedResult { Unknown, Skip, Owned, NotOwned }; 481 IsOwnedResult isOwned(const Expr *E) const { 482 while (1) { 483 if (auto *POE = dyn_cast<PseudoObjectExpr>(E)) { 484 if (unsigned SemanticExprCount = POE->getNumSemanticExprs()) { 485 E = POE->getSemanticExpr(SemanticExprCount - 1); 486 continue; 487 } 488 } 489 if (isa<CXXNullPtrLiteralExpr>(E)) 490 return IsOwnedResult::NotOwned; 491 if (auto *DRE = dyn_cast<DeclRefExpr>(E)) { 492 auto QT = DRE->getType(); 493 if (isRetainPtrType(QT)) 494 return IsOwnedResult::NotOwned; 495 QT = QT.getCanonicalType(); 496 if (RTC.isUnretained(QT, true /* ignoreARC */)) 497 return IsOwnedResult::NotOwned; 498 auto *PointeeType = QT->getPointeeType().getTypePtrOrNull(); 499 if (PointeeType && PointeeType->isVoidType()) 500 return IsOwnedResult::NotOwned; // Assume reading void* as +0. 501 } 502 if (auto *TE = dyn_cast<CXXBindTemporaryExpr>(E)) { 503 E = TE->getSubExpr(); 504 continue; 505 } 506 if (auto *ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(E)) { 507 auto Summary = Summaries->getSummary(AnyCall(ObjCMsgExpr)); 508 auto RetEffect = Summary->getRetEffect(); 509 switch (RetEffect.getKind()) { 510 case RetEffect::NoRet: 511 return IsOwnedResult::Unknown; 512 case RetEffect::OwnedSymbol: 513 return IsOwnedResult::Owned; 514 case RetEffect::NotOwnedSymbol: 515 return IsOwnedResult::NotOwned; 516 case RetEffect::OwnedWhenTrackedReceiver: 517 if (auto *Receiver = ObjCMsgExpr->getInstanceReceiver()) { 518 E = Receiver->IgnoreParenCasts(); 519 continue; 520 } 521 return IsOwnedResult::Unknown; 522 case RetEffect::NoRetHard: 523 return IsOwnedResult::Unknown; 524 } 525 } 526 if (auto *CXXCE = dyn_cast<CXXMemberCallExpr>(E)) { 527 if (auto *MD = CXXCE->getMethodDecl()) { 528 auto *Cls = MD->getParent(); 529 if (auto *CD = dyn_cast<CXXConversionDecl>(MD)) { 530 auto QT = CD->getConversionType().getCanonicalType(); 531 auto *ResultType = QT.getTypePtrOrNull(); 532 if (isRetainPtr(safeGetName(Cls)) && ResultType && 533 (ResultType->isPointerType() || ResultType->isReferenceType() || 534 ResultType->isObjCObjectPointerType())) 535 return IsOwnedResult::NotOwned; 536 } 537 if (safeGetName(MD) == "leakRef" && isRetainPtr(safeGetName(Cls))) 538 return IsOwnedResult::Owned; 539 } 540 } 541 if (auto *CE = dyn_cast<CallExpr>(E)) { 542 if (auto *Callee = CE->getDirectCallee()) { 543 if (isAdoptFn(Callee)) 544 return IsOwnedResult::NotOwned; 545 auto Name = safeGetName(Callee); 546 if (Name == "__builtin___CFStringMakeConstantString") 547 return IsOwnedResult::NotOwned; 548 if ((Name == "checked_cf_cast" || Name == "dynamic_cf_cast" || 549 Name == "checked_objc_cast" || Name == "dynamic_objc_cast") && 550 CE->getNumArgs() == 1) { 551 E = CE->getArg(0)->IgnoreParenCasts(); 552 continue; 553 } 554 auto RetType = Callee->getReturnType(); 555 if (isRetainPtrType(RetType)) 556 return IsOwnedResult::NotOwned; 557 if (isCreateOrCopyFunction(Callee)) { 558 CreateOrCopyFnCall.insert(CE); 559 return IsOwnedResult::Owned; 560 } 561 } else if (auto *CalleeExpr = CE->getCallee()) { 562 if (isa<CXXDependentScopeMemberExpr>(CalleeExpr)) 563 return IsOwnedResult::Skip; // Wait for instantiation. 564 if (isa<UnresolvedLookupExpr>(CalleeExpr)) 565 return IsOwnedResult::Skip; // Wait for instantiation. 566 } 567 auto Summary = Summaries->getSummary(AnyCall(CE)); 568 auto RetEffect = Summary->getRetEffect(); 569 switch (RetEffect.getKind()) { 570 case RetEffect::NoRet: 571 return IsOwnedResult::Unknown; 572 case RetEffect::OwnedSymbol: 573 return IsOwnedResult::Owned; 574 case RetEffect::NotOwnedSymbol: 575 return IsOwnedResult::NotOwned; 576 case RetEffect::OwnedWhenTrackedReceiver: 577 return IsOwnedResult::Unknown; 578 case RetEffect::NoRetHard: 579 return IsOwnedResult::Unknown; 580 } 581 } 582 break; 583 } 584 return IsOwnedResult::Unknown; 585 } 586 587 void reportUseAfterFree(const std::string &Name, const CallExpr *CE, 588 const Decl *DeclWithIssue, 589 const char *condition = nullptr) const { 590 SmallString<100> Buf; 591 llvm::raw_svector_ostream Os(Buf); 592 593 Os << "Incorrect use of " << Name 594 << ". The argument is +0 and results in an use-after-free"; 595 if (condition) 596 Os << " " << condition; 597 Os << "."; 598 599 assert(BR && "expected nonnull BugReporter"); 600 PathDiagnosticLocation BSLoc(CE->getSourceRange().getBegin(), 601 BR->getSourceManager()); 602 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc); 603 Report->addRange(CE->getSourceRange()); 604 Report->setDeclWithIssue(DeclWithIssue); 605 BR->emitReport(std::move(Report)); 606 } 607 608 void reportLeak(std::string &Name, const CXXConstructExpr *CE, 609 const Decl *DeclWithIssue, 610 const char *condition = nullptr) const { 611 SmallString<100> Buf; 612 llvm::raw_svector_ostream Os(Buf); 613 614 Os << "Incorrect use of " << Name 615 << ". The argument is +1 and results in a memory leak"; 616 if (condition) 617 Os << " " << condition; 618 Os << "."; 619 620 assert(BR && "expected nonnull BugReporter"); 621 PathDiagnosticLocation BSLoc(CE->getSourceRange().getBegin(), 622 BR->getSourceManager()); 623 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc); 624 Report->addRange(CE->getSourceRange()); 625 Report->setDeclWithIssue(DeclWithIssue); 626 BR->emitReport(std::move(Report)); 627 } 628 629 template <typename ExprType> 630 void reportLeak(const ExprType *E, const Decl *DeclWithIssue) const { 631 SmallString<100> Buf; 632 llvm::raw_svector_ostream Os(Buf); 633 634 Os << "The return value is +1 and results in a memory leak."; 635 636 PathDiagnosticLocation BSLoc(E->getSourceRange().getBegin(), 637 BR->getSourceManager()); 638 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc); 639 Report->addRange(E->getSourceRange()); 640 Report->setDeclWithIssue(DeclWithIssue); 641 BR->emitReport(std::move(Report)); 642 } 643 }; 644 } // namespace 645 646 void ento::registerRetainPtrCtorAdoptChecker(CheckerManager &Mgr) { 647 Mgr.registerChecker<RetainPtrCtorAdoptChecker>(); 648 } 649 650 bool ento::shouldRegisterRetainPtrCtorAdoptChecker(const CheckerManager &mgr) { 651 return true; 652 } 653