]> CyberLeo.Net >> Repos - FreeBSD/stable/9.git/blob - contrib/llvm/tools/clang/lib/StaticAnalyzer/Checkers/VirtualCallChecker.cpp
MFC r234353:
[FreeBSD/stable/9.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 "llvm/Support/SaveAndRestore.h"
19 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
20 #include "clang/StaticAnalyzer/Core/Checker.h"
21 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
22 #include "llvm/ADT/SmallString.h"
23
24 using namespace clang;
25 using namespace ento;
26
27 namespace {
28
29 class WalkAST : public StmtVisitor<WalkAST> {
30   BugReporter &BR;
31   AnalysisDeclContext *AC;
32
33   typedef const CallExpr * WorkListUnit;
34   typedef SmallVector<WorkListUnit, 20> DFSWorkList;
35
36   /// A vector representing the worklist which has a chain of CallExprs.
37   DFSWorkList WList;
38   
39   // PreVisited : A CallExpr to this FunctionDecl is in the worklist, but the
40   // body has not been visited yet.
41   // PostVisited : A CallExpr to this FunctionDecl is in the worklist, and the
42   // body has been visited.
43   enum Kind { NotVisited,
44               PreVisited,  /**< A CallExpr to this FunctionDecl is in the 
45                                 worklist, but the body has not yet been
46                                 visited. */
47               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   
59 public:
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
126 void 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
132 void WalkAST::VisitCallExpr(CallExpr *CE) {
133   VisitChildren(CE);
134   Enqueue(CE);
135 }
136
137 void 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
162 void 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
212 namespace {
213 class VirtualCallChecker : public Checker<check::ASTDecl<CXXRecordDecl> > {
214 public:
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
239 void ento::registerVirtualCallChecker(CheckerManager &mgr) {
240   mgr.registerChecker<VirtualCallChecker>();
241 }