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