1 //===--- AnalysisConsumer.cpp - ASTConsumer for running Analyses ----------===// 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 // "Meta" ASTConsumer for running different source analyses. 11 // 12 //===----------------------------------------------------------------------===// 13 14 #define DEBUG_TYPE "AnalysisConsumer" 15 16 #include "AnalysisConsumer.h" 17 #include "clang/AST/ASTConsumer.h" 18 #include "clang/AST/Decl.h" 19 #include "clang/AST/DeclCXX.h" 20 #include "clang/AST/DeclObjC.h" 21 #include "clang/AST/ParentMap.h" 22 #include "clang/AST/RecursiveASTVisitor.h" 23 #include "clang/Analysis/Analyses/LiveVariables.h" 24 #include "clang/Analysis/CFG.h" 25 #include "clang/Analysis/CallGraph.h" 26 #include "clang/Basic/FileManager.h" 27 #include "clang/Basic/SourceManager.h" 28 #include "clang/Lex/Preprocessor.h" 29 #include "clang/StaticAnalyzer/Checkers/LocalCheckers.h" 30 #include "clang/StaticAnalyzer/Core/AnalyzerOptions.h" 31 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 32 #include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" 33 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 34 #include "clang/StaticAnalyzer/Core/PathDiagnosticConsumers.h" 35 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 36 #include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 37 #include "clang/StaticAnalyzer/Frontend/CheckerRegistration.h" 38 #include "llvm/ADT/DepthFirstIterator.h" 39 #include "llvm/ADT/OwningPtr.h" 40 #include "llvm/ADT/PostOrderIterator.h" 41 #include "llvm/ADT/SmallPtrSet.h" 42 #include "llvm/ADT/Statistic.h" 43 #include "llvm/Support/FileSystem.h" 44 #include "llvm/Support/Path.h" 45 #include "llvm/Support/Program.h" 46 #include "llvm/Support/Timer.h" 47 #include "llvm/Support/raw_ostream.h" 48 #include <queue> 49 50 using namespace clang; 51 using namespace ento; 52 using llvm::SmallPtrSet; 53 54 static ExplodedNode::Auditor* CreateUbiViz(); 55 56 STATISTIC(NumFunctionTopLevel, "The # of functions at top level."); 57 STATISTIC(NumFunctionsAnalyzed, 58 "The # of functions and blocks analyzed (as top level " 59 "with inlining turned on)."); 60 STATISTIC(NumBlocksInAnalyzedFunctions, 61 "The # of basic blocks in the analyzed functions."); 62 STATISTIC(PercentReachableBlocks, "The % of reachable basic blocks."); 63 STATISTIC(MaxCFGSize, "The maximum number of basic blocks in a function."); 64 65 //===----------------------------------------------------------------------===// 66 // Special PathDiagnosticConsumers. 67 //===----------------------------------------------------------------------===// 68 69 static void createPlistHTMLDiagnosticConsumer(AnalyzerOptions &AnalyzerOpts, 70 PathDiagnosticConsumers &C, 71 const std::string &prefix, 72 const Preprocessor &PP) { 73 createHTMLDiagnosticConsumer(AnalyzerOpts, C, 74 llvm::sys::path::parent_path(prefix), PP); 75 createPlistDiagnosticConsumer(AnalyzerOpts, C, prefix, PP); 76 } 77 78 namespace { 79 class ClangDiagPathDiagConsumer : public PathDiagnosticConsumer { 80 DiagnosticsEngine &Diag; 81 public: 82 ClangDiagPathDiagConsumer(DiagnosticsEngine &Diag) : Diag(Diag) {} 83 virtual ~ClangDiagPathDiagConsumer() {} 84 virtual StringRef getName() const { return "ClangDiags"; } 85 virtual PathGenerationScheme getGenerationScheme() const { return None; } 86 87 void FlushDiagnosticsImpl(std::vector<const PathDiagnostic *> &Diags, 88 FilesMade *filesMade) { 89 for (std::vector<const PathDiagnostic*>::iterator I = Diags.begin(), 90 E = Diags.end(); I != E; ++I) { 91 const PathDiagnostic *PD = *I; 92 StringRef desc = PD->getShortDescription(); 93 SmallString<512> TmpStr; 94 llvm::raw_svector_ostream Out(TmpStr); 95 for (StringRef::iterator I=desc.begin(), E=desc.end(); I!=E; ++I) { 96 if (*I == '%') 97 Out << "%%"; 98 else 99 Out << *I; 100 } 101 Out.flush(); 102 unsigned ErrorDiag = Diag.getCustomDiagID(DiagnosticsEngine::Warning, 103 TmpStr); 104 SourceLocation L = PD->getLocation().asLocation(); 105 DiagnosticBuilder diagBuilder = Diag.Report(L, ErrorDiag); 106 107 // Get the ranges from the last point in the path. 108 ArrayRef<SourceRange> Ranges = PD->path.back()->getRanges(); 109 110 for (ArrayRef<SourceRange>::iterator I = Ranges.begin(), 111 E = Ranges.end(); I != E; ++I) { 112 diagBuilder << *I; 113 } 114 } 115 } 116 }; 117 } // end anonymous namespace 118 119 //===----------------------------------------------------------------------===// 120 // AnalysisConsumer declaration. 121 //===----------------------------------------------------------------------===// 122 123 namespace { 124 125 class AnalysisConsumer : public ASTConsumer, 126 public RecursiveASTVisitor<AnalysisConsumer> { 127 enum { 128 AM_None = 0, 129 AM_Syntax = 0x1, 130 AM_Path = 0x2 131 }; 132 typedef unsigned AnalysisMode; 133 134 /// Mode of the analyzes while recursively visiting Decls. 135 AnalysisMode RecVisitorMode; 136 /// Bug Reporter to use while recursively visiting Decls. 137 BugReporter *RecVisitorBR; 138 139 public: 140 ASTContext *Ctx; 141 const Preprocessor &PP; 142 const std::string OutDir; 143 AnalyzerOptionsRef Opts; 144 ArrayRef<std::string> Plugins; 145 146 /// \brief Stores the declarations from the local translation unit. 147 /// Note, we pre-compute the local declarations at parse time as an 148 /// optimization to make sure we do not deserialize everything from disk. 149 /// The local declaration to all declarations ratio might be very small when 150 /// working with a PCH file. 151 SetOfDecls LocalTUDecls; 152 153 // Set of PathDiagnosticConsumers. Owned by AnalysisManager. 154 PathDiagnosticConsumers PathConsumers; 155 156 StoreManagerCreator CreateStoreMgr; 157 ConstraintManagerCreator CreateConstraintMgr; 158 159 OwningPtr<CheckerManager> checkerMgr; 160 OwningPtr<AnalysisManager> Mgr; 161 162 /// Time the analyzes time of each translation unit. 163 static llvm::Timer* TUTotalTimer; 164 165 /// The information about analyzed functions shared throughout the 166 /// translation unit. 167 FunctionSummariesTy FunctionSummaries; 168 169 AnalysisConsumer(const Preprocessor& pp, 170 const std::string& outdir, 171 AnalyzerOptionsRef opts, 172 ArrayRef<std::string> plugins) 173 : RecVisitorMode(0), RecVisitorBR(0), 174 Ctx(0), PP(pp), OutDir(outdir), Opts(opts), Plugins(plugins) { 175 DigestAnalyzerOptions(); 176 if (Opts->PrintStats) { 177 llvm::EnableStatistics(); 178 TUTotalTimer = new llvm::Timer("Analyzer Total Time"); 179 } 180 } 181 182 ~AnalysisConsumer() { 183 if (Opts->PrintStats) 184 delete TUTotalTimer; 185 } 186 187 void DigestAnalyzerOptions() { 188 // Create the PathDiagnosticConsumer. 189 PathConsumers.push_back(new ClangDiagPathDiagConsumer(PP.getDiagnostics())); 190 191 if (!OutDir.empty()) { 192 switch (Opts->AnalysisDiagOpt) { 193 default: 194 #define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \ 195 case PD_##NAME: CREATEFN(*Opts.getPtr(), PathConsumers, OutDir, PP);\ 196 break; 197 #include "clang/StaticAnalyzer/Core/Analyses.def" 198 } 199 } else if (Opts->AnalysisDiagOpt == PD_TEXT) { 200 // Create the text client even without a specified output file since 201 // it just uses diagnostic notes. 202 createTextPathDiagnosticConsumer(*Opts.getPtr(), PathConsumers, "", PP); 203 } 204 205 // Create the analyzer component creators. 206 switch (Opts->AnalysisStoreOpt) { 207 default: 208 llvm_unreachable("Unknown store manager."); 209 #define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \ 210 case NAME##Model: CreateStoreMgr = CREATEFN; break; 211 #include "clang/StaticAnalyzer/Core/Analyses.def" 212 } 213 214 switch (Opts->AnalysisConstraintsOpt) { 215 default: 216 llvm_unreachable("Unknown constraint manager."); 217 #define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \ 218 case NAME##Model: CreateConstraintMgr = CREATEFN; break; 219 #include "clang/StaticAnalyzer/Core/Analyses.def" 220 } 221 } 222 223 void DisplayFunction(const Decl *D, AnalysisMode Mode, 224 ExprEngine::InliningModes IMode) { 225 if (!Opts->AnalyzerDisplayProgress) 226 return; 227 228 SourceManager &SM = Mgr->getASTContext().getSourceManager(); 229 PresumedLoc Loc = SM.getPresumedLoc(D->getLocation()); 230 if (Loc.isValid()) { 231 llvm::errs() << "ANALYZE"; 232 233 if (Mode == AM_Syntax) 234 llvm::errs() << " (Syntax)"; 235 else if (Mode == AM_Path) { 236 llvm::errs() << " (Path, "; 237 switch (IMode) { 238 case ExprEngine::Inline_Minimal: 239 llvm::errs() << " Inline_Minimal"; 240 break; 241 case ExprEngine::Inline_Regular: 242 llvm::errs() << " Inline_Regular"; 243 break; 244 } 245 llvm::errs() << ")"; 246 } 247 else 248 assert(Mode == (AM_Syntax | AM_Path) && "Unexpected mode!"); 249 250 llvm::errs() << ": " << Loc.getFilename(); 251 if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) { 252 const NamedDecl *ND = cast<NamedDecl>(D); 253 llvm::errs() << ' ' << *ND << '\n'; 254 } 255 else if (isa<BlockDecl>(D)) { 256 llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:" 257 << Loc.getColumn() << '\n'; 258 } 259 else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { 260 Selector S = MD->getSelector(); 261 llvm::errs() << ' ' << S.getAsString(); 262 } 263 } 264 } 265 266 virtual void Initialize(ASTContext &Context) { 267 Ctx = &Context; 268 checkerMgr.reset(createCheckerManager(*Opts, PP.getLangOpts(), Plugins, 269 PP.getDiagnostics())); 270 Mgr.reset(new AnalysisManager(*Ctx, 271 PP.getDiagnostics(), 272 PP.getLangOpts(), 273 PathConsumers, 274 CreateStoreMgr, 275 CreateConstraintMgr, 276 checkerMgr.get(), 277 *Opts)); 278 } 279 280 /// \brief Store the top level decls in the set to be processed later on. 281 /// (Doing this pre-processing avoids deserialization of data from PCH.) 282 virtual bool HandleTopLevelDecl(DeclGroupRef D); 283 virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D); 284 285 virtual void HandleTranslationUnit(ASTContext &C); 286 287 /// \brief Determine which inlining mode should be used when this function is 288 /// analyzed. This allows to redefine the default inlining policies when 289 /// analyzing a given function. 290 ExprEngine::InliningModes 291 getInliningModeForFunction(const Decl *D, SetOfConstDecls Visited); 292 293 /// \brief Build the call graph for all the top level decls of this TU and 294 /// use it to define the order in which the functions should be visited. 295 void HandleDeclsCallGraph(const unsigned LocalTUDeclsSize); 296 297 /// \brief Run analyzes(syntax or path sensitive) on the given function. 298 /// \param Mode - determines if we are requesting syntax only or path 299 /// sensitive only analysis. 300 /// \param VisitedCallees - The output parameter, which is populated with the 301 /// set of functions which should be considered analyzed after analyzing the 302 /// given root function. 303 void HandleCode(Decl *D, AnalysisMode Mode, 304 ExprEngine::InliningModes IMode = ExprEngine::Inline_Minimal, 305 SetOfConstDecls *VisitedCallees = 0); 306 307 void RunPathSensitiveChecks(Decl *D, 308 ExprEngine::InliningModes IMode, 309 SetOfConstDecls *VisitedCallees); 310 void ActionExprEngine(Decl *D, bool ObjCGCEnabled, 311 ExprEngine::InliningModes IMode, 312 SetOfConstDecls *VisitedCallees); 313 314 /// Visitors for the RecursiveASTVisitor. 315 bool shouldWalkTypesOfTypeLocs() const { return false; } 316 317 /// Handle callbacks for arbitrary Decls. 318 bool VisitDecl(Decl *D) { 319 AnalysisMode Mode = getModeForDecl(D, RecVisitorMode); 320 if (Mode & AM_Syntax) 321 checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR); 322 return true; 323 } 324 325 bool VisitFunctionDecl(FunctionDecl *FD) { 326 IdentifierInfo *II = FD->getIdentifier(); 327 if (II && II->getName().startswith("__inline")) 328 return true; 329 330 // We skip function template definitions, as their semantics is 331 // only determined when they are instantiated. 332 if (FD->isThisDeclarationADefinition() && 333 !FD->isDependentContext()) { 334 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false); 335 HandleCode(FD, RecVisitorMode); 336 } 337 return true; 338 } 339 340 bool VisitObjCMethodDecl(ObjCMethodDecl *MD) { 341 if (MD->isThisDeclarationADefinition()) { 342 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false); 343 HandleCode(MD, RecVisitorMode); 344 } 345 return true; 346 } 347 348 bool VisitBlockDecl(BlockDecl *BD) { 349 if (BD->hasBody()) { 350 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false); 351 HandleCode(BD, RecVisitorMode); 352 } 353 return true; 354 } 355 356 private: 357 void storeTopLevelDecls(DeclGroupRef DG); 358 359 /// \brief Check if we should skip (not analyze) the given function. 360 AnalysisMode getModeForDecl(Decl *D, AnalysisMode Mode); 361 362 }; 363 } // end anonymous namespace 364 365 366 //===----------------------------------------------------------------------===// 367 // AnalysisConsumer implementation. 368 //===----------------------------------------------------------------------===// 369 llvm::Timer* AnalysisConsumer::TUTotalTimer = 0; 370 371 bool AnalysisConsumer::HandleTopLevelDecl(DeclGroupRef DG) { 372 storeTopLevelDecls(DG); 373 return true; 374 } 375 376 void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) { 377 storeTopLevelDecls(DG); 378 } 379 380 void AnalysisConsumer::storeTopLevelDecls(DeclGroupRef DG) { 381 for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) { 382 383 // Skip ObjCMethodDecl, wait for the objc container to avoid 384 // analyzing twice. 385 if (isa<ObjCMethodDecl>(*I)) 386 continue; 387 388 LocalTUDecls.push_back(*I); 389 } 390 } 391 392 static bool shouldSkipFunction(const Decl *D, 393 SetOfConstDecls Visited, 394 SetOfConstDecls VisitedAsTopLevel) { 395 if (VisitedAsTopLevel.count(D)) 396 return true; 397 398 // We want to re-analyse the functions as top level in the following cases: 399 // - The 'init' methods should be reanalyzed because 400 // ObjCNonNilReturnValueChecker assumes that '[super init]' never returns 401 // 'nil' and unless we analyze the 'init' functions as top level, we will 402 // not catch errors within defensive code. 403 // - We want to reanalyze all ObjC methods as top level to report Retain 404 // Count naming convention errors more aggressively. 405 if (isa<ObjCMethodDecl>(D)) 406 return false; 407 408 // Otherwise, if we visited the function before, do not reanalyze it. 409 return Visited.count(D); 410 } 411 412 ExprEngine::InliningModes 413 AnalysisConsumer::getInliningModeForFunction(const Decl *D, 414 SetOfConstDecls Visited) { 415 // We want to reanalyze all ObjC methods as top level to report Retain 416 // Count naming convention errors more aggressively. But we should tune down 417 // inlining when reanalyzing an already inlined function. 418 if (Visited.count(D)) { 419 assert(isa<ObjCMethodDecl>(D) && 420 "We are only reanalyzing ObjCMethods."); 421 const ObjCMethodDecl *ObjCM = cast<ObjCMethodDecl>(D); 422 if (ObjCM->getMethodFamily() != OMF_init) 423 return ExprEngine::Inline_Minimal; 424 } 425 426 return ExprEngine::Inline_Regular; 427 } 428 429 void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) { 430 // Build the Call Graph by adding all the top level declarations to the graph. 431 // Note: CallGraph can trigger deserialization of more items from a pch 432 // (though HandleInterestingDecl); triggering additions to LocalTUDecls. 433 // We rely on random access to add the initially processed Decls to CG. 434 CallGraph CG; 435 for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) { 436 CG.addToCallGraph(LocalTUDecls[i]); 437 } 438 439 // Walk over all of the call graph nodes in topological order, so that we 440 // analyze parents before the children. Skip the functions inlined into 441 // the previously processed functions. Use external Visited set to identify 442 // inlined functions. The topological order allows the "do not reanalyze 443 // previously inlined function" performance heuristic to be triggered more 444 // often. 445 SetOfConstDecls Visited; 446 SetOfConstDecls VisitedAsTopLevel; 447 llvm::ReversePostOrderTraversal<clang::CallGraph*> RPOT(&CG); 448 for (llvm::ReversePostOrderTraversal<clang::CallGraph*>::rpo_iterator 449 I = RPOT.begin(), E = RPOT.end(); I != E; ++I) { 450 NumFunctionTopLevel++; 451 452 CallGraphNode *N = *I; 453 Decl *D = N->getDecl(); 454 455 // Skip the abstract root node. 456 if (!D) 457 continue; 458 459 // Skip the functions which have been processed already or previously 460 // inlined. 461 if (shouldSkipFunction(D, Visited, VisitedAsTopLevel)) 462 continue; 463 464 // Analyze the function. 465 SetOfConstDecls VisitedCallees; 466 467 HandleCode(D, AM_Path, getInliningModeForFunction(D, Visited), 468 (Mgr->options.InliningMode == All ? 0 : &VisitedCallees)); 469 470 // Add the visited callees to the global visited set. 471 for (SetOfConstDecls::iterator I = VisitedCallees.begin(), 472 E = VisitedCallees.end(); I != E; ++I) { 473 Visited.insert(*I); 474 } 475 VisitedAsTopLevel.insert(D); 476 } 477 } 478 479 void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { 480 // Don't run the actions if an error has occurred with parsing the file. 481 DiagnosticsEngine &Diags = PP.getDiagnostics(); 482 if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred()) 483 return; 484 485 { 486 if (TUTotalTimer) TUTotalTimer->startTimer(); 487 488 // Introduce a scope to destroy BR before Mgr. 489 BugReporter BR(*Mgr); 490 TranslationUnitDecl *TU = C.getTranslationUnitDecl(); 491 checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR); 492 493 // Run the AST-only checks using the order in which functions are defined. 494 // If inlining is not turned on, use the simplest function order for path 495 // sensitive analyzes as well. 496 RecVisitorMode = AM_Syntax; 497 if (!Mgr->shouldInlineCall()) 498 RecVisitorMode |= AM_Path; 499 RecVisitorBR = &BR; 500 501 // Process all the top level declarations. 502 // 503 // Note: TraverseDecl may modify LocalTUDecls, but only by appending more 504 // entries. Thus we don't use an iterator, but rely on LocalTUDecls 505 // random access. By doing so, we automatically compensate for iterators 506 // possibly being invalidated, although this is a bit slower. 507 const unsigned LocalTUDeclsSize = LocalTUDecls.size(); 508 for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) { 509 TraverseDecl(LocalTUDecls[i]); 510 } 511 512 if (Mgr->shouldInlineCall()) 513 HandleDeclsCallGraph(LocalTUDeclsSize); 514 515 // After all decls handled, run checkers on the entire TranslationUnit. 516 checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR); 517 518 RecVisitorBR = 0; 519 } 520 521 // Explicitly destroy the PathDiagnosticConsumer. This will flush its output. 522 // FIXME: This should be replaced with something that doesn't rely on 523 // side-effects in PathDiagnosticConsumer's destructor. This is required when 524 // used with option -disable-free. 525 Mgr.reset(NULL); 526 527 if (TUTotalTimer) TUTotalTimer->stopTimer(); 528 529 // Count how many basic blocks we have not covered. 530 NumBlocksInAnalyzedFunctions = FunctionSummaries.getTotalNumBasicBlocks(); 531 if (NumBlocksInAnalyzedFunctions > 0) 532 PercentReachableBlocks = 533 (FunctionSummaries.getTotalNumVisitedBasicBlocks() * 100) / 534 NumBlocksInAnalyzedFunctions; 535 536 } 537 538 static std::string getFunctionName(const Decl *D) { 539 if (const ObjCMethodDecl *ID = dyn_cast<ObjCMethodDecl>(D)) { 540 return ID->getSelector().getAsString(); 541 } 542 if (const FunctionDecl *ND = dyn_cast<FunctionDecl>(D)) { 543 IdentifierInfo *II = ND->getIdentifier(); 544 if (II) 545 return II->getName(); 546 } 547 return ""; 548 } 549 550 AnalysisConsumer::AnalysisMode 551 AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) { 552 if (!Opts->AnalyzeSpecificFunction.empty() && 553 getFunctionName(D) != Opts->AnalyzeSpecificFunction) 554 return AM_None; 555 556 // Unless -analyze-all is specified, treat decls differently depending on 557 // where they came from: 558 // - Main source file: run both path-sensitive and non-path-sensitive checks. 559 // - Header files: run non-path-sensitive checks only. 560 // - System headers: don't run any checks. 561 SourceManager &SM = Ctx->getSourceManager(); 562 SourceLocation SL = SM.getExpansionLoc(D->getLocation()); 563 if (!Opts->AnalyzeAll && !SM.isFromMainFile(SL)) { 564 if (SL.isInvalid() || SM.isInSystemHeader(SL)) 565 return AM_None; 566 return Mode & ~AM_Path; 567 } 568 569 return Mode; 570 } 571 572 void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode, 573 ExprEngine::InliningModes IMode, 574 SetOfConstDecls *VisitedCallees) { 575 if (!D->hasBody()) 576 return; 577 Mode = getModeForDecl(D, Mode); 578 if (Mode == AM_None) 579 return; 580 581 DisplayFunction(D, Mode, IMode); 582 CFG *DeclCFG = Mgr->getCFG(D); 583 if (DeclCFG) { 584 unsigned CFGSize = DeclCFG->size(); 585 MaxCFGSize = MaxCFGSize < CFGSize ? CFGSize : MaxCFGSize; 586 } 587 588 // Clear the AnalysisManager of old AnalysisDeclContexts. 589 Mgr->ClearContexts(); 590 BugReporter BR(*Mgr); 591 592 if (Mode & AM_Syntax) 593 checkerMgr->runCheckersOnASTBody(D, *Mgr, BR); 594 if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) { 595 RunPathSensitiveChecks(D, IMode, VisitedCallees); 596 if (IMode != ExprEngine::Inline_Minimal) 597 NumFunctionsAnalyzed++; 598 } 599 } 600 601 //===----------------------------------------------------------------------===// 602 // Path-sensitive checking. 603 //===----------------------------------------------------------------------===// 604 605 void AnalysisConsumer::ActionExprEngine(Decl *D, bool ObjCGCEnabled, 606 ExprEngine::InliningModes IMode, 607 SetOfConstDecls *VisitedCallees) { 608 // Construct the analysis engine. First check if the CFG is valid. 609 // FIXME: Inter-procedural analysis will need to handle invalid CFGs. 610 if (!Mgr->getCFG(D)) 611 return; 612 613 // See if the LiveVariables analysis scales. 614 if (!Mgr->getAnalysisDeclContext(D)->getAnalysis<RelaxedLiveVariables>()) 615 return; 616 617 ExprEngine Eng(*Mgr, ObjCGCEnabled, VisitedCallees, &FunctionSummaries,IMode); 618 619 // Set the graph auditor. 620 OwningPtr<ExplodedNode::Auditor> Auditor; 621 if (Mgr->options.visualizeExplodedGraphWithUbiGraph) { 622 Auditor.reset(CreateUbiViz()); 623 ExplodedNode::SetAuditor(Auditor.get()); 624 } 625 626 // Execute the worklist algorithm. 627 Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D), 628 Mgr->options.getMaxNodesPerTopLevelFunction()); 629 630 // Release the auditor (if any) so that it doesn't monitor the graph 631 // created BugReporter. 632 ExplodedNode::SetAuditor(0); 633 634 // Visualize the exploded graph. 635 if (Mgr->options.visualizeExplodedGraphWithGraphViz) 636 Eng.ViewGraph(Mgr->options.TrimGraph); 637 638 // Display warnings. 639 Eng.getBugReporter().FlushReports(); 640 } 641 642 void AnalysisConsumer::RunPathSensitiveChecks(Decl *D, 643 ExprEngine::InliningModes IMode, 644 SetOfConstDecls *Visited) { 645 646 switch (Mgr->getLangOpts().getGC()) { 647 case LangOptions::NonGC: 648 ActionExprEngine(D, false, IMode, Visited); 649 break; 650 651 case LangOptions::GCOnly: 652 ActionExprEngine(D, true, IMode, Visited); 653 break; 654 655 case LangOptions::HybridGC: 656 ActionExprEngine(D, false, IMode, Visited); 657 ActionExprEngine(D, true, IMode, Visited); 658 break; 659 } 660 } 661 662 //===----------------------------------------------------------------------===// 663 // AnalysisConsumer creation. 664 //===----------------------------------------------------------------------===// 665 666 ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp, 667 const std::string& outDir, 668 AnalyzerOptionsRef opts, 669 ArrayRef<std::string> plugins) { 670 // Disable the effects of '-Werror' when using the AnalysisConsumer. 671 pp.getDiagnostics().setWarningsAsErrors(false); 672 673 return new AnalysisConsumer(pp, outDir, opts, plugins); 674 } 675 676 //===----------------------------------------------------------------------===// 677 // Ubigraph Visualization. FIXME: Move to separate file. 678 //===----------------------------------------------------------------------===// 679 680 namespace { 681 682 class UbigraphViz : public ExplodedNode::Auditor { 683 OwningPtr<raw_ostream> Out; 684 std::string Filename; 685 unsigned Cntr; 686 687 typedef llvm::DenseMap<void*,unsigned> VMap; 688 VMap M; 689 690 public: 691 UbigraphViz(raw_ostream *Out, StringRef Filename); 692 693 ~UbigraphViz(); 694 695 virtual void AddEdge(ExplodedNode *Src, ExplodedNode *Dst); 696 }; 697 698 } // end anonymous namespace 699 700 static ExplodedNode::Auditor* CreateUbiViz() { 701 SmallString<128> P; 702 int FD; 703 llvm::sys::fs::createTemporaryFile("llvm_ubi", "", FD, P); 704 llvm::errs() << "Writing '" << P.str() << "'.\n"; 705 706 OwningPtr<llvm::raw_fd_ostream> Stream; 707 Stream.reset(new llvm::raw_fd_ostream(FD, true)); 708 709 return new UbigraphViz(Stream.take(), P); 710 } 711 712 void UbigraphViz::AddEdge(ExplodedNode *Src, ExplodedNode *Dst) { 713 714 assert (Src != Dst && "Self-edges are not allowed."); 715 716 // Lookup the Src. If it is a new node, it's a root. 717 VMap::iterator SrcI= M.find(Src); 718 unsigned SrcID; 719 720 if (SrcI == M.end()) { 721 M[Src] = SrcID = Cntr++; 722 *Out << "('vertex', " << SrcID << ", ('color','#00ff00'))\n"; 723 } 724 else 725 SrcID = SrcI->second; 726 727 // Lookup the Dst. 728 VMap::iterator DstI= M.find(Dst); 729 unsigned DstID; 730 731 if (DstI == M.end()) { 732 M[Dst] = DstID = Cntr++; 733 *Out << "('vertex', " << DstID << ")\n"; 734 } 735 else { 736 // We have hit DstID before. Change its style to reflect a cache hit. 737 DstID = DstI->second; 738 *Out << "('change_vertex_style', " << DstID << ", 1)\n"; 739 } 740 741 // Add the edge. 742 *Out << "('edge', " << SrcID << ", " << DstID 743 << ", ('arrow','true'), ('oriented', 'true'))\n"; 744 } 745 746 UbigraphViz::UbigraphViz(raw_ostream *Out, StringRef Filename) 747 : Out(Out), Filename(Filename), Cntr(0) { 748 749 *Out << "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n"; 750 *Out << "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66')," 751 " ('size', '1.5'))\n"; 752 } 753 754 UbigraphViz::~UbigraphViz() { 755 Out.reset(0); 756 llvm::errs() << "Running 'ubiviz' program... "; 757 std::string ErrMsg; 758 std::string Ubiviz = llvm::sys::FindProgramByName("ubiviz"); 759 std::vector<const char*> args; 760 args.push_back(Ubiviz.c_str()); 761 args.push_back(Filename.c_str()); 762 args.push_back(0); 763 764 if (llvm::sys::ExecuteAndWait(Ubiviz, &args[0], 0, 0, 0, 0, &ErrMsg)) { 765 llvm::errs() << "Error viewing graph: " << ErrMsg << "\n"; 766 } 767 768 // Delete the file. 769 llvm::sys::fs::remove(Filename); 770 } 771