clang: lib/StaticAnalyzer/Frontend/AnalysisConsumer.cpp Source File (original) (raw)

1

2

3

4

5

6

7

8

9

10

11

12

36#include "llvm/ADT/PostOrderIterator.h"

37#include "llvm/ADT/ScopeExit.h"

38#include "llvm/ADT/Statistic.h"

39#include "llvm/Support/FileSystem.h"

40#include "llvm/Support/Path.h"

41#include "llvm/Support/Program.h"

42#include "llvm/Support/Timer.h"

43#include "llvm/Support/raw_ostream.h"

44#include

45#include

46#include

47

48using namespace clang;

49using namespace ento;

50

51#define DEBUG_TYPE "AnalysisConsumer"

52

53STATISTIC(NumFunctionTopLevel, "The # of functions at top level.");

55 "The # of functions and blocks analyzed (as top level "

56 "with inlining turned on).");

58 "The # of basic blocks in the analyzed functions.");

59STATISTIC(NumVisitedBlocksInAnalyzedFunctions,

60 "The # of visited basic blocks in the analyzed functions.");

61STATISTIC(PercentReachableBlocks, "The % of reachable basic blocks.");

62STATISTIC(MaxCFGSize, "The maximum number of basic blocks in a function.");

63

64

65

66

67

68namespace {

69

72 enum {

73 AM_None = 0,

74 AM_Syntax = 0x1,

75 AM_Path = 0x2

76 };

77 typedef unsigned AnalysisMode;

78

79

80 AnalysisMode RecVisitorMode;

81

83

84 std::vector<std::function<void(CheckerRegistry &)>> CheckerRegistrationFns;

85

86public:

89 const std::string OutDir;

94

95

96

97

98

99

101

103

104

106

109

110 std::unique_ptr checkerMgr;

111 std::unique_ptr Mgr;

112

113

114 std::unique_ptrllvm::TimerGroup AnalyzerTimers;

115 std::unique_ptrllvm::Timer SyntaxCheckTimer;

116 std::unique_ptrllvm::Timer ExprEngineTimer;

117 std::unique_ptrllvm::Timer BugReporterTimer;

118

119

120

122

123 AnalysisConsumer(CompilerInstance &CI, const std::string &outdir,

126 : RecVisitorMode(0), RecVisitorBR(nullptr), Ctx(nullptr),

127 PP(CI.getPreprocessor()), OutDir(outdir), Opts(opts),

128 Plugins(plugins), Injector(injector), CTU(CI),

129 MacroExpansions(CI.getLangOpts()) {

130 DigestAnalyzerOptions();

132 Opts.ShouldSerializeStats) {

133 AnalyzerTimers = std::make_uniquellvm::TimerGroup(

134 "analyzer", "Analyzer timers");

135 SyntaxCheckTimer = std::make_uniquellvm::Timer(

136 "syntaxchecks", "Syntax-based analysis time", *AnalyzerTimers);

137 ExprEngineTimer = std::make_uniquellvm::Timer(

138 "exprengine", "Path exploration time", *AnalyzerTimers);

139 BugReporterTimer = std::make_uniquellvm::Timer(

140 "bugreporter", "Path-sensitive report post-processing time",

141 *AnalyzerTimers);

142 }

143

144 if (Opts.PrintStats || Opts.ShouldSerializeStats) {

145 llvm::EnableStatistics( false);

146 }

147

148 if (Opts.ShouldDisplayMacroExpansions)

150

151

152 ShouldWalkTypesOfTypeLocs = false;

153 }

154

155 ~AnalysisConsumer() override {

157 llvm::PrintStatistics();

158 }

159 }

160

161 void DigestAnalyzerOptions() {

164 break;

165#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN) \

166 case PD_##NAME: \

167 CREATEFN(Opts.getDiagOpts(), PathConsumers, OutDir, PP, CTU, \

168 MacroExpansions); \

169 break;

170#include "clang/StaticAnalyzer/Core/Analyses.def"

171 default:

172 llvm_unreachable("Unknown analyzer output type!");

173 }

174

175

177

179 default:

