RetainCountDiagnostics.cpp 35 KB

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