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