180 llvm_unreachable("Unknown constraint manager.");

181#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \

182 case NAME##Model: CreateConstraintMgr = CREATEFN; break;

183#include "clang/StaticAnalyzer/Core/Analyses.def"

184 }

185 }

186

187 void DisplayTime(llvm::TimeRecord &Time) {

189 return;

190 }

191 llvm::errs() << " : " << llvm::format("%1.1f", Time.getWallTime() * 1000)

192 << " ms\n";

193 }

194

195 void DisplayFunction(const Decl *D, AnalysisMode Mode,

198 return;

199

200 SourceManager &SM = Mgr->getASTContext().getSourceManager();

203 llvm::errs() << "ANALYZE";

204

205 if (Mode == AM_Syntax)

206 llvm::errs() << " (Syntax)";

207 else if (Mode == AM_Path) {

208 llvm::errs() << " (Path, ";

209 switch (IMode) {

211 llvm::errs() << " Inline_Minimal";

212 break;

214 llvm::errs() << " Inline_Regular";

215 break;

216 }

217 llvm::errs() << ")";

218 } else

219 assert(Mode == (AM_Syntax | AM_Path) && "Unexpected mode!");

220

221 llvm::errs() << ": " << Loc.getFilename() << ' '

223 }

224 }

225

227 Ctx = &Context;

228 checkerMgr = std::make_unique(*Ctx, Opts, PP, Plugins,

229 CheckerRegistrationFns);

230

231 Mgr = std::make_unique(*Ctx, PP, PathConsumers,

232 CreateStoreMgr, CreateConstraintMgr,

233 checkerMgr.get(), Opts, Injector);

234 }

235

236

237

240

242

243

244

245

248

249

250

251 void HandleDeclsCallGraph(const unsigned LocalTUDeclsSize);

252

253

254

255

256

257

258

259 void HandleCode(Decl *D, AnalysisMode Mode,

262

263 void RunPathSensitiveChecks(Decl *D,

266

267

269 AnalysisMode Mode = getModeForDecl(D, RecVisitorMode);

270 if (Mode & AM_Syntax) {

271 if (SyntaxCheckTimer)

272 SyntaxCheckTimer->startTimer();

273 checkerMgr->runCheckersOnASTDecl(D, *Mgr, *RecVisitorBR);

274 if (SyntaxCheckTimer)

275 SyntaxCheckTimer->stopTimer();

276 }

277 return true;

278 }

279

280 bool VisitVarDecl(VarDecl *VD) override {

281 if (!Opts.IsNaiveCTUEnabled)

282 return true;

283

286 return true;

287 } else {

288

289 return true;

290 }

291

293 return true;

294

297 Opts.DisplayCTUProgress);

298

299 if (!CTUDeclOrError) {

300 handleAllErrors(CTUDeclOrError.takeError(),

302 CTU.emitCrossTUDiagnostics(IE);

303 });

304 }

305

306 return true;

307 }

308

309 bool VisitFunctionDecl(FunctionDecl *FD) override {

311 if (II && II->getName().starts_with("__inline"))

312 return true;

313

314

315

318 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);

319 HandleCode(FD, RecVisitorMode);

320 }

321 return true;

322 }

323

324 bool VisitObjCMethodDecl(ObjCMethodDecl *MD) override {

326 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);

327 HandleCode(MD, RecVisitorMode);

328 }

329 return true;

330 }

331

332 bool VisitBlockDecl(BlockDecl *BD) override {

334 assert(RecVisitorMode == AM_Syntax || Mgr->shouldInlineCall() == false);

335

336

338 HandleCode(BD, RecVisitorMode);

339 }

340 }

341 return true;

342 }

343

345 PathConsumers.push_back(Consumer);

346 }

347

349 CheckerRegistrationFns.push_back(std::move(Fn));

350 }

351

352private:

354

355

356 AnalysisMode getModeForDecl(Decl *D, AnalysisMode Mode);

357 void runAnalysisOnTranslationUnit(ASTContext &C);

358

359

360 void reportAnalyzerProgress(StringRef S);

361};

362}

363

364

365

366

367

