AnalysisConsumer.cpp revision 43dee220252ef0b42c5f8a3bb1eca97f84f2565f
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 "AnalysisConsumer.h" 15#include "clang/AST/ASTConsumer.h" 16#include "clang/AST/Decl.h" 17#include "clang/AST/DeclCXX.h" 18#include "clang/AST/DeclObjC.h" 19#include "clang/AST/ParentMap.h" 20#include "clang/Analysis/Analyses/LiveVariables.h" 21#include "clang/Analysis/Analyses/UninitializedValues.h" 22#include "clang/Analysis/CFG.h" 23#include "clang/StaticAnalyzer/Core/CheckerManager.h" 24#include "clang/StaticAnalyzer/Checkers/LocalCheckers.h" 25#include "clang/StaticAnalyzer/Core/BugReporter/PathDiagnostic.h" 26#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 27#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 28#include "clang/StaticAnalyzer/Core/PathSensitive/ExprEngine.h" 29#include "clang/StaticAnalyzer/Core/PathSensitive/TransferFuncs.h" 30#include "clang/StaticAnalyzer/Core/PathDiagnosticClients.h" 31 32// FIXME: Restructure checker registration. 33#include "../Checkers/ExperimentalChecks.h" 34#include "../Checkers/InternalChecks.h" 35 36#include "clang/Basic/FileManager.h" 37#include "clang/Basic/SourceManager.h" 38#include "clang/Frontend/AnalyzerOptions.h" 39#include "clang/Lex/Preprocessor.h" 40#include "llvm/Support/raw_ostream.h" 41#include "llvm/Support/Path.h" 42#include "llvm/Support/Program.h" 43#include "llvm/ADT/OwningPtr.h" 44 45using namespace clang; 46using namespace ento; 47 48static ExplodedNode::Auditor* CreateUbiViz(); 49 50//===----------------------------------------------------------------------===// 51// Special PathDiagnosticClients. 52//===----------------------------------------------------------------------===// 53 54static PathDiagnosticClient* 55createPlistHTMLDiagnosticClient(const std::string& prefix, 56 const Preprocessor &PP) { 57 PathDiagnosticClient *PD = 58 createHTMLDiagnosticClient(llvm::sys::path::parent_path(prefix), PP); 59 return createPlistDiagnosticClient(prefix, PP, PD); 60} 61 62//===----------------------------------------------------------------------===// 63// AnalysisConsumer declaration. 64//===----------------------------------------------------------------------===// 65 66namespace { 67 68class AnalysisConsumer : public ASTConsumer { 69public: 70 typedef void (*CodeAction)(AnalysisConsumer &C, AnalysisManager &M, Decl *D); 71 typedef void (*TUAction)(AnalysisConsumer &C, AnalysisManager &M, 72 TranslationUnitDecl &TU); 73 74private: 75 typedef std::vector<CodeAction> Actions; 76 typedef std::vector<TUAction> TUActions; 77 78 Actions FunctionActions; 79 Actions ObjCMethodActions; 80 Actions ObjCImplementationActions; 81 Actions CXXMethodActions; 82 TUActions TranslationUnitActions; // Remove this. 83 84public: 85 ASTContext* Ctx; 86 const Preprocessor &PP; 87 const std::string OutDir; 88 AnalyzerOptions Opts; 89 90 // PD is owned by AnalysisManager. 91 PathDiagnosticClient *PD; 92 93 StoreManagerCreator CreateStoreMgr; 94 ConstraintManagerCreator CreateConstraintMgr; 95 96 llvm::OwningPtr<CheckerManager> checkerMgr; 97 llvm::OwningPtr<AnalysisManager> Mgr; 98 99 AnalysisConsumer(const Preprocessor& pp, 100 const std::string& outdir, 101 const AnalyzerOptions& opts) 102 : Ctx(0), PP(pp), OutDir(outdir), 103 Opts(opts), PD(0) { 104 DigestAnalyzerOptions(); 105 } 106 107 void DigestAnalyzerOptions() { 108 // Create the PathDiagnosticClient. 109 if (!OutDir.empty()) { 110 switch (Opts.AnalysisDiagOpt) { 111 default: 112#define ANALYSIS_DIAGNOSTICS(NAME, CMDFLAG, DESC, CREATEFN, AUTOCREATE) \ 113 case PD_##NAME: PD = CREATEFN(OutDir, PP); break; 114#include "clang/Frontend/Analyses.def" 115 } 116 } else if (Opts.AnalysisDiagOpt == PD_TEXT) { 117 // Create the text client even without a specified output file since 118 // it just uses diagnostic notes. 119 PD = createTextPathDiagnosticClient("", PP); 120 } 121 122 // Create the analyzer component creators. 123 switch (Opts.AnalysisStoreOpt) { 124 default: 125 assert(0 && "Unknown store manager."); 126#define ANALYSIS_STORE(NAME, CMDFLAG, DESC, CREATEFN) \ 127 case NAME##Model: CreateStoreMgr = CREATEFN; break; 128#include "clang/Frontend/Analyses.def" 129 } 130 131 switch (Opts.AnalysisConstraintsOpt) { 132 default: 133 assert(0 && "Unknown store manager."); 134#define ANALYSIS_CONSTRAINTS(NAME, CMDFLAG, DESC, CREATEFN) \ 135 case NAME##Model: CreateConstraintMgr = CREATEFN; break; 136#include "clang/Frontend/Analyses.def" 137 } 138 } 139 140 void DisplayFunction(const Decl *D) { 141 if (!Opts.AnalyzerDisplayProgress) 142 return; 143 144 SourceManager &SM = Mgr->getASTContext().getSourceManager(); 145 PresumedLoc Loc = SM.getPresumedLoc(D->getLocation()); 146 if (Loc.isValid()) { 147 llvm::errs() << "ANALYZE: " << Loc.getFilename(); 148 149 if (isa<FunctionDecl>(D) || isa<ObjCMethodDecl>(D)) { 150 const NamedDecl *ND = cast<NamedDecl>(D); 151 llvm::errs() << ' ' << ND << '\n'; 152 } 153 else if (isa<BlockDecl>(D)) { 154 llvm::errs() << ' ' << "block(line:" << Loc.getLine() << ",col:" 155 << Loc.getColumn() << '\n'; 156 } 157 else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { 158 Selector S = MD->getSelector(); 159 llvm::errs() << ' ' << S.getAsString(); 160 } 161 } 162 } 163 164 void addCodeAction(CodeAction action) { 165 FunctionActions.push_back(action); 166 ObjCMethodActions.push_back(action); 167 CXXMethodActions.push_back(action); 168 } 169 170 void addTranslationUnitAction(TUAction action) { 171 TranslationUnitActions.push_back(action); 172 } 173 174 void addObjCImplementationAction(CodeAction action) { 175 ObjCImplementationActions.push_back(action); 176 } 177 178 virtual void Initialize(ASTContext &Context) { 179 Ctx = &Context; 180 checkerMgr.reset(registerCheckers(Opts, PP.getDiagnostics())); 181 Mgr.reset(new AnalysisManager(*Ctx, PP.getDiagnostics(), 182 PP.getLangOptions(), PD, 183 CreateStoreMgr, CreateConstraintMgr, 184 checkerMgr.get(), 185 /* Indexer */ 0, 186 Opts.MaxNodes, Opts.MaxLoop, 187 Opts.VisualizeEGDot, Opts.VisualizeEGUbi, 188 Opts.PurgeDead, Opts.EagerlyAssume, 189 Opts.TrimGraph, Opts.InlineCall, 190 Opts.UnoptimizedCFG, Opts.CFGAddImplicitDtors, 191 Opts.CFGAddInitializers, 192 Opts.EagerlyTrimEGraph)); 193 } 194 195 virtual void HandleTranslationUnit(ASTContext &C); 196 void HandleDeclContext(ASTContext &C, DeclContext *dc); 197 198 void HandleCode(Decl *D, Actions& actions); 199}; 200} // end anonymous namespace 201 202//===----------------------------------------------------------------------===// 203// AnalysisConsumer implementation. 204//===----------------------------------------------------------------------===// 205 206void AnalysisConsumer::HandleDeclContext(ASTContext &C, DeclContext *dc) { 207 for (DeclContext::decl_iterator I = dc->decls_begin(), E = dc->decls_end(); 208 I != E; ++I) { 209 Decl *D = *I; 210 211 switch (D->getKind()) { 212 case Decl::Namespace: { 213 HandleDeclContext(C, cast<NamespaceDecl>(D)); 214 break; 215 } 216 case Decl::CXXConstructor: 217 case Decl::CXXDestructor: 218 case Decl::CXXConversion: 219 case Decl::CXXMethod: 220 case Decl::Function: { 221 FunctionDecl* FD = cast<FunctionDecl>(D); 222 // We skip function template definitions, as their semantics is 223 // only determined when they are instantiated. 224 if (FD->isThisDeclarationADefinition() && 225 !FD->isDependentContext()) { 226 if (!Opts.AnalyzeSpecificFunction.empty() && 227 FD->getDeclName().getAsString() != Opts.AnalyzeSpecificFunction) 228 break; 229 DisplayFunction(FD); 230 HandleCode(FD, FunctionActions); 231 } 232 break; 233 } 234 235 case Decl::ObjCImplementation: { 236 ObjCImplementationDecl* ID = cast<ObjCImplementationDecl>(*I); 237 HandleCode(ID, ObjCImplementationActions); 238 239 for (ObjCImplementationDecl::method_iterator MI = ID->meth_begin(), 240 ME = ID->meth_end(); MI != ME; ++MI) { 241 if ((*MI)->isThisDeclarationADefinition()) { 242 if (!Opts.AnalyzeSpecificFunction.empty() && 243 Opts.AnalyzeSpecificFunction != (*MI)->getSelector().getAsString()) 244 break; 245 DisplayFunction(*MI); 246 HandleCode(*MI, ObjCMethodActions); 247 } 248 } 249 break; 250 } 251 252 default: 253 break; 254 } 255 } 256} 257 258void AnalysisConsumer::HandleTranslationUnit(ASTContext &C) { 259 TranslationUnitDecl *TU = C.getTranslationUnitDecl(); 260 HandleDeclContext(C, TU); 261 262 for (TUActions::iterator I = TranslationUnitActions.begin(), 263 E = TranslationUnitActions.end(); I != E; ++I) { 264 (*I)(*this, *Mgr, *TU); 265 } 266 267 // Explicitly destroy the PathDiagnosticClient. This will flush its output. 268 // FIXME: This should be replaced with something that doesn't rely on 269 // side-effects in PathDiagnosticClient's destructor. This is required when 270 // used with option -disable-free. 271 Mgr.reset(NULL); 272} 273 274static void FindBlocks(DeclContext *D, llvm::SmallVectorImpl<Decl*> &WL) { 275 if (BlockDecl *BD = dyn_cast<BlockDecl>(D)) 276 WL.push_back(BD); 277 278 for (DeclContext::decl_iterator I = D->decls_begin(), E = D->decls_end(); 279 I!=E; ++I) 280 if (DeclContext *DC = dyn_cast<DeclContext>(*I)) 281 FindBlocks(DC, WL); 282} 283 284void AnalysisConsumer::HandleCode(Decl *D, Actions& actions) { 285 286 // Don't run the actions if an error has occured with parsing the file. 287 Diagnostic &Diags = PP.getDiagnostics(); 288 if (Diags.hasErrorOccurred() || Diags.hasFatalErrorOccurred()) 289 return; 290 291 // Don't run the actions on declarations in header files unless 292 // otherwise specified. 293 SourceManager &SM = Ctx->getSourceManager(); 294 SourceLocation SL = SM.getInstantiationLoc(D->getLocation()); 295 if (!Opts.AnalyzeAll && !SM.isFromMainFile(SL)) 296 return; 297 298 // Clear the AnalysisManager of old AnalysisContexts. 299 Mgr->ClearContexts(); 300 301 // Dispatch on the actions. 302 llvm::SmallVector<Decl*, 10> WL; 303 WL.push_back(D); 304 305 if (D->hasBody() && Opts.AnalyzeNestedBlocks) 306 FindBlocks(cast<DeclContext>(D), WL); 307 308 for (Actions::iterator I = actions.begin(), E = actions.end(); I != E; ++I) 309 for (llvm::SmallVectorImpl<Decl*>::iterator WI=WL.begin(), WE=WL.end(); 310 WI != WE; ++WI) 311 (*I)(*this, *Mgr, *WI); 312} 313 314//===----------------------------------------------------------------------===// 315// Analyses 316//===----------------------------------------------------------------------===// 317 318static void ActionWarnDeadStores(AnalysisConsumer &C, AnalysisManager& mgr, 319 Decl *D) { 320 if (LiveVariables *L = mgr.getLiveVariables(D)) { 321 BugReporter BR(mgr); 322 CheckDeadStores(*mgr.getCFG(D), *L, mgr.getParentMap(D), BR); 323 } 324} 325 326static void ActionWarnUninitVals(AnalysisConsumer &C, AnalysisManager& mgr, 327 Decl *D) { 328 if (CFG* c = mgr.getCFG(D)) { 329 CheckUninitializedValues(*c, mgr.getASTContext(), mgr.getDiagnostic()); 330 } 331} 332 333 334static void ActionExprEngine(AnalysisConsumer &C, AnalysisManager& mgr, 335 Decl *D, 336 TransferFuncs* tf) { 337 338 llvm::OwningPtr<TransferFuncs> TF(tf); 339 340 // Construct the analysis engine. We first query for the LiveVariables 341 // information to see if the CFG is valid. 342 // FIXME: Inter-procedural analysis will need to handle invalid CFGs. 343 if (!mgr.getLiveVariables(D)) 344 return; 345 ExprEngine Eng(mgr, TF.take()); 346 347 if (C.Opts.EnableExperimentalInternalChecks) 348 RegisterExperimentalInternalChecks(Eng); 349 350 RegisterAppleChecks(Eng, *D); 351 352 if (C.Opts.EnableExperimentalChecks) 353 RegisterExperimentalChecks(Eng); 354 355 if (C.Opts.ObjCSelfInitCheck && isa<ObjCMethodDecl>(D)) 356 registerObjCSelfInitChecker(Eng); 357 358 // Enable idempotent operation checking if it was explicitly turned on, or if 359 // we are running experimental checks (i.e. everything) 360 if (C.Opts.IdempotentOps || C.Opts.EnableExperimentalChecks 361 || C.Opts.EnableExperimentalInternalChecks) 362 RegisterIdempotentOperationChecker(Eng); 363 364 if (C.Opts.BufferOverflows) 365 RegisterArrayBoundCheckerV2(Eng); 366 367 // Enable AnalyzerStatsChecker if it was given as an argument 368 if (C.Opts.AnalyzerStats) 369 RegisterAnalyzerStatsChecker(Eng); 370 371 // Set the graph auditor. 372 llvm::OwningPtr<ExplodedNode::Auditor> Auditor; 373 if (mgr.shouldVisualizeUbigraph()) { 374 Auditor.reset(CreateUbiViz()); 375 ExplodedNode::SetAuditor(Auditor.get()); 376 } 377 378 // Execute the worklist algorithm. 379 Eng.ExecuteWorkList(mgr.getStackFrame(D, 0), mgr.getMaxNodes()); 380 381 // Release the auditor (if any) so that it doesn't monitor the graph 382 // created BugReporter. 383 ExplodedNode::SetAuditor(0); 384 385 // Visualize the exploded graph. 386 if (mgr.shouldVisualizeGraphviz()) 387 Eng.ViewGraph(mgr.shouldTrimGraph()); 388 389 // Display warnings. 390 Eng.getBugReporter().FlushReports(); 391} 392 393static void ActionObjCMemCheckerAux(AnalysisConsumer &C, AnalysisManager& mgr, 394 Decl *D, bool GCEnabled) { 395 396 TransferFuncs* TF = MakeCFRefCountTF(mgr.getASTContext(), 397 GCEnabled, 398 mgr.getLangOptions()); 399 400 ActionExprEngine(C, mgr, D, TF); 401} 402 403static void ActionObjCMemChecker(AnalysisConsumer &C, AnalysisManager& mgr, 404 Decl *D) { 405 406 switch (mgr.getLangOptions().getGCMode()) { 407 default: 408 assert (false && "Invalid GC mode."); 409 case LangOptions::NonGC: 410 ActionObjCMemCheckerAux(C, mgr, D, false); 411 break; 412 413 case LangOptions::GCOnly: 414 ActionObjCMemCheckerAux(C, mgr, D, true); 415 break; 416 417 case LangOptions::HybridGC: 418 ActionObjCMemCheckerAux(C, mgr, D, false); 419 ActionObjCMemCheckerAux(C, mgr, D, true); 420 break; 421 } 422} 423 424static void ActionDisplayLiveVariables(AnalysisConsumer &C, 425 AnalysisManager& mgr, Decl *D) { 426 if (LiveVariables* L = mgr.getLiveVariables(D)) { 427 L->dumpBlockLiveness(mgr.getSourceManager()); 428 } 429} 430 431static void ActionCFGDump(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { 432 if (CFG *cfg = mgr.getCFG(D)) { 433 cfg->dump(mgr.getLangOptions()); 434 } 435} 436 437static void ActionCFGView(AnalysisConsumer &C, AnalysisManager& mgr, Decl *D) { 438 if (CFG *cfg = mgr.getCFG(D)) { 439 cfg->viewCFG(mgr.getLangOptions()); 440 } 441} 442 443static void ActionSecuritySyntacticChecks(AnalysisConsumer &C, 444 AnalysisManager &mgr, Decl *D) { 445 BugReporter BR(mgr); 446 CheckSecuritySyntaxOnly(D, BR); 447} 448 449static void ActionLLVMConventionChecker(AnalysisConsumer &C, 450 AnalysisManager &mgr, 451 TranslationUnitDecl &TU) { 452 BugReporter BR(mgr); 453 CheckLLVMConventions(TU, BR); 454} 455 456static void ActionWarnObjCDealloc(AnalysisConsumer &C, AnalysisManager& mgr, 457 Decl *D) { 458 if (mgr.getLangOptions().getGCMode() == LangOptions::GCOnly) 459 return; 460 BugReporter BR(mgr); 461 CheckObjCDealloc(cast<ObjCImplementationDecl>(D), mgr.getLangOptions(), BR); 462} 463 464static void ActionWarnObjCUnusedIvars(AnalysisConsumer &C, AnalysisManager& mgr, 465 Decl *D) { 466 BugReporter BR(mgr); 467 CheckObjCUnusedIvar(cast<ObjCImplementationDecl>(D), BR); 468} 469 470static void ActionWarnObjCMethSigs(AnalysisConsumer &C, AnalysisManager& mgr, 471 Decl *D) { 472 BugReporter BR(mgr); 473 CheckObjCInstMethSignature(cast<ObjCImplementationDecl>(D), BR); 474} 475 476static void ActionWarnSizeofPointer(AnalysisConsumer &C, AnalysisManager &mgr, 477 Decl *D) { 478 BugReporter BR(mgr); 479 CheckSizeofPointer(D, BR); 480} 481 482//===----------------------------------------------------------------------===// 483// AnalysisConsumer creation. 484//===----------------------------------------------------------------------===// 485 486ASTConsumer* ento::CreateAnalysisConsumer(const Preprocessor& pp, 487 const std::string& OutDir, 488 const AnalyzerOptions& Opts) { 489 llvm::OwningPtr<AnalysisConsumer> C(new AnalysisConsumer(pp, OutDir, Opts)); 490 491 for (unsigned i = 0; i < Opts.AnalysisList.size(); ++i) 492 switch (Opts.AnalysisList[i]) { 493#define ANALYSIS(NAME, CMD, DESC, SCOPE)\ 494 case NAME:\ 495 C->add ## SCOPE ## Action(&Action ## NAME);\ 496 break; 497#include "clang/Frontend/Analyses.def" 498 default: break; 499 } 500 501 // Last, disable the effects of '-Werror' when using the AnalysisConsumer. 502 pp.getDiagnostics().setWarningsAsErrors(false); 503 504 return C.take(); 505} 506 507//===----------------------------------------------------------------------===// 508// Ubigraph Visualization. FIXME: Move to separate file. 509//===----------------------------------------------------------------------===// 510 511namespace { 512 513class UbigraphViz : public ExplodedNode::Auditor { 514 llvm::OwningPtr<llvm::raw_ostream> Out; 515 llvm::sys::Path Dir, Filename; 516 unsigned Cntr; 517 518 typedef llvm::DenseMap<void*,unsigned> VMap; 519 VMap M; 520 521public: 522 UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir, 523 llvm::sys::Path& filename); 524 525 ~UbigraphViz(); 526 527 virtual void AddEdge(ExplodedNode* Src, ExplodedNode* Dst); 528}; 529 530} // end anonymous namespace 531 532static ExplodedNode::Auditor* CreateUbiViz() { 533 std::string ErrMsg; 534 535 llvm::sys::Path Dir = llvm::sys::Path::GetTemporaryDirectory(&ErrMsg); 536 if (!ErrMsg.empty()) 537 return 0; 538 539 llvm::sys::Path Filename = Dir; 540 Filename.appendComponent("llvm_ubi"); 541 Filename.makeUnique(true,&ErrMsg); 542 543 if (!ErrMsg.empty()) 544 return 0; 545 546 llvm::errs() << "Writing '" << Filename.str() << "'.\n"; 547 548 llvm::OwningPtr<llvm::raw_fd_ostream> Stream; 549 Stream.reset(new llvm::raw_fd_ostream(Filename.c_str(), ErrMsg)); 550 551 if (!ErrMsg.empty()) 552 return 0; 553 554 return new UbigraphViz(Stream.take(), Dir, Filename); 555} 556 557void UbigraphViz::AddEdge(ExplodedNode* Src, ExplodedNode* Dst) { 558 559 assert (Src != Dst && "Self-edges are not allowed."); 560 561 // Lookup the Src. If it is a new node, it's a root. 562 VMap::iterator SrcI= M.find(Src); 563 unsigned SrcID; 564 565 if (SrcI == M.end()) { 566 M[Src] = SrcID = Cntr++; 567 *Out << "('vertex', " << SrcID << ", ('color','#00ff00'))\n"; 568 } 569 else 570 SrcID = SrcI->second; 571 572 // Lookup the Dst. 573 VMap::iterator DstI= M.find(Dst); 574 unsigned DstID; 575 576 if (DstI == M.end()) { 577 M[Dst] = DstID = Cntr++; 578 *Out << "('vertex', " << DstID << ")\n"; 579 } 580 else { 581 // We have hit DstID before. Change its style to reflect a cache hit. 582 DstID = DstI->second; 583 *Out << "('change_vertex_style', " << DstID << ", 1)\n"; 584 } 585 586 // Add the edge. 587 *Out << "('edge', " << SrcID << ", " << DstID 588 << ", ('arrow','true'), ('oriented', 'true'))\n"; 589} 590 591UbigraphViz::UbigraphViz(llvm::raw_ostream* out, llvm::sys::Path& dir, 592 llvm::sys::Path& filename) 593 : Out(out), Dir(dir), Filename(filename), Cntr(0) { 594 595 *Out << "('vertex_style_attribute', 0, ('shape', 'icosahedron'))\n"; 596 *Out << "('vertex_style', 1, 0, ('shape', 'sphere'), ('color', '#ffcc66')," 597 " ('size', '1.5'))\n"; 598} 599 600UbigraphViz::~UbigraphViz() { 601 Out.reset(0); 602 llvm::errs() << "Running 'ubiviz' program... "; 603 std::string ErrMsg; 604 llvm::sys::Path Ubiviz = llvm::sys::Program::FindProgramByName("ubiviz"); 605 std::vector<const char*> args; 606 args.push_back(Ubiviz.c_str()); 607 args.push_back(Filename.c_str()); 608 args.push_back(0); 609 610 if (llvm::sys::Program::ExecuteAndWait(Ubiviz, &args[0],0,0,0,0,&ErrMsg)) { 611 llvm::errs() << "Error viewing graph: " << ErrMsg << "\n"; 612 } 613 614 // Delete the directory. 615 Dir.eraseFromDisk(true); 616} 617