blob: 83c2be8298c82008705c65097696d310732de86e [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,
124 const ExplodedNode *PrevN,
125 BugReporterContext &BRC,
126 BugReport &BR) override;
127
128 std::shared_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
129 const ExplodedNode *N,
130 BugReport &BR) override;
131};
132
133class CFRefLeakReportVisitor : public CFRefReportVisitor {
134public:
135 CFRefLeakReportVisitor(SymbolRef sym,
136 const SummaryLogTy &log)
137 : CFRefReportVisitor(sym, log) {}
138
139 std::shared_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
140 const ExplodedNode *N,
141 BugReport &BR) override;
142};
143
144class CFRefReport : public BugReport {
145
146public:
147 CFRefReport(CFRefBug &D, const LangOptions &LOpts,
148 const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym,
149 bool registerVisitor = true)
150 : BugReport(D, D.getDescription(), n) {
151 if (registerVisitor)
152 addVisitor(llvm::make_unique<CFRefReportVisitor>(sym, Log));
153 }
154
155 CFRefReport(CFRefBug &D, const LangOptions &LOpts,
156 const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym,
157 StringRef endText)
158 : BugReport(D, D.getDescription(), endText, n) {
159 addVisitor(llvm::make_unique<CFRefReportVisitor>(sym, Log));
160 }
161
162 llvm::iterator_range<ranges_iterator> getRanges() override {
163 const CFRefBug& BugTy = static_cast<CFRefBug&>(getBugType());
164 if (!BugTy.isLeak())
165 return BugReport::getRanges();
166 return llvm::make_range(ranges_iterator(), ranges_iterator());
167 }
168};
169
170class CFRefLeakReport : public CFRefReport {
171 const MemRegion* AllocBinding;
172 const Stmt *AllocStmt;
173
174 // Finds the function declaration where a leak warning for the parameter
175 // 'sym' should be raised.
176 void deriveParamLocation(CheckerContext &Ctx, SymbolRef sym);
177 // Finds the location where a leak warning for 'sym' should be raised.
178 void deriveAllocLocation(CheckerContext &Ctx, SymbolRef sym);
179 // Produces description of a leak warning which is printed on the console.
180 void createDescription(CheckerContext &Ctx, bool IncludeAllocationLine);
181
182public:
183 CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
184 const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym,
185 CheckerContext &Ctx,
186 bool IncludeAllocationLine);
187
188 PathDiagnosticLocation getLocation(const SourceManager &SM) const override {
189 assert(Location.isValid());
190 return Location;
191 }
192};
193
194} // end namespace retaincountchecker
195} // end namespace ento
196} // end namespace clang
197
198#endif