368bool AnalysisConsumer::HandleTopLevelDecl(DeclGroupRef DG) {

369 storeTopLevelDecls(DG);

370 return true;

371}

372

373void AnalysisConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef DG) {

374 storeTopLevelDecls(DG);

375}

376

377void AnalysisConsumer::storeTopLevelDecls(DeclGroupRef DG) {

378 for (auto &I : DG) {

379

380

381

382 if (isa(I))

383 continue;

384

385 LocalTUDecls.push_back(I);

386 }

387}

388

392 if (VisitedAsTopLevel.count(D))

393 return true;

394

395

396

397

398 if (const auto *CD = dyn_cast(D))

399 if (CD->isInheritingConstructor())

400 return true;

401

402

403

404

405

406

407

408

409 if (isa(D))

410 return false;

411

412

413

414 if (const auto *MD = dyn_cast(D)) {

415 if (MD->isCopyAssignmentOperator() || MD->isMoveAssignmentOperator())

416 return false;

417 }

418

419

421}

422

424AnalysisConsumer::getInliningModeForFunction(const Decl *D,

426

427

428

429 if (Visited.count(D) && isa(D)) {

433 }

434

436}

437

438void AnalysisConsumer::HandleDeclsCallGraph(const unsigned LocalTUDeclsSize) {

439

440

441

442

444 for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {

446 }

447

448

449

450

451

452

453

456 llvm::ReversePostOrderTraversalclang::CallGraph\* RPOT(&CG);

457 for (auto &N : RPOT) {

458 NumFunctionTopLevel++;

459

460 Decl *D = N->getDecl();

461

462

463 if (D)

464 continue;

465

466

467

469 continue;

470

471

472

473

474

475 if (const auto *FD = dyn_cast(D)) {

476

477

480 continue;

481 }

482

483

485

486 HandleCode(D, AM_Path, getInliningModeForFunction(D, Visited),

487 (Mgr->options.InliningMode == All ? nullptr : &VisitedCallees));

488

489

490 for (const Decl *Callee : VisitedCallees)

491

492

493 Visited.insert(isa(Callee) ? Callee

494 : Callee->getCanonicalDecl());

495 VisitedAsTopLevel.insert(D);

496 }

497}

498

501 FileID FID = SM.getMainFileID();

502 StringRef Buffer = SM.getBufferOrFake(FID).getBuffer();

503 return Buffer.contains(Substring);

504}

505

508 llvm::errs() << "Every top-level function was skipped.\n";

509

511 llvm::errs() << "Pass the -analyzer-display-progress for tracking which "

512 "functions are analyzed.\n";

513

514 bool HasBrackets =

516

517 if (Ctx.getLangOpts().CPlusPlus && !HasBrackets) {

518 llvm::errs()

519 << "For analyzing C++ code you need to pass the function parameter "

520 "list: -analyze-function=\"foobar(int, _Bool)\"\n";

521 } else if (!Ctx.getLangOpts().CPlusPlus && HasBrackets) {

522 llvm::errs() << "For analyzing C code you shouldn't pass the function "

523 "parameter list, only the name of the function: "

524 "-analyze-function=foobar\n";

525 }

526}

527

528void AnalysisConsumer::runAnalysisOnTranslationUnit(ASTContext &C) {

531 BR.setAnalysisEntryPoint(TU);

532 if (SyntaxCheckTimer)

533 SyntaxCheckTimer->startTimer();

534 checkerMgr->runCheckersOnASTDecl(TU, *Mgr, BR);

535 if (SyntaxCheckTimer)

536 SyntaxCheckTimer->stopTimer();

537

538

539

540

541 RecVisitorMode = AM_Syntax;

542 if (!Mgr->shouldInlineCall())

543 RecVisitorMode |= AM_Path;

544 RecVisitorBR = &BR;

545

546

547

548

549

550

551

552 const unsigned LocalTUDeclsSize = LocalTUDecls.size();

553 for (unsigned i = 0 ; i < LocalTUDeclsSize ; ++i) {

554 TraverseDecl(LocalTUDecls[i]);

555 }

556

557 if (Mgr->shouldInlineCall())

558 HandleDeclsCallGraph(LocalTUDeclsSize);

559

560

561 checkerMgr->runCheckersOnEndOfTranslationUnit(TU, *Mgr, BR);

562

563 BR.FlushReports();

564 RecVisitorBR = nullptr;

565

566

567

568

569

570

573}

