blob: 7e1fc1eb54adfe221499eca01830e44d895bf51c [file] [log] [blame]
Ted Kremenekb3512d32012-01-03 23:18:57 +00001//=======- 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"
Ted Kremenekb3512d32012-01-03 23:18:57 +000018#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000019#include "clang/StaticAnalyzer/Core/Checker.h"
20#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
Benjamin Kramer49038022012-02-04 13:45:25 +000021#include "llvm/ADT/SmallString.h"
Chandler Carruth3a022472012-12-04 09:13:33 +000022#include "llvm/Support/SaveAndRestore.h"
Benjamin Kramer444a1302012-12-01 17:12:56 +000023#include "llvm/Support/raw_ostream.h"
Ted Kremenekb3512d32012-01-03 23:18:57 +000024
25using namespace clang;
26using namespace ento;
27
28namespace {
29
30class WalkAST : public StmtVisitor<WalkAST> {
Alexander Kornienko4aca9b12014-02-11 21:49:21 +000031 const CheckerBase *Checker;
Ted Kremenekb3512d32012-01-03 23:18:57 +000032 BugReporter &BR;
33 AnalysisDeclContext *AC;
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. */
Benjamin Kramerd1d76b22012-06-06 17:32:50 +000051 };
Ted Kremenekb3512d32012-01-03 23:18:57 +000052
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
61public:
Alexander Kornienko4aca9b12014-02-11 21:49:21 +000062 WalkAST(const CheckerBase *checker, BugReporter &br,
63 AnalysisDeclContext *ac)
Craig Topper0dbb7832014-05-27 02:45:47 +000064 : Checker(checker), BR(br), AC(ac), visitingCallExpr(nullptr) {}
Alexander Kornienko4aca9b12014-02-11 21:49:21 +000065
Ted Kremenekb3512d32012-01-03 23:18:57 +000066 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
127void WalkAST::VisitChildren(Stmt *S) {
128 for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I)
129 if (Stmt *child = *I)
130 Visit(child);
131}
132
133void WalkAST::VisitCallExpr(CallExpr *CE) {
134 VisitChildren(CE);
135 Enqueue(CE);
136}
137
138void 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
Benjamin Kramercb4efc12014-08-21 10:25:03 +0000149 if (Expr *base = CME->getBase()->IgnoreImpCasts()) {
150 // Elide analyzing the call entirely if the base pointer is not 'this'.
Ted Kremenekb3512d32012-01-03 23:18:57 +0000151 if (!isa<CXXThisExpr>(base))
152 return;
Benjamin Kramercb4efc12014-08-21 10:25:03 +0000153
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 }
Ted Kremenekb3512d32012-01-03 23:18:57 +0000159 }
160
161 // Get the callee.
162 const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CE->getDirectCallee());
Benjamin Kramercb4efc12014-08-21 10:25:03 +0000163 if (MD && MD->isVirtual() && !callIsNonVirtual && !MD->hasAttr<FinalAttr>() &&
164 !MD->getParent()->hasAttr<FinalAttr>())
Ted Kremenekb3512d32012-01-03 23:18:57 +0000165 ReportVirtualCall(CE, MD->isPure());
166
167 Enqueue(CE);
168}
169
170void WalkAST::ReportVirtualCall(const CallExpr *CE, bool isPure) {
Dylan Noblesmith2c1dd272012-02-05 02:13:05 +0000171 SmallString<100> buf;
Ted Kremenekb3512d32012-01-03 23:18:57 +0000172 llvm::raw_svector_ostream os(buf);
173
174 os << "Call Path : ";
175 // Name of current visiting CallExpr.
Benjamin Kramerdb0fc512012-02-07 11:57:57 +0000176 os << *CE->getDirectCallee();
Ted Kremenekb3512d32012-01-03 23:18:57 +0000177
178 // Name of the CallExpr whose body is current walking.
179 if (visitingCallExpr)
Benjamin Kramerdb0fc512012-02-07 11:57:57 +0000180 os << " <-- " << *visitingCallExpr->getDirectCallee();
Ted Kremenekb3512d32012-01-03 23:18:57 +0000181 // Names of FunctionDecls in worklist with state PostVisited.
182 for (SmallVectorImpl<const CallExpr *>::iterator I = WList.end(),
183 E = WList.begin(); I != E; --I) {
184 const FunctionDecl *FD = (*(I-1))->getDirectCallee();
185 assert(FD);
186 if (VisitedFunctions[FD] == PostVisited)
Benjamin Kramerdb0fc512012-02-07 11:57:57 +0000187 os << " <-- " << *FD;
Ted Kremenekb3512d32012-01-03 23:18:57 +0000188 }
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";
Alexander Kornienko4aca9b12014-02-11 21:49:21 +0000197 BR.EmitBasicReport(AC->getDecl(), Checker,
Ted Kremenek5a10f082012-04-04 18:11:35 +0000198 "Call pure virtual function during construction or "
Ted Kremenekb3512d32012-01-03 23:18:57 +0000199 "Destruction",
Alexander Kornienko4aca9b12014-02-11 21:49:21 +0000200 "Cplusplus", os.str(), CELoc, R);
Ted Kremenekb3512d32012-01-03 23:18:57 +0000201 return;
202 }
203 else {
204 os << "\n" << "Call virtual functions during construction or "
205 << "destruction will never go to a more derived class";
Alexander Kornienko4aca9b12014-02-11 21:49:21 +0000206 BR.EmitBasicReport(AC->getDecl(), Checker,
Ted Kremenek5a10f082012-04-04 18:11:35 +0000207 "Call virtual function during construction or "
Ted Kremenekb3512d32012-01-03 23:18:57 +0000208 "Destruction",
Alexander Kornienko4aca9b12014-02-11 21:49:21 +0000209 "Cplusplus", os.str(), CELoc, R);
Ted Kremenekb3512d32012-01-03 23:18:57 +0000210 return;
211 }
212}
213
214//===----------------------------------------------------------------------===//
215// VirtualCallChecker
216//===----------------------------------------------------------------------===//
217
218namespace {
219class VirtualCallChecker : public Checker<check::ASTDecl<CXXRecordDecl> > {
220public:
221 void checkASTDecl(const CXXRecordDecl *RD, AnalysisManager& mgr,
222 BugReporter &BR) const {
Alexander Kornienko4aca9b12014-02-11 21:49:21 +0000223 WalkAST walker(this, BR, mgr.getAnalysisDeclContext(RD));
Ted Kremenekb3512d32012-01-03 23:18:57 +0000224
225 // Check the constructors.
Aaron Ballman2a4bd6d2014-03-13 16:51:27 +0000226 for (const auto *I : RD->ctors()) {
Ted Kremenekb3512d32012-01-03 23:18:57 +0000227 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};
Alexander Kornienkoab9db512015-06-22 23:07:51 +0000242}
Ted Kremenekb3512d32012-01-03 23:18:57 +0000243
244void ento::registerVirtualCallChecker(CheckerManager &mgr) {
245 mgr.registerChecker<VirtualCallChecker>();
246}