• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //===---  BugReporter.h - Generate PathDiagnostics --------------*- 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 BugReporter, a utility class for generating
11 //  PathDiagnostics for analyses based on GRState.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #ifndef LLVM_CLANG_GR_BUGREPORTER
16 #define LLVM_CLANG_GR_BUGREPORTER
17 
18 #include "clang/Basic/SourceLocation.h"
19 #include "clang/StaticAnalyzer/Core/PathSensitive/GRState.h"
20 #include "llvm/ADT/FoldingSet.h"
21 #include "llvm/ADT/ImmutableList.h"
22 #include "llvm/ADT/ImmutableSet.h"
23 #include "llvm/ADT/SmallSet.h"
24 #include <list>
25 
26 namespace clang {
27 
28 class ASTContext;
29 class Diagnostic;
30 class Stmt;
31 class ParentMap;
32 
33 namespace ento {
34 
35 class PathDiagnostic;
36 class PathDiagnosticPiece;
37 class PathDiagnosticClient;
38 class ExplodedNode;
39 class ExplodedGraph;
40 class BugReporter;
41 class BugReporterContext;
42 class ExprEngine;
43 class GRState;
44 class BugType;
45 
46 //===----------------------------------------------------------------------===//
47 // Interface for individual bug reports.
48 //===----------------------------------------------------------------------===//
49 
50 class BugReporterVisitor : public llvm::FoldingSetNode {
51 public:
52   virtual ~BugReporterVisitor();
53   virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
54                                          const ExplodedNode* PrevN,
55                                          BugReporterContext& BRC) = 0;
56 
isOwnedByReporterContext()57   virtual bool isOwnedByReporterContext() { return true; }
58   virtual void Profile(llvm::FoldingSetNodeID &ID) const = 0;
59 };
60 
61 // FIXME: Combine this with RangedBugReport and remove RangedBugReport.
62 class BugReport : public BugReporterVisitor {
63 protected:
64   BugType& BT;
65   std::string ShortDescription;
66   std::string Description;
67   const ExplodedNode *ErrorNode;
68   mutable SourceRange R;
69 
70 protected:
71   friend class BugReporter;
72   friend class BugReportEquivClass;
73 
Profile(llvm::FoldingSetNodeID & hash)74   virtual void Profile(llvm::FoldingSetNodeID& hash) const {
75     hash.AddPointer(&BT);
76     hash.AddInteger(getLocation().getRawEncoding());
77     hash.AddString(Description);
78   }
79 
80 public:
81   class NodeResolver {
82   public:
~NodeResolver()83     virtual ~NodeResolver() {}
84     virtual const ExplodedNode*
85             getOriginalNode(const ExplodedNode* N) = 0;
86   };
87 
BugReport(BugType & bt,llvm::StringRef desc,const ExplodedNode * errornode)88   BugReport(BugType& bt, llvm::StringRef desc, const ExplodedNode *errornode)
89     : BT(bt), Description(desc), ErrorNode(errornode) {}
90 
BugReport(BugType & bt,llvm::StringRef shortDesc,llvm::StringRef desc,const ExplodedNode * errornode)91   BugReport(BugType& bt, llvm::StringRef shortDesc, llvm::StringRef desc,
92             const ExplodedNode *errornode)
93   : BT(bt), ShortDescription(shortDesc), Description(desc),
94     ErrorNode(errornode) {}
95 
96   virtual ~BugReport();
97 
isOwnedByReporterContext()98   virtual bool isOwnedByReporterContext() { return false; }
99 
getBugType()100   const BugType& getBugType() const { return BT; }
getBugType()101   BugType& getBugType() { return BT; }
102 
103   // FIXME: Perhaps this should be moved into a subclass?
getErrorNode()104   const ExplodedNode* getErrorNode() const { return ErrorNode; }
105 
106   // FIXME: Do we need this?  Maybe getLocation() should return a ProgramPoint
107   // object.
108   // FIXME: If we do need it, we can probably just make it private to
109   // BugReporter.
110   const Stmt* getStmt() const;
111 
getDescription()112   const llvm::StringRef getDescription() const { return Description; }
113 
getShortDescription()114   const llvm::StringRef getShortDescription() const {
115     return ShortDescription.empty() ? Description : ShortDescription;
116   }
117 
118   // FIXME: Is this needed?
getExtraDescriptiveText()119   virtual std::pair<const char**,const char**> getExtraDescriptiveText() {
120     return std::make_pair((const char**)0,(const char**)0);
121   }
122 
123   // FIXME: Perhaps move this into a subclass.
124   virtual PathDiagnosticPiece* getEndPath(BugReporterContext& BRC,
125                                           const ExplodedNode* N);
126 
127   /// getLocation - Return the "definitive" location of the reported bug.
128   ///  While a bug can span an entire path, usually there is a specific
129   ///  location that can be used to identify where the key issue occurred.
130   ///  This location is used by clients rendering diagnostics.
131   virtual SourceLocation getLocation() const;
132 
133   typedef const SourceRange *ranges_iterator;
134 
135   /// getRanges - Returns the source ranges associated with this bug.
136   virtual std::pair<ranges_iterator, ranges_iterator> getRanges() const;
137 
138   virtual PathDiagnosticPiece* VisitNode(const ExplodedNode* N,
139                                          const ExplodedNode* PrevN,
140                                          BugReporterContext& BR);
141 
registerInitialVisitors(BugReporterContext & BRC,const ExplodedNode * N)142   virtual void registerInitialVisitors(BugReporterContext& BRC,
143                                        const ExplodedNode* N) {}
144 };
145 
146 //===----------------------------------------------------------------------===//
147 // BugTypes (collections of related reports).
148 //===----------------------------------------------------------------------===//
149 
150 class BugReportEquivClass : public llvm::FoldingSetNode {
151   // List of *owned* BugReport objects.
152   std::list<BugReport*> Reports;
153 
154   friend class BugReporter;
AddReport(BugReport * R)155   void AddReport(BugReport* R) { Reports.push_back(R); }
156 public:
BugReportEquivClass(BugReport * R)157   BugReportEquivClass(BugReport* R) { Reports.push_back(R); }
158   ~BugReportEquivClass();
159 
Profile(llvm::FoldingSetNodeID & ID)160   void Profile(llvm::FoldingSetNodeID& ID) const {
161     assert(!Reports.empty());
162     (*Reports.begin())->Profile(ID);
163   }
164 
165   class iterator {
166     std::list<BugReport*>::iterator impl;
167   public:
iterator(std::list<BugReport * >::iterator i)168     iterator(std::list<BugReport*>::iterator i) : impl(i) {}
169     iterator& operator++() { ++impl; return *this; }
170     bool operator==(const iterator& I) const { return I.impl == impl; }
171     bool operator!=(const iterator& I) const { return I.impl != impl; }
172     BugReport* operator*() const { return *impl; }
173     BugReport* operator->() const { return *impl; }
174   };
175 
176   class const_iterator {
177     std::list<BugReport*>::const_iterator impl;
178   public:
const_iterator(std::list<BugReport * >::const_iterator i)179     const_iterator(std::list<BugReport*>::const_iterator i) : impl(i) {}
180     const_iterator& operator++() { ++impl; return *this; }
181     bool operator==(const const_iterator& I) const { return I.impl == impl; }
182     bool operator!=(const const_iterator& I) const { return I.impl != impl; }
183     const BugReport* operator*() const { return *impl; }
184     const BugReport* operator->() const { return *impl; }
185   };
186 
begin()187   iterator begin() { return iterator(Reports.begin()); }
end()188   iterator end() { return iterator(Reports.end()); }
189 
begin()190   const_iterator begin() const { return const_iterator(Reports.begin()); }
end()191   const_iterator end() const { return const_iterator(Reports.end()); }
192 };
193 
194 
195 //===----------------------------------------------------------------------===//
196 // Specialized subclasses of BugReport.
197 //===----------------------------------------------------------------------===//
198 
199 // FIXME: Collapse this with the default BugReport class.
200 class RangedBugReport : public BugReport {
201   llvm::SmallVector<SourceRange, 4> Ranges;
202 public:
RangedBugReport(BugType & D,llvm::StringRef description,ExplodedNode * errornode)203   RangedBugReport(BugType& D, llvm::StringRef description,
204                   ExplodedNode *errornode)
205     : BugReport(D, description, errornode) {}
206 
RangedBugReport(BugType & D,llvm::StringRef shortDescription,llvm::StringRef description,ExplodedNode * errornode)207   RangedBugReport(BugType& D, llvm::StringRef shortDescription,
208                   llvm::StringRef description, ExplodedNode *errornode)
209   : BugReport(D, shortDescription, description, errornode) {}
210 
211   ~RangedBugReport();
212 
213   // FIXME: Move this out of line.
addRange(SourceRange R)214   void addRange(SourceRange R) {
215     assert(R.isValid());
216     Ranges.push_back(R);
217   }
218 
getRanges()219   virtual std::pair<ranges_iterator, ranges_iterator> getRanges() const {
220     return std::make_pair(Ranges.begin(), Ranges.end());
221   }
222 
Profile(llvm::FoldingSetNodeID & hash)223   virtual void Profile(llvm::FoldingSetNodeID& hash) const {
224     BugReport::Profile(hash);
225     for (llvm::SmallVectorImpl<SourceRange>::const_iterator I =
226           Ranges.begin(), E = Ranges.end(); I != E; ++I) {
227       const SourceRange range = *I;
228       if (!range.isValid())
229         continue;
230       hash.AddInteger(range.getBegin().getRawEncoding());
231       hash.AddInteger(range.getEnd().getRawEncoding());
232     }
233   }
234 };
235 
236 class EnhancedBugReport : public RangedBugReport {
237 public:
238   typedef void (*VisitorCreator)(BugReporterContext &BRcC, const void *data,
239                                  const ExplodedNode *N);
240 
241 private:
242   typedef std::vector<std::pair<VisitorCreator, const void*> > Creators;
243   Creators creators;
244 
245 public:
EnhancedBugReport(BugType & D,llvm::StringRef description,ExplodedNode * errornode)246   EnhancedBugReport(BugType& D, llvm::StringRef description,
247                     ExplodedNode *errornode)
248    : RangedBugReport(D, description, errornode) {}
249 
EnhancedBugReport(BugType & D,llvm::StringRef shortDescription,llvm::StringRef description,ExplodedNode * errornode)250   EnhancedBugReport(BugType& D, llvm::StringRef shortDescription,
251                    llvm::StringRef description, ExplodedNode *errornode)
252     : RangedBugReport(D, shortDescription, description, errornode) {}
253 
~EnhancedBugReport()254   ~EnhancedBugReport() {}
255 
registerInitialVisitors(BugReporterContext & BRC,const ExplodedNode * N)256   void registerInitialVisitors(BugReporterContext& BRC, const ExplodedNode* N) {
257     for (Creators::iterator I = creators.begin(), E = creators.end(); I!=E; ++I)
258       I->first(BRC, I->second, N);
259   }
260 
addVisitorCreator(VisitorCreator creator,const void * data)261   void addVisitorCreator(VisitorCreator creator, const void *data) {
262     creators.push_back(std::make_pair(creator, data));
263   }
264 };
265 
266 //===----------------------------------------------------------------------===//
267 // BugReporter and friends.
268 //===----------------------------------------------------------------------===//
269 
270 class BugReporterData {
271 public:
272   virtual ~BugReporterData();
273   virtual Diagnostic& getDiagnostic() = 0;
274   virtual PathDiagnosticClient* getPathDiagnosticClient() = 0;
275   virtual ASTContext& getASTContext() = 0;
276   virtual SourceManager& getSourceManager() = 0;
277 };
278 
279 class BugReporter {
280 public:
281   enum Kind { BaseBRKind, GRBugReporterKind };
282 
283 private:
284   typedef llvm::ImmutableSet<BugType*> BugTypesTy;
285   BugTypesTy::Factory F;
286   BugTypesTy BugTypes;
287 
288   const Kind kind;
289   BugReporterData& D;
290 
291   void FlushReport(BugReportEquivClass& EQ);
292 
293   llvm::FoldingSet<BugReportEquivClass> EQClasses;
294 
295 protected:
BugReporter(BugReporterData & d,Kind k)296   BugReporter(BugReporterData& d, Kind k) : BugTypes(F.getEmptySet()), kind(k),
297                                             D(d) {}
298 
299 public:
BugReporter(BugReporterData & d)300   BugReporter(BugReporterData& d) : BugTypes(F.getEmptySet()), kind(BaseBRKind),
301                                     D(d) {}
302   virtual ~BugReporter();
303 
304   void FlushReports();
305 
getKind()306   Kind getKind() const { return kind; }
307 
getDiagnostic()308   Diagnostic& getDiagnostic() {
309     return D.getDiagnostic();
310   }
311 
getPathDiagnosticClient()312   PathDiagnosticClient* getPathDiagnosticClient() {
313     return D.getPathDiagnosticClient();
314   }
315 
316   typedef BugTypesTy::iterator iterator;
begin()317   iterator begin() { return BugTypes.begin(); }
end()318   iterator end() { return BugTypes.end(); }
319 
320   typedef llvm::FoldingSet<BugReportEquivClass>::iterator EQClasses_iterator;
EQClasses_begin()321   EQClasses_iterator EQClasses_begin() { return EQClasses.begin(); }
EQClasses_end()322   EQClasses_iterator EQClasses_end() { return EQClasses.end(); }
323 
getContext()324   ASTContext& getContext() { return D.getASTContext(); }
325 
getSourceManager()326   SourceManager& getSourceManager() { return D.getSourceManager(); }
327 
GeneratePathDiagnostic(PathDiagnostic & pathDiagnostic,llvm::SmallVectorImpl<BugReport * > & bugReports)328   virtual void GeneratePathDiagnostic(PathDiagnostic& pathDiagnostic,
329         llvm::SmallVectorImpl<BugReport *> &bugReports) {}
330 
331   void Register(BugType *BT);
332 
333   void EmitReport(BugReport *R);
334 
335   void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
336                        SourceLocation Loc,
337                        SourceRange* RangeBeg, unsigned NumRanges);
338 
339   void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory,
340                        llvm::StringRef BugStr, SourceLocation Loc,
341                        SourceRange* RangeBeg, unsigned NumRanges);
342 
343 
EmitBasicReport(llvm::StringRef BugName,llvm::StringRef BugStr,SourceLocation Loc)344   void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
345                        SourceLocation Loc) {
346     EmitBasicReport(BugName, BugStr, Loc, 0, 0);
347   }
348 
EmitBasicReport(llvm::StringRef BugName,llvm::StringRef BugCategory,llvm::StringRef BugStr,SourceLocation Loc)349   void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugCategory,
350                        llvm::StringRef BugStr, SourceLocation Loc) {
351     EmitBasicReport(BugName, BugCategory, BugStr, Loc, 0, 0);
352   }
353 
EmitBasicReport(llvm::StringRef BugName,llvm::StringRef BugStr,SourceLocation Loc,SourceRange R)354   void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef BugStr,
355                        SourceLocation Loc, SourceRange R) {
356     EmitBasicReport(BugName, BugStr, Loc, &R, 1);
357   }
358 
EmitBasicReport(llvm::StringRef BugName,llvm::StringRef Category,llvm::StringRef BugStr,SourceLocation Loc,SourceRange R)359   void EmitBasicReport(llvm::StringRef BugName, llvm::StringRef Category,
360                        llvm::StringRef BugStr, SourceLocation Loc,
361                        SourceRange R) {
362     EmitBasicReport(BugName, Category, BugStr, Loc, &R, 1);
363   }
364 
classof(const BugReporter * R)365   static bool classof(const BugReporter* R) { return true; }
366 
367 private:
368   llvm::StringMap<BugType *> StrBugTypes;
369 
370   /// \brief Returns a BugType that is associated with the given name and
371   /// category.
372   BugType *getBugTypeForName(llvm::StringRef name, llvm::StringRef category);
373 };
374 
375 // FIXME: Get rid of GRBugReporter.  It's the wrong abstraction.
376 class GRBugReporter : public BugReporter {
377   ExprEngine& Eng;
378   llvm::SmallSet<SymbolRef, 10> NotableSymbols;
379 public:
GRBugReporter(BugReporterData & d,ExprEngine & eng)380   GRBugReporter(BugReporterData& d, ExprEngine& eng)
381     : BugReporter(d, GRBugReporterKind), Eng(eng) {}
382 
383   virtual ~GRBugReporter();
384 
385   /// getEngine - Return the analysis engine used to analyze a given
386   ///  function or method.
getEngine()387   ExprEngine &getEngine() { return Eng; }
388 
389   /// getGraph - Get the exploded graph created by the analysis engine
390   ///  for the analyzed method or function.
391   ExplodedGraph &getGraph();
392 
393   /// getStateManager - Return the state manager used by the analysis
394   ///  engine.
395   GRStateManager &getStateManager();
396 
397   virtual void GeneratePathDiagnostic(PathDiagnostic &pathDiagnostic,
398                      llvm::SmallVectorImpl<BugReport*> &bugReports);
399 
addNotableSymbol(SymbolRef Sym)400   void addNotableSymbol(SymbolRef Sym) {
401     NotableSymbols.insert(Sym);
402   }
403 
isNotable(SymbolRef Sym)404   bool isNotable(SymbolRef Sym) const {
405     return (bool) NotableSymbols.count(Sym);
406   }
407 
408   /// classof - Used by isa<>, cast<>, and dyn_cast<>.
classof(const BugReporter * R)409   static bool classof(const BugReporter* R) {
410     return R->getKind() == GRBugReporterKind;
411   }
412 };
413 
414 class BugReporterContext {
415   GRBugReporter &BR;
416   // Not the most efficient data structure, but we use an ImmutableList for the
417   // Callbacks because it is safe to make additions to list during iteration.
418   llvm::ImmutableList<BugReporterVisitor*>::Factory F;
419   llvm::ImmutableList<BugReporterVisitor*> Callbacks;
420   llvm::FoldingSet<BugReporterVisitor> CallbacksSet;
421 public:
BugReporterContext(GRBugReporter & br)422   BugReporterContext(GRBugReporter& br) : BR(br), Callbacks(F.getEmptyList()) {}
423   virtual ~BugReporterContext();
424 
425   void addVisitor(BugReporterVisitor* visitor);
426 
427   typedef llvm::ImmutableList<BugReporterVisitor*>::iterator visitor_iterator;
visitor_begin()428   visitor_iterator visitor_begin() { return Callbacks.begin(); }
visitor_end()429   visitor_iterator visitor_end() { return Callbacks.end(); }
430 
getBugReporter()431   GRBugReporter& getBugReporter() { return BR; }
432 
getGraph()433   ExplodedGraph &getGraph() { return BR.getGraph(); }
434 
addNotableSymbol(SymbolRef Sym)435   void addNotableSymbol(SymbolRef Sym) {
436     // FIXME: For now forward to GRBugReporter.
437     BR.addNotableSymbol(Sym);
438   }
439 
isNotable(SymbolRef Sym)440   bool isNotable(SymbolRef Sym) const {
441     // FIXME: For now forward to GRBugReporter.
442     return BR.isNotable(Sym);
443   }
444 
getStateManager()445   GRStateManager& getStateManager() {
446     return BR.getStateManager();
447   }
448 
getSValBuilder()449   SValBuilder& getSValBuilder() {
450     return getStateManager().getSValBuilder();
451   }
452 
getASTContext()453   ASTContext& getASTContext() {
454     return BR.getContext();
455   }
456 
getSourceManager()457   SourceManager& getSourceManager() {
458     return BR.getSourceManager();
459   }
460 
461   virtual BugReport::NodeResolver& getNodeResolver() = 0;
462 };
463 
464 class DiagBugReport : public RangedBugReport {
465   std::list<std::string> Strs;
466   FullSourceLoc L;
467 public:
DiagBugReport(BugType & D,llvm::StringRef desc,FullSourceLoc l)468   DiagBugReport(BugType& D, llvm::StringRef desc, FullSourceLoc l) :
469   RangedBugReport(D, desc, 0), L(l) {}
470 
~DiagBugReport()471   virtual ~DiagBugReport() {}
472 
473   // FIXME: Move out-of-line (virtual function).
getLocation()474   SourceLocation getLocation() const { return L; }
475 
addString(llvm::StringRef s)476   void addString(llvm::StringRef s) { Strs.push_back(s); }
477 
478   typedef std::list<std::string>::const_iterator str_iterator;
str_begin()479   str_iterator str_begin() const { return Strs.begin(); }
str_end()480   str_iterator str_end() const { return Strs.end(); }
481 };
482 
483 //===----------------------------------------------------------------------===//
484 //===----------------------------------------------------------------------===//
485 
486 namespace bugreporter {
487 
488 const Stmt *GetDerefExpr(const ExplodedNode *N);
489 const Stmt *GetDenomExpr(const ExplodedNode *N);
490 const Stmt *GetCalleeExpr(const ExplodedNode *N);
491 const Stmt *GetRetValExpr(const ExplodedNode *N);
492 
493 void registerTrackNullOrUndefValue(BugReporterContext& BRC, const void *stmt,
494                                    const ExplodedNode* N);
495 
496 void registerFindLastStore(BugReporterContext& BRC, const void *memregion,
497                            const ExplodedNode *N);
498 
499 void registerNilReceiverVisitor(BugReporterContext &BRC);
500 
501 void registerVarDeclsLastStore(BugReporterContext &BRC, const void *stmt,
502                                const ExplodedNode *N);
503 
504 } // end namespace clang::bugreporter
505 
506 //===----------------------------------------------------------------------===//
507 
508 } // end GR namespace
509 
510 } // end clang namespace
511 
512 #endif
513