574

575void AnalysisConsumer::reportAnalyzerProgress(StringRef S) {

577 llvm::errs() << S;

578}

579

580void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) {

581

584 return;

585

586

587

588

589

590 const auto DiagFlusherScopeExit =

591 llvm::make_scope_exit([this] { Mgr.reset(); });

592

593 if (Opts.ShouldIgnoreBisonGeneratedFiles &&

595 reportAnalyzerProgress("Skipping bison-generated file\n");

596 return;

597 }

598

599 if (Opts.ShouldIgnoreFlexGeneratedFiles &&

601 reportAnalyzerProgress("Skipping flex-generated file\n");

602 return;

603 }

604

605

606

608 reportAnalyzerProgress("All checks are disabled using a supplied option\n");

609 return;

610 }

611

612

613 runAnalysisOnTranslationUnit(C);

614

615

617 NumVisitedBlocksInAnalyzedFunctions =

619 if (NumBlocksInAnalyzedFunctions > 0)

620 PercentReachableBlocks =

622 NumBlocksInAnalyzedFunctions;

623}

624

625AnalysisConsumer::AnalysisMode

626AnalysisConsumer::getModeForDecl(Decl *D, AnalysisMode Mode) {

629 return AM_None;

630

631

632

633

634

635

637 return Mode;

638

640

644 return SM.getExpansionLoc(SL);

645 }(D);

646

647

648 if (Loc.isInvalid() || SM.isInSystemHeader(Loc))

649 return AM_None;

650

651

652 if (!Mgr->isInCodeFile(Loc))

653 return Mode & ~AM_Path;

654

655 return Mode;

656}

657

658void AnalysisConsumer::HandleCode(Decl *D, AnalysisMode Mode,

662 return;

663 Mode = getModeForDecl(D, Mode);

664 if (Mode == AM_None)

665 return;

666

667

668 Mgr->ClearContexts();

669

670 if (Mgr->getAnalysisDeclContext(D)->isBodyAutosynthesized())

671 return;

672

673 CFG *DeclCFG = Mgr->getCFG(D);

674 if (DeclCFG)

675 MaxCFGSize.updateMax(DeclCFG->size());

676

677 DisplayFunction(D, Mode, IMode);

679 BR.setAnalysisEntryPoint(D);

680

681 if (Mode & AM_Syntax) {

682 llvm::TimeRecord CheckerStartTime;

683 if (SyntaxCheckTimer) {

684 CheckerStartTime = SyntaxCheckTimer->getTotalTime();

685 SyntaxCheckTimer->startTimer();

686 }

687 checkerMgr->runCheckersOnASTBody(D, *Mgr, BR);

688 if (SyntaxCheckTimer) {

689 SyntaxCheckTimer->stopTimer();

690 llvm::TimeRecord CheckerEndTime = SyntaxCheckTimer->getTotalTime();

691 CheckerEndTime -= CheckerStartTime;

692 DisplayTime(CheckerEndTime);

693 }

694 }

695

696 BR.FlushReports();

697

698 if ((Mode & AM_Path) && checkerMgr->hasPathSensitiveCheckers()) {

699 RunPathSensitiveChecks(D, IMode, VisitedCallees);

701 NumFunctionsAnalyzed++;

702 }

703}

704

705

706

707

708

