clang  3.9.0
VirtualCallChecker.cpp
Go to the documentation of this file.
1 //=======- VirtualCallChecker.cpp --------------------------------*- C++ -*-==//
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 // This file defines a checker that checks virtual function calls during
11 // construction or destruction of C++ objects.
12 //
13 //===----------------------------------------------------------------------===//
14 
15 #include "ClangSACheckers.h"
16 #include "clang/AST/DeclCXX.h"
17 #include "clang/AST/StmtVisitor.h"
21 #include "llvm/ADT/SmallString.h"
22 #include "llvm/Support/SaveAndRestore.h"
23 #include "llvm/Support/raw_ostream.h"
24 
25 using namespace clang;
26 using namespace ento;
27 
28 namespace {
29 
30 class WalkAST : public StmtVisitor<WalkAST> {
31  const CheckerBase *Checker;
32  BugReporter &BR;
34 
35  typedef const CallExpr * WorkListUnit;
36  typedef SmallVector<WorkListUnit, 20> DFSWorkList;
37 
38  /// A vector representing the worklist which has a chain of CallExprs.
39  DFSWorkList WList;
40 
41  // PreVisited : A CallExpr to this FunctionDecl is in the worklist, but the
42  // body has not been visited yet.
43  // PostVisited : A CallExpr to this FunctionDecl is in the worklist, and the
44  // body has been visited.
45  enum Kind { NotVisited,
46  PreVisited, /**< A CallExpr to this FunctionDecl is in the
47  worklist, but the body has not yet been
48  visited. */
49  PostVisited /**< A CallExpr to this FunctionDecl is in the
50  worklist, and the body has been visited. */
51  };
52 
53  /// A DenseMap that records visited states of FunctionDecls.
54  llvm::DenseMap<const FunctionDecl *, Kind> VisitedFunctions;
55 
56  /// The CallExpr whose body is currently being visited. This is used for
57  /// generating bug reports. This is null while visiting the body of a
58  /// constructor or destructor.
59  const CallExpr *visitingCallExpr;
60 
61 public:
62  WalkAST(const CheckerBase *checker, BugReporter &br,
64  : Checker(checker), BR(br), AC(ac), visitingCallExpr(nullptr) {}
65 
66  bool hasWork() const { return !WList.empty(); }
67 
68  /// This method adds a CallExpr to the worklist and marks the callee as
69  /// being PreVisited.
70  void Enqueue(WorkListUnit WLUnit) {
71  const FunctionDecl *FD = WLUnit->getDirectCallee();
72  if (!FD || !FD->getBody())
73  return;
74  Kind &K = VisitedFunctions[FD];
75  if (K != NotVisited)
76  return;
77  K = PreVisited;
78  WList.push_back(WLUnit);
79  }
80 
81  /// This method returns an item from the worklist without removing it.
82  WorkListUnit Dequeue() {
83  assert(!WList.empty());
84  return WList.back();
85  }
86 
87  void Execute() {
88  while (hasWork()) {
89  WorkListUnit WLUnit = Dequeue();
90  const FunctionDecl *FD = WLUnit->getDirectCallee();
91  assert(FD && FD->getBody());
92 
93  if (VisitedFunctions[FD] == PreVisited) {
94  // If the callee is PreVisited, walk its body.
95  // Visit the body.
96  SaveAndRestore<const CallExpr *> SaveCall(visitingCallExpr, WLUnit);
97  Visit(FD->getBody());
98 
99  // Mark the function as being PostVisited to indicate we have
100  // scanned the body.
101  VisitedFunctions[FD] = PostVisited;
102  continue;
103  }
104 
105  // Otherwise, the callee is PostVisited.
106  // Remove it from the worklist.
107  assert(VisitedFunctions[FD] == PostVisited);
108  WList.pop_back();
109  }
110  }
111 
112  // Stmt visitor methods.
113  void VisitCallExpr(CallExpr *CE);
114  void VisitCXXMemberCallExpr(CallExpr *CE);
115  void VisitStmt(Stmt *S) { VisitChildren(S); }
116  void VisitChildren(Stmt *S);
117 
118  void ReportVirtualCall(const CallExpr *CE, bool isPure);
119 
120 };
121 } // end anonymous namespace
122 
123 //===----------------------------------------------------------------------===//
124 // AST walking.
125 //===----------------------------------------------------------------------===//
126 
127 void WalkAST::VisitChildren(Stmt *S) {
128  for (Stmt *Child : S->children())
129  if (Child)
130  Visit(Child);
131 }
132 
133 void WalkAST::VisitCallExpr(CallExpr *CE) {
134  VisitChildren(CE);
135  Enqueue(CE);
136 }
137 
138 void WalkAST::VisitCXXMemberCallExpr(CallExpr *CE) {
139  VisitChildren(CE);
140  bool callIsNonVirtual = false;
141 
142  // Several situations to elide for checking.
143  if (MemberExpr *CME = dyn_cast<MemberExpr>(CE->getCallee())) {
144  // If the member access is fully qualified (i.e., X::F), then treat
145  // this as a non-virtual call and do not warn.
146  if (CME->getQualifier())
147  callIsNonVirtual = true;
148 
149  if (Expr *base = CME->getBase()->IgnoreImpCasts()) {
150  // Elide analyzing the call entirely if the base pointer is not 'this'.
151  if (!isa<CXXThisExpr>(base))
152  return;
153 
154  // If the most derived class is marked final, we know that now subclass
155  // can override this member.
156  if (base->getBestDynamicClassType()->hasAttr<FinalAttr>())
157  callIsNonVirtual = true;
158  }
159  }
160 
161  // Get the callee.
162  const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CE->getDirectCallee());
163  if (MD && MD->isVirtual() && !callIsNonVirtual && !MD->hasAttr<FinalAttr>() &&
164  !MD->getParent()->hasAttr<FinalAttr>())
165  ReportVirtualCall(CE, MD->isPure());
166 
167  Enqueue(CE);
168 }
169 
170 void WalkAST::ReportVirtualCall(const CallExpr *CE, bool isPure) {
171  SmallString<100> buf;
172  llvm::raw_svector_ostream os(buf);
173 
174  os << "Call Path : ";
175  // Name of current visiting CallExpr.
176  os << *CE->getDirectCallee();
177 
178  // Name of the CallExpr whose body is current walking.
179  if (visitingCallExpr)
180  os << " <-- " << *visitingCallExpr->getDirectCallee();
181  // Names of FunctionDecls in worklist with state PostVisited.
183  E = WList.begin(); I != E; --I) {
184  const FunctionDecl *FD = (*(I-1))->getDirectCallee();
185  assert(FD);
186  if (VisitedFunctions[FD] == PostVisited)
187  os << " <-- " << *FD;
188  }
189 
190  PathDiagnosticLocation CELoc =
191  PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
192  SourceRange R = CE->getCallee()->getSourceRange();
193 
194  if (isPure) {
195  os << "\n" << "Call pure virtual functions during construction or "
196  << "destruction may leads undefined behaviour";
197  BR.EmitBasicReport(AC->getDecl(), Checker,
198  "Call pure virtual function during construction or "
199  "Destruction",
200  "Cplusplus", os.str(), CELoc, R);
201  return;
202  }
203  else {
204  os << "\n" << "Call virtual functions during construction or "
205  << "destruction will never go to a more derived class";
206  BR.EmitBasicReport(AC->getDecl(), Checker,
207  "Call virtual function during construction or "
208  "Destruction",
209  "Cplusplus", os.str(), CELoc, R);
210  return;
211  }
212 }
213 
214 //===----------------------------------------------------------------------===//
215 // VirtualCallChecker
216 //===----------------------------------------------------------------------===//
217 
218 namespace {
219 class VirtualCallChecker : public Checker<check::ASTDecl<CXXRecordDecl> > {
220 public:
221  void checkASTDecl(const CXXRecordDecl *RD, AnalysisManager& mgr,
222  BugReporter &BR) const {
223  WalkAST walker(this, BR, mgr.getAnalysisDeclContext(RD));
224 
225  // Check the constructors.
226  for (const auto *I : RD->ctors()) {
227  if (!I->isCopyOrMoveConstructor())
228  if (Stmt *Body = I->getBody()) {
229  walker.Visit(Body);
230  walker.Execute();
231  }
232  }
233 
234  // Check the destructor.
235  if (CXXDestructorDecl *DD = RD->getDestructor())
236  if (Stmt *Body = DD->getBody()) {
237  walker.Visit(Body);
238  walker.Execute();
239  }
240  }
241 };
242 }
243 
244 void ento::registerVirtualCallChecker(CheckerManager &mgr) {
245  mgr.registerChecker<VirtualCallChecker>();
246 }
FunctionDecl - An instance of this class is created to represent a function declaration or definition...
Definition: Decl.h:1561
ctor_range ctors() const
Definition: DeclCXX.h:779
const Expr * getCallee() const
Definition: Expr.h:2188
Expr * IgnoreImpCasts() LLVM_READONLY
IgnoreImpCasts - Skip past any implicit casts which might surround this expression.
Definition: Expr.h:2777
AnalysisDeclContext contains the context data for the function or method under analysis.
bool isPure() const
Whether this virtual function is pure, i.e.
Definition: Decl.h:1837
const CXXRecordDecl * getParent() const
Returns the parent of this method declaration, which is the class in which this method is defined...
Definition: DeclCXX.h:1838
detail::InMemoryDirectory::const_iterator I
AnalysisDeclContext * getAnalysisDeclContext(const Decl *D)
Expr - This represents one expression.
Definition: Expr.h:105
bool isVirtual() const
Definition: DeclCXX.h:1780
Represents a C++ destructor within a class.
Definition: DeclCXX.h:2414
BugReporter is a utility class for generating PathDiagnostics for analysis.
Definition: BugReporter.h:388
Stmt * getBody(const FunctionDecl *&Definition) const
getBody - Retrieve the body (definition) of the function.
Definition: Decl.cpp:2491
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
Kind
CHECKER * registerChecker()
Used to register checkers.
Represents a static or instance method of a struct/union/class.
Definition: DeclCXX.h:1736
StmtVisitor - This class implements a simple visitor for Stmt subclasses.
Definition: StmtVisitor.h:178
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return 0.
Definition: Expr.cpp:1209
CXXDestructorDecl * getDestructor() const
Returns the destructor decl for this class.
Definition: DeclCXX.cpp:1375
detail::InMemoryDirectory::const_iterator E
Defines the C++ Decl subclasses, other than those for templates (found in DeclTemplate.h) and friends (in DeclFriend.h).
MemberExpr - [C99 6.5.2.3] Structure and Union Members.
Definition: Expr.h:2315
Represents a C++ struct/union/class.
Definition: DeclCXX.h:263
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2148
A trivial tuple used to represent a source range.