aboutsummaryrefslogtreecommitdiff
path: root/lib/StaticAnalyzer/Checkers/RetainCountChecker/RetainCountDiagnostics.h
blob: 8634c37c34005321af492e2d02b7740a80098c8f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
//== RetainCountDiagnostics.h - Checks for leaks and other issues -*- C++ -*--//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
//  This file defines diagnostics for RetainCountChecker, which implements
//  a reference count checker for Core Foundation and Cocoa on (Mac OS X).
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_DIAGNOSTICS_H
#define LLVM_CLANG_LIB_STATICANALYZER_CHECKERS_RETAINCOUNTCHECKER_DIAGNOSTICS_H

#include "clang/Analysis/RetainSummaryManager.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugType.h"
#include "clang/StaticAnalyzer/Core/BugReporter/BugReporterVisitors.h"
#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h"

namespace clang {
namespace ento {
namespace retaincountchecker {

class CFRefBug : public BugType {
protected:
  CFRefBug(const CheckerBase *checker, StringRef name)
      : BugType(checker, name, categories::MemoryCoreFoundationObjectiveC) {}

public:

  // FIXME: Eventually remove.
  virtual const char *getDescription() const = 0;

  virtual bool isLeak() const { return false; }
};

class UseAfterRelease : public CFRefBug {
public:
  UseAfterRelease(const CheckerBase *checker)
      : CFRefBug(checker, "Use-after-release") {}

  const char *getDescription() const override {
    return "Reference-counted object is used after it is released";
  }
};

class BadRelease : public CFRefBug {
public:
  BadRelease(const CheckerBase *checker) : CFRefBug(checker, "Bad release") {}

  const char *getDescription() const override {
    return "Incorrect decrement of the reference count of an object that is "
           "not owned at this point by the caller";
  }
};

class DeallocNotOwned : public CFRefBug {
public:
  DeallocNotOwned(const CheckerBase *checker)
      : CFRefBug(checker, "-dealloc sent to non-exclusively owned object") {}

  const char *getDescription() const override {
    return "-dealloc sent to object that may be referenced elsewhere";
  }
};

class OverAutorelease : public CFRefBug {
public:
  OverAutorelease(const CheckerBase *checker)
      : CFRefBug(checker, "Object autoreleased too many times") {}

  const char *getDescription() const override {
    return "Object autoreleased too many times";
  }
};

class ReturnedNotOwnedForOwned : public CFRefBug {
public:
  ReturnedNotOwnedForOwned(const CheckerBase *checker)
      : CFRefBug(checker, "Method should return an owned object") {}

  const char *getDescription() const override {
    return "Object with a +0 retain count returned to caller where a +1 "
           "(owning) retain count is expected";
  }
};

class Leak : public CFRefBug {
public:
  Leak(const CheckerBase *checker, StringRef name) : CFRefBug(checker, name) {
    // Leaks should not be reported if they are post-dominated by a sink.
    setSuppressOnSink(true);
  }

  const char *getDescription() const override { return ""; }

  bool isLeak() const override { return true; }
};

typedef ::llvm::DenseMap<const ExplodedNode *, const RetainSummary *>
  SummaryLogTy;

/// Visitors.

class CFRefReportVisitor : public BugReporterVisitor {
protected:
  SymbolRef Sym;
  const SummaryLogTy &SummaryLog;

public:
  CFRefReportVisitor(SymbolRef sym, const SummaryLogTy &log)
     : Sym(sym), SummaryLog(log) {}

  void Profile(llvm::FoldingSetNodeID &ID) const override {
    static int x = 0;
    ID.AddPointer(&x);
    ID.AddPointer(Sym);
  }

  std::shared_ptr<PathDiagnosticPiece> VisitNode(const ExplodedNode *N,
                                                 const ExplodedNode *PrevN,
                                                 BugReporterContext &BRC,
                                                 BugReport &BR) override;

  std::shared_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
                                                  const ExplodedNode *N,
                                                  BugReport &BR) override;
};

class CFRefLeakReportVisitor : public CFRefReportVisitor {
public:
  CFRefLeakReportVisitor(SymbolRef sym,
                         const SummaryLogTy &log)
     : CFRefReportVisitor(sym, log) {}

  std::shared_ptr<PathDiagnosticPiece> getEndPath(BugReporterContext &BRC,
                                                  const ExplodedNode *N,
                                                  BugReport &BR) override;
};

class CFRefReport : public BugReport {

public:
  CFRefReport(CFRefBug &D, const LangOptions &LOpts,
              const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym,
              bool registerVisitor = true)
    : BugReport(D, D.getDescription(), n) {
    if (registerVisitor)
      addVisitor(llvm::make_unique<CFRefReportVisitor>(sym, Log));
  }

  CFRefReport(CFRefBug &D, const LangOptions &LOpts,
              const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym,
              StringRef endText)
    : BugReport(D, D.getDescription(), endText, n) {
    addVisitor(llvm::make_unique<CFRefReportVisitor>(sym, Log));
  }

  llvm::iterator_range<ranges_iterator> getRanges() override {
    const CFRefBug& BugTy = static_cast<CFRefBug&>(getBugType());
    if (!BugTy.isLeak())
      return BugReport::getRanges();
    return llvm::make_range(ranges_iterator(), ranges_iterator());
  }
};

class CFRefLeakReport : public CFRefReport {
  const MemRegion* AllocBinding;
  const Stmt *AllocStmt;

  // Finds the function declaration where a leak warning for the parameter
  // 'sym' should be raised.
  void deriveParamLocation(CheckerContext &Ctx, SymbolRef sym);
  // Finds the location where a leak warning for 'sym' should be raised.
  void deriveAllocLocation(CheckerContext &Ctx, SymbolRef sym);
  // Produces description of a leak warning which is printed on the console.
  void createDescription(CheckerContext &Ctx, bool IncludeAllocationLine);

public:
  CFRefLeakReport(CFRefBug &D, const LangOptions &LOpts,
                  const SummaryLogTy &Log, ExplodedNode *n, SymbolRef sym,
                  CheckerContext &Ctx,
                  bool IncludeAllocationLine);

  PathDiagnosticLocation getLocation(const SourceManager &SM) const override {
    assert(Location.isValid());
    return Location;
  }
};

} // end namespace retaincountchecker
} // end namespace ento
} // end namespace clang

#endif