709void AnalysisConsumer::RunPathSensitiveChecks(Decl *D,

712

713

714 if (!Mgr->getCFG(D))

715 return;

716

717

719 return;

720

721 ExprEngine Eng(CTU, *Mgr, VisitedCallees, &FunctionSummaries, IMode);

722

723

724 llvm::TimeRecord ExprEngineStartTime;

725 if (ExprEngineTimer) {

726 ExprEngineStartTime = ExprEngineTimer->getTotalTime();

727 ExprEngineTimer->startTimer();

728 }

729 Eng.ExecuteWorkList(Mgr->getAnalysisDeclContextManager().getStackFrame(D),

730 Mgr->options.MaxNodesPerTopLevelFunction);

731 if (ExprEngineTimer) {

732 ExprEngineTimer->stopTimer();

733 llvm::TimeRecord ExprEngineEndTime = ExprEngineTimer->getTotalTime();

734 ExprEngineEndTime -= ExprEngineStartTime;

735 DisplayTime(ExprEngineEndTime);

736 }

737

738 if (!Mgr->options.DumpExplodedGraphTo.empty())

739 Eng.DumpGraph(Mgr->options.TrimGraph, Mgr->options.DumpExplodedGraphTo);

740

741

742 if (Mgr->options.visualizeExplodedGraphWithGraphViz)

743 Eng.ViewGraph(Mgr->options.TrimGraph);

744

745

746 if (BugReporterTimer)

747 BugReporterTimer->startTimer();

748 Eng.getBugReporter().FlushReports();

749 if (BugReporterTimer)

750 BugReporterTimer->stopTimer();

751}

752

753

754

755

756

757std::unique_ptr

759

761

763 bool hasModelPath = analyzerOpts.Config.count("model-path") > 0;

764

765 return std::make_unique(

769}

STATISTIC(NumFunctionTopLevel, "The # of functions at top level.")

static bool shouldSkipFunction(const Decl *D, const SetOfConstDecls &Visited, const SetOfConstDecls &VisitedAsTopLevel)

static bool fileContainsString(StringRef Substring, ASTContext &C)

static void reportAnalyzerFunctionMisuse(const AnalyzerOptions &Opts, const ASTContext &Ctx)

Defines the clang::CodeInjector interface which is responsible for injecting AST of function definiti...

Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate....

llvm::DenseSet< const void * > Visited

This file defines the clang::ento::ModelInjector class which implements the clang::CodeInjector inter...

Defines the clang::Preprocessor interface.

Defines the SourceManager interface.

virtual void HandleTranslationUnit(ASTContext &Ctx)

HandleTranslationUnit - This method is called when the ASTs for entire translation unit have been par...

virtual void HandleTopLevelDeclInObjCContainer(DeclGroupRef D)

Handle the specified top-level declaration that occurred inside and ObjC container.

virtual bool HandleTopLevelDecl(DeclGroupRef D)

HandleTopLevelDecl - Handle the specified top-level declaration.

virtual void Initialize(ASTContext &Context)

Initialize - This is called to initialize the consumer, providing the ASTContext.

Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...

SourceManager & getSourceManager()

const LangOptions & getLangOpts() const

static std::string getFunctionName(const Decl *D)

Stores options for the analyzer from the command line.

unsigned DisableAllCheckers

Disable all analyzer checkers.

AnalysisDiagClients AnalysisDiagOpt

AnalysisConstraints AnalysisConstraintsOpt

ConfigTable Config

A key-value table of use-specified configuration values.

std::string AnalyzeSpecificFunction

unsigned AnalyzerDisplayProgress

Represents a block literal declaration, which is like an unnamed FunctionDecl.

Represents a source-level, intra-procedural CFG that represents the control-flow of a Stmt.

unsigned size() const

Return the total number of CFGBlocks within the CFG This is simply a renaming of the getNumBlockIDs()...

The AST-based call graph.

void addToCallGraph(Decl *D)

Populate the call graph with the functions in the given declaration.

CodeInjector is an interface which is responsible for injecting AST of function definitions that may ...

CompilerInstance - Helper class for managing a single instance of the Clang compiler.

AnalyzerOptions & getAnalyzerOpts()

Preprocessor & getPreprocessor() const

Return the current preprocessor.

FrontendOptions & getFrontendOpts()

bool isDependentContext() const

Determines whether this context is dependent on a template parameter.

Decl - This represents one declaration (or definition), e.g.

virtual Stmt * getBody() const

getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...

virtual bool hasBody() const

Returns true if this Decl represents a declaration for a body of code, such as a function or method d...

SourceLocation getLocation() const

