clang 22.0.0git
RetainPtrCtorAdoptChecker.cpp
Go to the documentation of this file.
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"
18#include "llvm/ADT/DenseSet.h"
19#include <optional>
20
21using namespace clang;
22using namespace ento;
23
24namespace {
25
26class RetainPtrCtorAdoptChecker
27 : 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'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) {
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 else
194 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 RetainSummaryManager
254 // 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()) {
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;
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 else
382 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;
415 return true;
417 return false;
419 return std::nullopt;
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();
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;
519 return IsOwnedResult::Owned;
521 return IsOwnedResult::NotOwned;
523 if (auto *Receiver = ObjCMsgExpr->getInstanceReceiver()) {
524 E = Receiver->IgnoreParenCasts();
525 continue;
526 }
527 return IsOwnedResult::Unknown;
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" &&
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;
580 return IsOwnedResult::Owned;
582 return IsOwnedResult::NotOwned;
584 return IsOwnedResult::Unknown;
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 " << Name
601 << ". 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 " << Name
622 << ". 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} // namespace
652
653void ento::registerRetainPtrCtorAdoptChecker(CheckerManager &Mgr) {
654 Mgr.registerChecker<RetainPtrCtorAdoptChecker>();
655}
656
657bool ento::shouldRegisterRetainPtrCtorAdoptChecker(const CheckerManager &mgr) {
658 return true;
659}
static bool RetValue(InterpState &S, CodePtr &Pt)
Definition Interp.cpp:31
Expr * getLHS() const
Definition Expr.h:4022
Expr * getRHS() const
Definition Expr.h:4024
static bool isAssignmentOp(Opcode Opc)
Definition Expr.h:4108
Expr * getArg(unsigned Arg)
Return the specified argument.
Definition ExprCXX.h:1692
CXXConstructorDecl * getConstructor() const
Get the constructor that this expression will (ultimately) call.
Definition ExprCXX.h:1612
unsigned getNumArgs() const
Return the number of arguments to the constructor call.
Definition ExprCXX.h:1689
const CXXRecordDecl * getParent() const
Return the parent of this method declaration, which is the class in which this method is defined.
Definition DeclCXX.h:2255
Expr * getArg(unsigned Arg)
getArg - Return the specified argument.
Definition Expr.h:3081
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return null.
Definition Expr.h:3060
Expr * getCallee()
Definition Expr.h:3024
unsigned getNumArgs() const
getNumArgs - Return the number of actual arguments to this call.
Definition Expr.h:3068
Decl * getCalleeDecl()
Definition Expr.h:3054
FunctionDecl * getAsFunction() LLVM_READONLY
Returns the function itself, or the templated function if this is a function template.
Definition DeclBase.cpp:273
Expr * IgnoreParenCasts() LLVM_READONLY
Skip past any parentheses and casts which might surround this expression until reaching a fixed point...
Definition Expr.cpp:3090
SourceLocation getExprLoc() const LLVM_READONLY
getExprLoc - Return the preferred location for the arrow when diagnosing a problem with a generic exp...
Definition Expr.cpp:273
Expr * getInstanceReceiver()
Returns the object expression (receiver) for an instance message, or null for a message that is not a...
Definition ExprObjC.h:1268
Selector getSelector() const
Definition ExprObjC.cpp:289
bool isInstanceMessage() const
Determine whether this is an instance message to either a computed object or to super.
Definition ExprObjC.h:1256
void visitTypedef(const TypedefDecl *)
Expr * getRetValue()
Definition Stmt.h:3187
StringRef getNameForSlot(unsigned argIndex) const
Retrieve the name at a given position in the selector.
SourceLocation getBegin() const
SourceRange getSourceRange() const LLVM_READONLY
SourceLocation tokens are not useful in isolation - they are low level value objects created/interpre...
Definition Stmt.cpp:338
ASTContext & getASTContext() const
Definition Decl.h:141
const Expr * getInit() const
Definition Decl.h:1368
CHECKER * registerChecker(AT &&...Args)
Register a single-part checker (derived from Checker): construct its singleton instance,...
Simple checker classes that implement one frontend (i.e.
Definition Checker.h:553
@ OwnedSymbol
Indicates that the returned value is an owned (+1) symbol.
@ OwnedWhenTrackedReceiver
Indicates that the return value is an owned object when the receiver is also a tracked object.
@ NoRet
Indicates that no retain count information is tracked for the return value.
@ NotOwnedSymbol
Indicates that the returned value is an object with retain count semantics but that it is not owned (...
std::variant< struct RequiresDecl, struct HeaderDecl, struct UmbrellaDirDecl, struct ModuleDecl, struct ExcludeDecl, struct ExportDecl, struct ExportAsDecl, struct ExternModuleDecl, struct UseDecl, struct LinkDecl, struct ConfigMacrosDecl, struct ConflictDecl > Decl
All declarations that can appear in a module declaration.
The JSON file list parser is used to communicate input to InstallAPI.
bool isa(CodeGen::Address addr)
Definition Address.h:330
bool isRetainPtrOrOSPtrType(const clang::QualType T)
@ Result
The result type of a method or function.
Definition TypeBase.h:905
bool isRetainPtrOrOSPtr(const std::string &Name)
std::string safeGetName(const T *ASTNode)
Definition ASTUtils.h:91
bool isNullPtr(const clang::Expr *E)
Definition ASTUtils.cpp:270