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