660 lines · cpp
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-exception6//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 21using namespace clang;22using namespace ento;23 24namespace {25 26class RetainPtrCtorAdoptChecker27 : public Checker<check::ASTDecl<TranslationUnitDecl>> {28private: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 36public: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't46 // visit template instantiations or lambda classes. We47 // 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 (isRetainPtrOrOSPtr(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 Name == "adoptOSObject" || Name == "adoptOSObjectArc";126 }127 128 bool isAdoptNS(const std::string &Name) const {129 return Name == "adoptNS" || Name == "adoptNSArc";130 }131 132 void visitCallExpr(const CallExpr *CE, const Decl *DeclWithIssue) const {133 assert(BR && "expected nonnull BugReporter");134 if (BR->getSourceManager().isInSystemHeader(CE->getExprLoc()))135 return;136 137 std::string FnName;138 if (auto *F = CE->getDirectCallee()) {139 FnName = safeGetName(F);140 if (isAdoptFnName(FnName))141 checkAdoptCall(CE, FnName, DeclWithIssue);142 else {143 checkCreateOrCopyFunction(CE, DeclWithIssue);144 checkBridgingRelease(CE, F, DeclWithIssue);145 }146 return;147 }148 149 auto *CalleeExpr = CE->getCallee();150 if (!CalleeExpr)151 return;152 CalleeExpr = CalleeExpr->IgnoreParenCasts();153 if (auto *UnresolvedExpr = dyn_cast<UnresolvedLookupExpr>(CalleeExpr)) {154 auto Name = UnresolvedExpr->getName();155 if (!Name.isIdentifier())156 return;157 FnName = Name.getAsString();158 if (isAdoptFnName(FnName))159 checkAdoptCall(CE, FnName, DeclWithIssue);160 }161 checkCreateOrCopyFunction(CE, DeclWithIssue);162 }163 164 void checkAdoptCall(const CallExpr *CE, const std::string &FnName,165 const Decl *DeclWithIssue) const {166 if (!CE->getNumArgs())167 return;168 169 auto *Arg = CE->getArg(0)->IgnoreParenCasts();170 auto Result = isOwned(Arg);171 if (Result == IsOwnedResult::Unknown)172 Result = IsOwnedResult::NotOwned;173 174 const Expr *Inner = nullptr;175 if (isAllocInit(Arg, &Inner) || isCreateOrCopy(Arg)) {176 if (Inner)177 CreateOrCopyFnCall.insert(Inner);178 CreateOrCopyFnCall.insert(Arg); // Avoid double reporting.179 return;180 }181 if (Result == IsOwnedResult::Owned || Result == IsOwnedResult::Skip ||182 isNullPtr(Arg)) {183 CreateOrCopyFnCall.insert(Arg);184 return;185 }186 187 if (auto *DRE = dyn_cast<DeclRefExpr>(Arg)) {188 if (CreateOrCopyOutArguments.contains(DRE->getDecl()))189 return;190 }191 if (RTC.isARCEnabled() && isAdoptFnName(FnName))192 reportUseAfterFree(FnName, CE, DeclWithIssue, "when ARC is disabled");193 else194 reportUseAfterFree(FnName, CE, DeclWithIssue);195 }196 197 void visitObjCMessageExpr(const ObjCMessageExpr *ObjCMsgExpr,198 const Decl *DeclWithIssue) const {199 if (BR->getSourceManager().isInSystemHeader(ObjCMsgExpr->getExprLoc()))200 return;201 202 auto Selector = ObjCMsgExpr->getSelector();203 if (Selector.getAsString() == "autorelease") {204 auto *Receiver = ObjCMsgExpr->getInstanceReceiver()->IgnoreParenCasts();205 if (!Receiver)206 return;207 ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(Receiver);208 if (!ObjCMsgExpr)209 return;210 const Expr *Inner = nullptr;211 if (!isAllocInit(ObjCMsgExpr, &Inner))212 return;213 CreateOrCopyFnCall.insert(ObjCMsgExpr);214 if (Inner)215 CreateOrCopyFnCall.insert(Inner);216 return;217 }218 219 const Expr *Inner = nullptr;220 if (!isAllocInit(ObjCMsgExpr, &Inner))221 return;222 if (RTC.isARCEnabled())223 return; // ARC never leaks.224 if (CreateOrCopyFnCall.contains(ObjCMsgExpr))225 return;226 if (Inner)227 CreateOrCopyFnCall.insert(Inner); // Avoid double reporting.228 reportLeak(ObjCMsgExpr, DeclWithIssue);229 }230 231 void checkCreateOrCopyFunction(const CallExpr *CE,232 const Decl *DeclWithIssue) const {233 unsigned ArgCount = CE->getNumArgs();234 auto *CalleeDecl = CE->getCalleeDecl();235 auto *FnDecl = CalleeDecl ? CalleeDecl->getAsFunction() : nullptr;236 for (unsigned ArgIndex = 0; ArgIndex < ArgCount; ++ArgIndex) {237 auto *Arg = CE->getArg(ArgIndex)->IgnoreParenCasts();238 auto *Unary = dyn_cast<UnaryOperator>(Arg);239 if (!Unary)240 continue;241 if (Unary->getOpcode() != UO_AddrOf)242 continue;243 auto *SubExpr = Unary->getSubExpr();244 if (!SubExpr)245 continue;246 auto *DRE = dyn_cast<DeclRefExpr>(SubExpr->IgnoreParenCasts());247 if (!DRE)248 continue;249 auto *Decl = DRE->getDecl();250 if (!Decl)251 continue;252 if (FnDecl && ArgIndex < FnDecl->getNumParams()) {253 // Manually check attributes on argumenet since RetainSummaryManager254 // basically ignores CF_RETRUNS_RETAINED on out arguments.255 auto *ParamDecl = FnDecl->getParamDecl(ArgIndex);256 if (ParamDecl->hasAttr<CFReturnsRetainedAttr>())257 CreateOrCopyOutArguments.insert(Decl);258 } else {259 // No callee or a variadic argument.260 // Conservatively assume it's an out argument.261 if (RTC.isUnretained(Decl->getType()))262 CreateOrCopyOutArguments.insert(Decl);263 }264 }265 auto Summary = Summaries->getSummary(AnyCall(CE));266 switch (Summary->getRetEffect().getKind()) {267 case RetEffect::OwnedSymbol:268 case RetEffect::OwnedWhenTrackedReceiver:269 if (!CreateOrCopyFnCall.contains(CE))270 reportLeak(CE, DeclWithIssue);271 break;272 default:273 break;274 }275 }276 277 void checkBridgingRelease(const CallExpr *CE, const FunctionDecl *Callee,278 const Decl *DeclWithIssue) const {279 if (safeGetName(Callee) != "CFBridgingRelease" || CE->getNumArgs() != 1)280 return;281 282 auto *Arg = CE->getArg(0)->IgnoreParenCasts();283 auto *InnerCE = dyn_cast<CallExpr>(Arg);284 if (!InnerCE)285 return;286 287 auto *InnerF = InnerCE->getDirectCallee();288 if (!InnerF || !isCreateOrCopyFunction(InnerF))289 return;290 291 CreateOrCopyFnCall.insert(InnerCE);292 }293 294 void visitConstructExpr(const CXXConstructExpr *CE,295 const Decl *DeclWithIssue) const {296 assert(BR && "expected nonnull BugReporter");297 if (BR->getSourceManager().isInSystemHeader(CE->getExprLoc()))298 return;299 300 auto *Ctor = CE->getConstructor();301 if (!Ctor)302 return;303 304 auto *Cls = Ctor->getParent();305 if (!Cls)306 return;307 308 if (!isRetainPtrOrOSPtr(safeGetName(Cls)) || !CE->getNumArgs())309 return;310 311 // Ignore RetainPtr construction inside adoptNS, adoptCF, and retainPtr.312 if (isAdoptFn(DeclWithIssue) || safeGetName(DeclWithIssue) == "retainPtr")313 return;314 315 std::string Name = "RetainPtr constructor";316 auto *Arg = CE->getArg(0)->IgnoreParenCasts();317 auto Result = isOwned(Arg);318 319 if (isCreateOrCopy(Arg))320 CreateOrCopyFnCall.insert(Arg); // Avoid double reporting.321 322 const Expr *Inner = nullptr;323 if (isAllocInit(Arg, &Inner)) {324 CreateOrCopyFnCall.insert(Arg);325 if (Inner)326 CreateOrCopyFnCall.insert(Inner);327 }328 329 if (Result == IsOwnedResult::Skip)330 return;331 332 if (Result == IsOwnedResult::Unknown)333 Result = IsOwnedResult::NotOwned;334 if (Result == IsOwnedResult::Owned)335 reportLeak(Name, CE, DeclWithIssue);336 else if (RTC.isARCEnabled() && isAllocInit(Arg))337 reportLeak(Name, CE, DeclWithIssue, "when ARC is disabled");338 else if (isCreateOrCopy(Arg))339 reportLeak(Name, CE, DeclWithIssue);340 }341 342 void visitVarDecl(const VarDecl *VD) const {343 auto *Init = VD->getInit();344 if (!Init || !RTC.isARCEnabled())345 return;346 Init = Init->IgnoreParenCasts();347 const Expr *Inner = nullptr;348 if (isAllocInit(Init, &Inner)) {349 CreateOrCopyFnCall.insert(Init);350 if (Inner)351 CreateOrCopyFnCall.insert(Inner);352 }353 }354 355 void visitBinaryOperator(const BinaryOperator *BO) const {356 if (!BO->isAssignmentOp())357 return;358 if (!isa<ObjCIvarRefExpr>(BO->getLHS()))359 return;360 auto *RHS = BO->getRHS()->IgnoreParenCasts();361 const Expr *Inner = nullptr;362 if (isAllocInit(RHS, &Inner)) {363 CreateOrCopyFnCall.insert(RHS);364 if (Inner)365 CreateOrCopyFnCall.insert(Inner);366 }367 }368 369 void visitReturnStmt(const ReturnStmt *RS, const Decl *DeclWithIssue) const {370 if (!DeclWithIssue)371 return;372 auto *RetValue = RS->getRetValue();373 if (!RetValue)374 return;375 RetValue = RetValue->IgnoreParenCasts();376 std::optional<bool> retainsRet;377 if (auto *FnDecl = dyn_cast<FunctionDecl>(DeclWithIssue))378 retainsRet = retainsReturnValue(FnDecl);379 else if (auto *MethodDecl = dyn_cast<ObjCMethodDecl>(DeclWithIssue))380 retainsRet = retainsReturnValue(MethodDecl);381 else382 return;383 if (!retainsRet || !*retainsRet) {384 // Under ARC, returning [[X alloc] init] doesn't leak X.385 if (RTC.isUnretained(RetValue->getType()))386 return;387 }388 if (retainsRet && *retainsRet) {389 CreateOrCopyFnCall.insert(RetValue);390 return;391 }392 if (auto *CE = dyn_cast<CallExpr>(RetValue)) {393 auto *Callee = CE->getDirectCallee();394 if (!Callee || !isCreateOrCopyFunction(Callee))395 return;396 CreateOrCopyFnCall.insert(CE);397 return;398 }399 const Expr *Inner = nullptr;400 if (isAllocInit(RetValue, &Inner)) {401 CreateOrCopyFnCall.insert(RetValue);402 if (Inner)403 CreateOrCopyFnCall.insert(Inner);404 }405 }406 407 template <typename CallableType>408 std::optional<bool> retainsReturnValue(const CallableType *FnDecl) const {409 auto Summary = Summaries->getSummary(AnyCall(FnDecl));410 auto RetEffect = Summary->getRetEffect();411 switch (RetEffect.getKind()) {412 case RetEffect::NoRet:413 return std::nullopt;414 case RetEffect::OwnedSymbol:415 return true;416 case RetEffect::NotOwnedSymbol:417 return false;418 case RetEffect::OwnedWhenTrackedReceiver:419 return std::nullopt;420 case RetEffect::NoRetHard:421 return std::nullopt;422 }423 return std::nullopt;424 }425 426 bool isAllocInit(const Expr *E, const Expr **InnerExpr = nullptr) const {427 auto *ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(E);428 if (auto *POE = dyn_cast<PseudoObjectExpr>(E)) {429 if (unsigned ExprCount = POE->getNumSemanticExprs()) {430 auto *Expr = POE->getSemanticExpr(ExprCount - 1)->IgnoreParenCasts();431 ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(Expr);432 if (InnerExpr)433 *InnerExpr = ObjCMsgExpr;434 }435 }436 if (!ObjCMsgExpr)437 return false;438 auto Selector = ObjCMsgExpr->getSelector();439 auto NameForFirstSlot = Selector.getNameForSlot(0);440 if (NameForFirstSlot == "alloc" || NameForFirstSlot.starts_with("copy") ||441 NameForFirstSlot.starts_with("mutableCopy"))442 return true;443 if (!NameForFirstSlot.starts_with("init") &&444 !NameForFirstSlot.starts_with("_init"))445 return false;446 if (!ObjCMsgExpr->isInstanceMessage())447 return false;448 auto *Receiver = ObjCMsgExpr->getInstanceReceiver();449 if (!Receiver)450 return false;451 Receiver = Receiver->IgnoreParenCasts();452 if (auto *Inner = dyn_cast<ObjCMessageExpr>(Receiver)) {453 if (InnerExpr)454 *InnerExpr = Inner;455 auto InnerSelector = Inner->getSelector();456 return InnerSelector.getNameForSlot(0) == "alloc";457 } else if (auto *CE = dyn_cast<CallExpr>(Receiver)) {458 if (InnerExpr)459 *InnerExpr = CE;460 if (auto *Callee = CE->getDirectCallee()) {461 if (Callee->getDeclName().isIdentifier()) {462 auto CalleeName = Callee->getName();463 return CalleeName.starts_with("alloc");464 }465 }466 }467 return false;468 }469 470 bool isCreateOrCopy(const Expr *E) const {471 auto *CE = dyn_cast<CallExpr>(E);472 if (!CE)473 return false;474 auto *Callee = CE->getDirectCallee();475 if (!Callee)476 return false;477 return isCreateOrCopyFunction(Callee);478 }479 480 bool isCreateOrCopyFunction(const FunctionDecl *FnDecl) const {481 auto CalleeName = safeGetName(FnDecl);482 return CalleeName.find("Create") != std::string::npos ||483 CalleeName.find("Copy") != std::string::npos;484 }485 486 enum class IsOwnedResult { Unknown, Skip, Owned, NotOwned };487 IsOwnedResult isOwned(const Expr *E) const {488 while (1) {489 if (auto *POE = dyn_cast<PseudoObjectExpr>(E)) {490 if (unsigned SemanticExprCount = POE->getNumSemanticExprs()) {491 E = POE->getSemanticExpr(SemanticExprCount - 1);492 continue;493 }494 }495 if (isNullPtr(E))496 return IsOwnedResult::NotOwned;497 if (auto *DRE = dyn_cast<DeclRefExpr>(E)) {498 auto QT = DRE->getType();499 if (isRetainPtrOrOSPtrType(QT))500 return IsOwnedResult::NotOwned;501 QT = QT.getCanonicalType();502 if (RTC.isUnretained(QT, true /* ignoreARC */))503 return IsOwnedResult::NotOwned;504 auto *PointeeType = QT->getPointeeType().getTypePtrOrNull();505 if (PointeeType && PointeeType->isVoidType())506 return IsOwnedResult::NotOwned; // Assume reading void* as +0.507 }508 if (auto *TE = dyn_cast<CXXBindTemporaryExpr>(E)) {509 E = TE->getSubExpr();510 continue;511 }512 if (auto *ObjCMsgExpr = dyn_cast<ObjCMessageExpr>(E)) {513 auto Summary = Summaries->getSummary(AnyCall(ObjCMsgExpr));514 auto RetEffect = Summary->getRetEffect();515 switch (RetEffect.getKind()) {516 case RetEffect::NoRet:517 return IsOwnedResult::Unknown;518 case RetEffect::OwnedSymbol:519 return IsOwnedResult::Owned;520 case RetEffect::NotOwnedSymbol:521 return IsOwnedResult::NotOwned;522 case RetEffect::OwnedWhenTrackedReceiver:523 if (auto *Receiver = ObjCMsgExpr->getInstanceReceiver()) {524 E = Receiver->IgnoreParenCasts();525 continue;526 }527 return IsOwnedResult::Unknown;528 case RetEffect::NoRetHard:529 return IsOwnedResult::Unknown;530 }531 }532 if (auto *CXXCE = dyn_cast<CXXMemberCallExpr>(E)) {533 if (auto *MD = CXXCE->getMethodDecl()) {534 auto *Cls = MD->getParent();535 if (auto *CD = dyn_cast<CXXConversionDecl>(MD)) {536 auto QT = CD->getConversionType().getCanonicalType();537 auto *ResultType = QT.getTypePtrOrNull();538 if (isRetainPtrOrOSPtr(safeGetName(Cls)) && ResultType &&539 (ResultType->isPointerType() || ResultType->isReferenceType() ||540 ResultType->isObjCObjectPointerType()))541 return IsOwnedResult::NotOwned;542 }543 if (safeGetName(MD) == "leakRef" &&544 isRetainPtrOrOSPtr(safeGetName(Cls)))545 return IsOwnedResult::Owned;546 }547 }548 if (auto *CE = dyn_cast<CallExpr>(E)) {549 if (auto *Callee = CE->getDirectCallee()) {550 if (isAdoptFn(Callee))551 return IsOwnedResult::NotOwned;552 auto Name = safeGetName(Callee);553 if (Name == "__builtin___CFStringMakeConstantString")554 return IsOwnedResult::NotOwned;555 if ((Name == "checked_cf_cast" || Name == "dynamic_cf_cast" ||556 Name == "checked_objc_cast" || Name == "dynamic_objc_cast") &&557 CE->getNumArgs() == 1) {558 E = CE->getArg(0)->IgnoreParenCasts();559 continue;560 }561 auto RetType = Callee->getReturnType();562 if (isRetainPtrOrOSPtrType(RetType))563 return IsOwnedResult::NotOwned;564 if (isCreateOrCopyFunction(Callee)) {565 CreateOrCopyFnCall.insert(CE);566 return IsOwnedResult::Owned;567 }568 } else if (auto *CalleeExpr = CE->getCallee()) {569 if (isa<CXXDependentScopeMemberExpr>(CalleeExpr))570 return IsOwnedResult::Skip; // Wait for instantiation.571 if (isa<UnresolvedLookupExpr>(CalleeExpr))572 return IsOwnedResult::Skip; // Wait for instantiation.573 }574 auto Summary = Summaries->getSummary(AnyCall(CE));575 auto RetEffect = Summary->getRetEffect();576 switch (RetEffect.getKind()) {577 case RetEffect::NoRet:578 return IsOwnedResult::Unknown;579 case RetEffect::OwnedSymbol:580 return IsOwnedResult::Owned;581 case RetEffect::NotOwnedSymbol:582 return IsOwnedResult::NotOwned;583 case RetEffect::OwnedWhenTrackedReceiver:584 return IsOwnedResult::Unknown;585 case RetEffect::NoRetHard:586 return IsOwnedResult::Unknown;587 }588 }589 break;590 }591 return IsOwnedResult::Unknown;592 }593 594 void reportUseAfterFree(const std::string &Name, const CallExpr *CE,595 const Decl *DeclWithIssue,596 const char *condition = nullptr) const {597 SmallString<100> Buf;598 llvm::raw_svector_ostream Os(Buf);599 600 Os << "Incorrect use of " << Name601 << ". The argument is +0 and results in an use-after-free";602 if (condition)603 Os << " " << condition;604 Os << ".";605 606 assert(BR && "expected nonnull BugReporter");607 PathDiagnosticLocation BSLoc(CE->getSourceRange().getBegin(),608 BR->getSourceManager());609 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);610 Report->addRange(CE->getSourceRange());611 Report->setDeclWithIssue(DeclWithIssue);612 BR->emitReport(std::move(Report));613 }614 615 void reportLeak(std::string &Name, const CXXConstructExpr *CE,616 const Decl *DeclWithIssue,617 const char *condition = nullptr) const {618 SmallString<100> Buf;619 llvm::raw_svector_ostream Os(Buf);620 621 Os << "Incorrect use of " << Name622 << ". The argument is +1 and results in a memory leak";623 if (condition)624 Os << " " << condition;625 Os << ".";626 627 assert(BR && "expected nonnull BugReporter");628 PathDiagnosticLocation BSLoc(CE->getSourceRange().getBegin(),629 BR->getSourceManager());630 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);631 Report->addRange(CE->getSourceRange());632 Report->setDeclWithIssue(DeclWithIssue);633 BR->emitReport(std::move(Report));634 }635 636 template <typename ExprType>637 void reportLeak(const ExprType *E, const Decl *DeclWithIssue) const {638 SmallString<100> Buf;639 llvm::raw_svector_ostream Os(Buf);640 641 Os << "The return value is +1 and results in a memory leak.";642 643 PathDiagnosticLocation BSLoc(E->getSourceRange().getBegin(),644 BR->getSourceManager());645 auto Report = std::make_unique<BasicBugReport>(Bug, Os.str(), BSLoc);646 Report->addRange(E->getSourceRange());647 Report->setDeclWithIssue(DeclWithIssue);648 BR->emitReport(std::move(Report));649 }650};651} // namespace652 653void ento::registerRetainPtrCtorAdoptChecker(CheckerManager &Mgr) {654 Mgr.registerChecker<RetainPtrCtorAdoptChecker>();655}656 657bool ento::shouldRegisterRetainPtrCtorAdoptChecker(const CheckerManager &mgr) {658 return true;659}660