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