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