blob: a25cc12fb0936a9aacfa0d768bba435059a75245 [file] [log] [blame]
George Karpenkov70c2ee32018-08-17 21:41:07 +00001//== RetainCountDiagnostics.h - Checks for leaks and other issues -*- C++ -*--//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// This file defines diagnostics for RetainCountChecker, which implements
11// a reference count checker for Core Foundation and Cocoa on (Mac OS X).
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_DIAGNOSTICS_H
16#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_DIAGNOSTICS_H
17
George Karpenkov70c2ee32018-08-17 21:41:07 +000018#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
19#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
20#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"
George Karpenkovefef49c2018-08-21 03:09:02 +000021#include "clang/StaticAnalyzer/Core/RetainSummaryManager.h"
George Karpenkov70c2ee32018-08-17 21:41:07 +000022
23namespace clang {
24namespace ento {
25namespace retaincountchecker {
26
27class CFRefBug : public BugType {
28protected:
29 CFRefBug(const CheckerBase *checker, StringRef name)
30 : BugType(checker, name, categories::MemoryCoreFoundationObjectiveC) {}
31
32public:
33
34 // FIXME: Eventually remove.
35 virtual const char *getDescription() const = 0;
36
37 virtual bool isLeak() const { return false; }
38};
39
40class UseAfterRelease : public CFRefBug {
41public:
42 UseAfterRelease(const CheckerBase *checker)
43 : CFRefBug(checker, "Use-after-release") {}
44
45 const char *getDescription() const override {
46 return "Reference-counted object is used after it is released";
47 }
48};
49
50class BadRelease : public CFRefBug {
51public:
52 BadRelease(const CheckerBase *checker) : CFRefBug(checker, "Bad release") {}
53
54 const char *getDescription() const override {
55 return "Incorrect decrement of the reference count of an object that is "
56 "not owned at this point by the caller";
57 }
58};
59
60class DeallocNotOwned : public CFRefBug {
61public:
62 DeallocNotOwned(const CheckerBase *checker)
63 : CFRefBug(checker, "-dealloc sent to non-exclusively owned object") {}
64
65 const char *getDescription() const override {
66 return "-dealloc sent to object that may be referenced elsewhere";
67 }
68};
69
70class OverAutorelease : public CFRefBug {
71public:
72 OverAutorelease(const CheckerBase *checker)
73 : CFRefBug(checker, "Object autoreleased too many times") {}
74
75 const char *getDescription() const override {
76 return "Object autoreleased too many times";
77 }
78};
79
80class ReturnedNotOwnedForOwned : public CFRefBug {
81public:
82 ReturnedNotOwnedForOwned(const CheckerBase *checker)
83 : CFRefBug(checker, "Method should return an owned object") {}
84
85 const char *getDescription() const override {
86 return "Object with a +0 retain count returned to caller where a +1 "
87 "(owning) retain count is expected";
88 }
89};
90
91class Leak : public CFRefBug {
92public:
93 Leak(const CheckerBase *checker, StringRef name) : CFRefBug(checker, name) {
94 // Leaks should not be reported if they are post-dominated by a sink.
95 setSuppressOnSink(true);
96 }
97
98 const char *getDescription() const override { return ""; }
99
100 bool isLeak() const override { return true; }
101};
102
103typedef ::llvm::DenseMap<const ExplodedNode *, const RetainSummary *>
104 SummaryLogTy;
105
106/// Visitors.
107
108class CFRefReportVisitor : public BugReporterVisitor {
109protected:
110 SymbolRef Sym;
111 const SummaryLogTy &SummaryLog;
112
113public:
114 CFRefReportVisitor(SymbolRef sym, const SummaryLogTy &log)
115 : Sym(sym), SummaryLog(log) {}
116
117 void Profile(llvm::FoldingSetNodeID &ID) const override {
118 static int x = 0;
119 ID.AddPointer(&x);
120 ID.AddPointer(Sym);
121 }
122
123 std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
George Karpenkov70c2ee32018-08-17 21:41:07 +0000124 BugReporterContext &BRC,
125 BugReport &BR) override;
126
127 std::shared_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
128 const ExplodedNode *N,
129 BugReport &BR) override;
130};
131
132class CFRefLeakReportVisitor : public CFRefReportVisitor {
133public:
134 CFRefLeakReportVisitor(SymbolRef sym,
135 const SummaryLogTy &log)
136 : CFRefReportVisitor(sym, log) {}
137
138 std::shared_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
139 const ExplodedNode *N,
140 BugReport &BR) override;
141};
142
143class CFRefReport : public BugReport {
George Karpenkovf893ea12018-11-30 02:17:44 +0000144protected:
145 SymbolRef Sym;
George Karpenkov70c2ee32018-08-17 21:41:07 +0000146
147public:
148 CFRefReport(CFRefBug &D, const LangOptions &LOpts,
149 const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym,
150 bool registerVisitor = true)
George Karpenkovf893ea12018-11-30 02:17:44 +0000151 : BugReport(D, D.getDescription(), n), Sym(sym) {
George Karpenkov70c2ee32018-08-17 21:41:07 +0000152 if (registerVisitor)
153 addVisitor(llvm::make_unique<CFRefReportVisitor>(sym, Log));
154 }
155
156 CFRefReport(CFRefBug &D, const LangOptions &LOpts,
157 const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym,
158 StringRef endText)
159 : BugReport(D, D.getDescription(), endText, n) {
160 addVisitor(llvm::make_unique<CFRefReportVisitor>(sym, Log));
161 }
162
163 llvm::iterator_range<ranges_iterator> getRanges() override {
164 const CFRefBug& BugTy = static_cast<CFRefBug&>(getBugType());
165 if (!BugTy.isLeak())
166 return BugReport::getRanges();
167 return llvm::make_range(ranges_iterator(), ranges_iterator());
168 }
169};
170
171class CFRefLeakReport : public CFRefReport {
172 const MemRegion* AllocBinding;
173 const Stmt *AllocStmt;
174
175 // Finds the function declaration where a leak warning for the parameter
176 // 'sym' should be raised.
177 void deriveParamLocation(CheckerContext &Ctx, SymbolRef sym);
178 // Finds the location where a leak warning for 'sym' should be raised.
179 void deriveAllocLocation(CheckerContext &Ctx, SymbolRef sym);
180 // Produces description of a leak warning which is printed on the console.
181 void createDescription(CheckerContext &Ctx, bool IncludeAllocationLine);
182
183public:
184 CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
185 const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym,
186 CheckerContext &Ctx,
187 bool IncludeAllocationLine);
188
189 PathDiagnosticLocation getLocation(const SourceManager &SM) const override {
190 assert(Location.isValid());
191 return Location;
192 }
193};
194
195} // end namespace retaincountchecker
196} // end namespace ento
197} // end namespace clang
198
199#endif