Concrete class used by the front-end to report problems and issues.

bool hasErrorOccurred() const

void setWarningsAsErrors(bool Val)

When set to true, any warnings reported are issued as errors.

bool hasFatalErrorOccurred() const

Recursive AST visitor that supports extension via dynamic dispatch.

virtual bool VisitDecl(Decl *D)

An opaque identifier used by SourceManager which refers to a source file (MemoryBuffer) along with it...

std::string OutputFile

The output file, if any.

std::vector< std::string > Plugins

The list of plugins to load.

Represents a function declaration or definition.

bool isThisDeclarationADefinition() const

Returns whether this specific declaration of the function is also a definition that does not contain ...

bool hasBody(const FunctionDecl *&Definition) const

Returns true if the function has a body.

One of these records is kept for each identifier that is lexed.

StringRef getName() const

Return the actual identifier string.

MacroExpansionContext tracks the macro expansions processed by the Preprocessor.

void registerForPreprocessor(Preprocessor &PP)

Register the necessary callbacks to the Preprocessor to record the expansion events and the generated...

IdentifierInfo * getIdentifier() const

Get the identifier that names this declaration, if there is one.

ObjCMethodDecl - Represents an instance or class method declaration.

bool isThisDeclarationADefinition() const

Returns whether this specific method is a definition.

ObjCMethodFamily getMethodFamily() const

Determines the family of this method.

Engages in a tight little dance with the lexer to efficiently preprocess tokens.

DiagnosticsEngine & getDiagnostics() const

Represents an unpacked "presumed" location which can be presented to the user.

Encodes a location in the source.

This class handles loading and caching of source files into memory.

Stmt - This represents one statement.

SourceLocation getBeginLoc() const LLVM_READONLY

The top declaration context.

Represents a variable declaration or definition.

bool isStaticDataMember() const

Determines whether this is a static data member.

bool hasExternalStorage() const

Returns true if a variable has extern or private_extern storage.

const Expr * getAnyInitializer() const

Get the initializer for this variable, no matter which declaration it is attached to.

This class is used for tools that requires cross translation unit capability.

llvm::Expected< const FunctionDecl * > getCrossTUDefinition(const FunctionDecl *FD, StringRef CrossTUDir, StringRef IndexName, bool DisplayCTUProgress=false)

This function loads a function or variable definition from an external AST file and merges it into th...

bool isImportedAsNew(const Decl *ToDecl) const

Returns true if the given Decl is newly created during the import.

virtual void AddCheckerRegistrationFn(std::function< void(CheckerRegistry &)> Fn)=0

This method allows registering statically linked custom checkers that are not a part of the Clang tre...

virtual void AddDiagnosticConsumer(PathDiagnosticConsumer *Consumer)=0

BugReporter is a utility class for generating PathDiagnostics for analysis.

Manages a set of available checkers for running a static analysis.

bool isValid() const =delete

InliningModes

The modes of inlining, which override the default analysis-wide settings.

@ Inline_Minimal

Do minimal inlining of callees.

@ Inline_Regular

Follow the default settings for inlining callees.

unsigned getTotalNumBasicBlocks()

unsigned getTotalNumVisitedBasicBlocks()

bool shouldImport(const VarDecl *VD, const ASTContext &ACtx)

Returns true if it makes sense to import a foreign variable definition.

std::unique_ptr< AnalysisASTConsumer > CreateAnalysisConsumer(CompilerInstance &CI)

CreateAnalysisConsumer - Creates an ASTConsumer to run various code analysis passes.

llvm::DenseSet< const Decl * > SetOfConstDecls

std::unique_ptr< ConstraintManager >(* ConstraintManagerCreator)(ProgramStateManager &, ExprEngine *)

std::vector< PathDiagnosticConsumer * > PathDiagnosticConsumers

std::unique_ptr< StoreManager >(* StoreManagerCreator)(ProgramStateManager &)

std::deque< Decl * > SetOfDecls

std::unique_ptr< StoreManager > CreateRegionStoreManager(ProgramStateManager &StMgr)

The JSON file list parser is used to communicate input to InstallAPI.