]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
Merge ACPICA 20170929 (take 2).
[FreeBSD/FreeBSD.git] / contrib / llvm / tools / clang / lib / StaticAnalyzer / Checkers / VirtualCallChecker.cpp
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"
18 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
19 #include "clang/StaticAnalyzer/Core/Checker.h"
20 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.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;
33   AnalysisDeclContext *AC;
34
35   /// The root constructor or destructor whose callees are being analyzed.
36   const CXXMethodDecl *RootMethod = nullptr;
37
38   /// Whether the checker should walk into bodies of called functions.
39   /// Controlled by the "Interprocedural" analyzer-config option.
40   bool IsInterprocedural = false;
41
42   /// Whether the checker should only warn for calls to pure virtual functions
43   /// (which is undefined behavior) or for all virtual functions (which may
44   /// may result in unexpected behavior).
45   bool ReportPureOnly = false;
46
47   typedef const CallExpr * WorkListUnit;
48   typedef SmallVector<WorkListUnit, 20> DFSWorkList;
49
50   /// A vector representing the worklist which has a chain of CallExprs.
51   DFSWorkList WList;
52
53   // PreVisited : A CallExpr to this FunctionDecl is in the worklist, but the
54   // body has not been visited yet.
55   // PostVisited : A CallExpr to this FunctionDecl is in the worklist, and the
56   // body has been visited.
57   enum Kind { NotVisited,
58               PreVisited,  /**< A CallExpr to this FunctionDecl is in the
59                                 worklist, but the body has not yet been
60                                 visited. */
61               PostVisited  /**< A CallExpr to this FunctionDecl is in the
62                                 worklist, and the body has been visited. */
63   };
64
65   /// A DenseMap that records visited states of FunctionDecls.
66   llvm::DenseMap<const FunctionDecl *, Kind> VisitedFunctions;
67
68   /// The CallExpr whose body is currently being visited.  This is used for
69   /// generating bug reports.  This is null while visiting the body of a
70   /// constructor or destructor.
71   const CallExpr *visitingCallExpr;
72
73 public:
74   WalkAST(const CheckerBase *checker, BugReporter &br, AnalysisDeclContext *ac,
75           const CXXMethodDecl *rootMethod, bool isInterprocedural,
76           bool reportPureOnly)
77       : Checker(checker), BR(br), AC(ac), RootMethod(rootMethod),
78         IsInterprocedural(isInterprocedural), ReportPureOnly(reportPureOnly),
79         visitingCallExpr(nullptr) {
80     // Walking should always start from either a constructor or a destructor.
81     assert(isa<CXXConstructorDecl>(rootMethod) ||
82            isa<CXXDestructorDecl>(rootMethod));
83   }
84
85   bool hasWork() const { return !WList.empty(); }
86
87   /// This method adds a CallExpr to the worklist and marks the callee as
88   /// being PreVisited.
89   void Enqueue(WorkListUnit WLUnit) {
90     const FunctionDecl *FD = WLUnit->getDirectCallee();
91     if (!FD || !FD->getBody())
92       return;
93     Kind &K = VisitedFunctions[FD];
94     if (K != NotVisited)
95       return;
96     K = PreVisited;
97     WList.push_back(WLUnit);
98   }
99
100   /// This method returns an item from the worklist without removing it.
101   WorkListUnit Dequeue() {
102     assert(!WList.empty());
103     return WList.back();
104   }
105
106   void Execute() {
107     while (hasWork()) {
108       WorkListUnit WLUnit = Dequeue();
109       const FunctionDecl *FD = WLUnit->getDirectCallee();
110       assert(FD && FD->getBody());
111
112       if (VisitedFunctions[FD] == PreVisited) {
113         // If the callee is PreVisited, walk its body.
114         // Visit the body.
115         SaveAndRestore<const CallExpr *> SaveCall(visitingCallExpr, WLUnit);
116         Visit(FD->getBody());
117
118         // Mark the function as being PostVisited to indicate we have
119         // scanned the body.
120         VisitedFunctions[FD] = PostVisited;
121         continue;
122       }
123
124       // Otherwise, the callee is PostVisited.
125       // Remove it from the worklist.
126       assert(VisitedFunctions[FD] == PostVisited);
127       WList.pop_back();
128     }
129   }
130
131   // Stmt visitor methods.
132   void VisitCallExpr(CallExpr *CE);
133   void VisitCXXMemberCallExpr(CallExpr *CE);
134   void VisitStmt(Stmt *S) { VisitChildren(S); }
135   void VisitChildren(Stmt *S);
136
137   void ReportVirtualCall(const CallExpr *CE, bool isPure);
138
139 };
140 } // end anonymous namespace
141
142 //===----------------------------------------------------------------------===//
143 // AST walking.
144 //===----------------------------------------------------------------------===//
145
146 void WalkAST::VisitChildren(Stmt *S) {
147   for (Stmt *Child : S->children())
148     if (Child)
149       Visit(Child);
150 }
151
152 void WalkAST::VisitCallExpr(CallExpr *CE) {
153   VisitChildren(CE);
154   if (IsInterprocedural)
155     Enqueue(CE);
156 }
157
158 void WalkAST::VisitCXXMemberCallExpr(CallExpr *CE) {
159   VisitChildren(CE);
160   bool callIsNonVirtual = false;
161
162   // Several situations to elide for checking.
163   if (MemberExpr *CME = dyn_cast<MemberExpr>(CE->getCallee())) {
164     // If the member access is fully qualified (i.e., X::F), then treat
165     // this as a non-virtual call and do not warn.
166     if (CME->getQualifier())
167       callIsNonVirtual = true;
168
169     if (Expr *base = CME->getBase()->IgnoreImpCasts()) {
170       // Elide analyzing the call entirely if the base pointer is not 'this'.
171       if (!isa<CXXThisExpr>(base))
172         return;
173
174       // If the most derived class is marked final, we know that now subclass
175       // can override this member.
176       if (base->getBestDynamicClassType()->hasAttr<FinalAttr>())
177         callIsNonVirtual = true;
178     }
179   }
180
181   // Get the callee.
182   const CXXMethodDecl *MD =
183       dyn_cast_or_null<CXXMethodDecl>(CE->getDirectCallee());
184   if (MD && MD->isVirtual() && !callIsNonVirtual && !MD->hasAttr<FinalAttr>() &&
185       !MD->getParent()->hasAttr<FinalAttr>())
186     ReportVirtualCall(CE, MD->isPure());
187
188   if (IsInterprocedural)
189     Enqueue(CE);
190 }
191
192 void WalkAST::ReportVirtualCall(const CallExpr *CE, bool isPure) {
193   if (ReportPureOnly && !isPure)
194     return;
195
196   SmallString<100> buf;
197   llvm::raw_svector_ostream os(buf);
198
199   // FIXME: The interprocedural diagnostic experience here is not good.
200   // Ultimately this checker should be re-written to be path sensitive.
201   // For now, only diagnose intraprocedurally, by default.
202   if (IsInterprocedural) {
203     os << "Call Path : ";
204     // Name of current visiting CallExpr.
205     os << *CE->getDirectCallee();
206
207     // Name of the CallExpr whose body is current being walked.
208     if (visitingCallExpr)
209       os << " <-- " << *visitingCallExpr->getDirectCallee();
210     // Names of FunctionDecls in worklist with state PostVisited.
211     for (SmallVectorImpl<const CallExpr *>::iterator I = WList.end(),
212          E = WList.begin(); I != E; --I) {
213       const FunctionDecl *FD = (*(I-1))->getDirectCallee();
214       assert(FD);
215       if (VisitedFunctions[FD] == PostVisited)
216         os << " <-- " << *FD;
217     }
218
219     os << "\n";
220   }
221
222   PathDiagnosticLocation CELoc =
223     PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
224   SourceRange R = CE->getCallee()->getSourceRange();
225
226   os << "Call to ";
227   if (isPure)
228     os << "pure ";
229
230   os << "virtual function during ";
231
232   if (isa<CXXConstructorDecl>(RootMethod))
233     os << "construction ";
234   else
235     os << "destruction ";
236
237   if (isPure)
238     os << "has undefined behavior";
239   else
240     os << "will not dispatch to derived class";
241
242   BR.EmitBasicReport(AC->getDecl(), Checker,
243                      "Call to virtual function during construction or "
244                      "destruction",
245                      "C++ Object Lifecycle", os.str(), CELoc, R);
246 }
247
248 //===----------------------------------------------------------------------===//
249 // VirtualCallChecker
250 //===----------------------------------------------------------------------===//
251
252 namespace {
253 class VirtualCallChecker : public Checker<check::ASTDecl<CXXRecordDecl> > {
254 public:
255   DefaultBool isInterprocedural;
256   DefaultBool isPureOnly;
257
258   void checkASTDecl(const CXXRecordDecl *RD, AnalysisManager& mgr,
259                     BugReporter &BR) const {
260     AnalysisDeclContext *ADC = mgr.getAnalysisDeclContext(RD);
261
262     // Check the constructors.
263     for (const auto *I : RD->ctors()) {
264       if (!I->isCopyOrMoveConstructor())
265         if (Stmt *Body = I->getBody()) {
266           WalkAST walker(this, BR, ADC, I, isInterprocedural, isPureOnly);
267           walker.Visit(Body);
268           walker.Execute();
269         }
270     }
271
272     // Check the destructor.
273     if (CXXDestructorDecl *DD = RD->getDestructor())
274       if (Stmt *Body = DD->getBody()) {
275         WalkAST walker(this, BR, ADC, DD, isInterprocedural, isPureOnly);
276         walker.Visit(Body);
277         walker.Execute();
278       }
279   }
280 };
281 }
282
283 void ento::registerVirtualCallChecker(CheckerManager &mgr) {
284   VirtualCallChecker *checker = mgr.registerChecker<VirtualCallChecker>();
285   checker->isInterprocedural =
286       mgr.getAnalyzerOptions().getBooleanOption("Interprocedural", false,
287                                                 checker);
288
289   checker->isPureOnly =
290       mgr.getAnalyzerOptions().getBooleanOption("PureOnly", false,
291                                                 checker);
292 }