VirtualCallChecker.cpp revision 07189521a15d9c088216b943649cb9fe231cbb57
19e49fb63d355446b91d20ff78ad78b297e89a50dcaryclark@google.com//=======- VirtualCallChecker.cpp --------------------------------*- C++ -*-==//
29e49fb63d355446b91d20ff78ad78b297e89a50dcaryclark@google.com//
39e49fb63d355446b91d20ff78ad78b297e89a50dcaryclark@google.com//                     The LLVM Compiler Infrastructure
49e49fb63d355446b91d20ff78ad78b297e89a50dcaryclark@google.com//
59e49fb63d355446b91d20ff78ad78b297e89a50dcaryclark@google.com// This file is distributed under the University of Illinois Open Source
69e49fb63d355446b91d20ff78ad78b297e89a50dcaryclark@google.com// License. See LICENSE.TXT for details.
7a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com//
88dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com//===----------------------------------------------------------------------===//
9fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com//
10fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com//  This file defines a checker that checks virtual function calls during
11fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com//  construction or destruction of C++ objects.
12fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com//
13fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com//===----------------------------------------------------------------------===//
14fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
15fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#include "ClangSACheckers.h"
16fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#include "clang/AST/DeclCXX.h"
17fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#include "clang/AST/StmtVisitor.h"
18fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#include "llvm/Support/SaveAndRestore.h"
19fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
20fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#include "clang/StaticAnalyzer/Core/Checker.h"
21fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
22fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#include "llvm/ADT/SmallString.h"
23fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
24fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comusing namespace clang;
25fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comusing namespace ento;
26fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
27fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comnamespace {
28fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
2945a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.comclass WalkAST : public StmtVisitor<WalkAST> {
30fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com  BugReporter &BR;
31fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com  AnalysisDeclContext *AC;
3245a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com
3345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com  typedef const CallExpr * WorkListUnit;
34fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com  typedef SmallVector<WorkListUnit, 20> DFSWorkList;
35fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
36fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com  /// A vector representing the worklist which has a chain of CallExprs.
37fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com  DFSWorkList WList;
38fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com
39fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com  // PreVisited : A CallExpr to this FunctionDecl is in the worklist, but the
40fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com  // body has not been visited yet.
41fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com  // PostVisited : A CallExpr to this FunctionDecl is in the worklist, and the
42fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com  // body has been visited.
43fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com  enum Kind { NotVisited,
44fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com              PreVisited,  /**< A CallExpr to this FunctionDecl is in the
45fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                                worklist, but the body has not yet been
46fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com                                visited. */
47fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com              PostVisited  /**< A CallExpr to this FunctionDecl is in the
48                                worklist, and the body has been visited. */
49  } K;
50
51  /// A DenseMap that records visited states of FunctionDecls.
52  llvm::DenseMap<const FunctionDecl *, Kind> VisitedFunctions;
53
54  /// The CallExpr whose body is currently being visited.  This is used for
55  /// generating bug reports.  This is null while visiting the body of a
56  /// constructor or destructor.
57  const CallExpr *visitingCallExpr;
58
59public:
60  WalkAST(BugReporter &br, AnalysisDeclContext *ac)
61    : BR(br),
62      AC(ac),
63      visitingCallExpr(0) {}
64
65  bool hasWork() const { return !WList.empty(); }
66
67  /// This method adds a CallExpr to the worklist and marks the callee as
68  /// being PreVisited.
69  void Enqueue(WorkListUnit WLUnit) {
70    const FunctionDecl *FD = WLUnit->getDirectCallee();
71    if (!FD || !FD->getBody())
72      return;
73    Kind &K = VisitedFunctions[FD];
74    if (K != NotVisited)
75      return;
76    K = PreVisited;
77    WList.push_back(WLUnit);
78  }
79
80  /// This method returns an item from the worklist without removing it.
81  WorkListUnit Dequeue() {
82    assert(!WList.empty());
83    return WList.back();
84  }
85
86  void Execute() {
87    while (hasWork()) {
88      WorkListUnit WLUnit = Dequeue();
89      const FunctionDecl *FD = WLUnit->getDirectCallee();
90      assert(FD && FD->getBody());
91
92      if (VisitedFunctions[FD] == PreVisited) {
93        // If the callee is PreVisited, walk its body.
94        // Visit the body.
95        SaveAndRestore<const CallExpr *> SaveCall(visitingCallExpr, WLUnit);
96        Visit(FD->getBody());
97
98        // Mark the function as being PostVisited to indicate we have
99        // scanned the body.
100        VisitedFunctions[FD] = PostVisited;
101        continue;
102      }
103
104      // Otherwise, the callee is PostVisited.
105      // Remove it from the worklist.
106      assert(VisitedFunctions[FD] == PostVisited);
107      WList.pop_back();
108    }
109  }
110
111  // Stmt visitor methods.
112  void VisitCallExpr(CallExpr *CE);
113  void VisitCXXMemberCallExpr(CallExpr *CE);
114  void VisitStmt(Stmt *S) { VisitChildren(S); }
115  void VisitChildren(Stmt *S);
116
117  void ReportVirtualCall(const CallExpr *CE, bool isPure);
118
119};
120} // end anonymous namespace
121
122//===----------------------------------------------------------------------===//
123// AST walking.
124//===----------------------------------------------------------------------===//
125
126void WalkAST::VisitChildren(Stmt *S) {
127  for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
128    if (Stmt *child = *I)
129      Visit(child);
130}
131
132void WalkAST::VisitCallExpr(CallExpr *CE) {
133  VisitChildren(CE);
134  Enqueue(CE);
135}
136
137void WalkAST::VisitCXXMemberCallExpr(CallExpr *CE) {
138  VisitChildren(CE);
139  bool callIsNonVirtual = false;
140
141  // Several situations to elide for checking.
142  if (MemberExpr *CME = dyn_cast<MemberExpr>(CE->getCallee())) {
143    // If the member access is fully qualified (i.e., X::F), then treat
144    // this as a non-virtual call and do not warn.
145    if (CME->getQualifier())
146      callIsNonVirtual = true;
147
148    // Elide analyzing the call entirely if the base pointer is not 'this'.
149    if (Expr *base = CME->getBase()->IgnoreImpCasts())
150      if (!isa<CXXThisExpr>(base))
151        return;
152  }
153
154  // Get the callee.
155  const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CE->getDirectCallee());
156  if (MD && MD->isVirtual() && !callIsNonVirtual)
157    ReportVirtualCall(CE, MD->isPure());
158
159  Enqueue(CE);
160}
161
162void WalkAST::ReportVirtualCall(const CallExpr *CE, bool isPure) {
163  SmallString<100> buf;
164  llvm::raw_svector_ostream os(buf);
165
166  os << "Call Path : ";
167  // Name of current visiting CallExpr.
168  os << *CE->getDirectCallee();
169
170  // Name of the CallExpr whose body is current walking.
171  if (visitingCallExpr)
172    os << " <-- " << *visitingCallExpr->getDirectCallee();
173  // Names of FunctionDecls in worklist with state PostVisited.
174  for (SmallVectorImpl<const CallExpr *>::iterator I = WList.end(),
175         E = WList.begin(); I != E; --I) {
176    const FunctionDecl *FD = (*(I-1))->getDirectCallee();
177    assert(FD);
178    if (VisitedFunctions[FD] == PostVisited)
179      os << " <-- " << *FD;
180  }
181
182  PathDiagnosticLocation CELoc =
183    PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
184  SourceRange R = CE->getCallee()->getSourceRange();
185
186  if (isPure) {
187    os << "\n" <<  "Call pure virtual functions during construction or "
188       << "destruction may leads undefined behaviour";
189    BR.EmitBasicReport(AC->getDecl(),
190                       "Call pure virtual function during construction or "
191                       "Destruction",
192                       "Cplusplus",
193                       os.str(), CELoc, &R, 1);
194    return;
195  }
196  else {
197    os << "\n" << "Call virtual functions during construction or "
198       << "destruction will never go to a more derived class";
199    BR.EmitBasicReport(AC->getDecl(),
200                       "Call virtual function during construction or "
201                       "Destruction",
202                       "Cplusplus",
203                       os.str(), CELoc, &R, 1);
204    return;
205  }
206}
207
208//===----------------------------------------------------------------------===//
209// VirtualCallChecker
210//===----------------------------------------------------------------------===//
211
212namespace {
213class VirtualCallChecker : public Checker<check::ASTDecl<CXXRecordDecl> > {
214public:
215  void checkASTDecl(const CXXRecordDecl *RD, AnalysisManager& mgr,
216                    BugReporter &BR) const {
217    WalkAST walker(BR, mgr.getAnalysisDeclContext(RD));
218
219    // Check the constructors.
220    for (CXXRecordDecl::ctor_iterator I = RD->ctor_begin(), E = RD->ctor_end();
221         I != E; ++I) {
222      if (!I->isCopyOrMoveConstructor())
223        if (Stmt *Body = I->getBody()) {
224          walker.Visit(Body);
225          walker.Execute();
226        }
227    }
228
229    // Check the destructor.
230    if (CXXDestructorDecl *DD = RD->getDestructor())
231      if (Stmt *Body = DD->getBody()) {
232        walker.Visit(Body);
233        walker.Execute();
234      }
235  }
236};
237}
238
239void ento::registerVirtualCallChecker(CheckerManager &mgr) {
240  mgr.registerChecker<VirtualCallChecker>();
241}
242