clang API Documentation
00001 //=======- VirtualCallChecker.cpp --------------------------------*- C++ -*-==// 00002 // 00003 // The LLVM Compiler Infrastructure 00004 // 00005 // This file is distributed under the University of Illinois Open Source 00006 // License. See LICENSE.TXT for details. 00007 // 00008 //===----------------------------------------------------------------------===// 00009 // 00010 // This file defines a checker that checks virtual function calls during 00011 // construction or destruction of C++ objects. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #include "ClangSACheckers.h" 00016 #include "clang/AST/DeclCXX.h" 00017 #include "clang/AST/StmtVisitor.h" 00018 #include "llvm/Support/SaveAndRestore.h" 00019 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 00020 #include "clang/StaticAnalyzer/Core/Checker.h" 00021 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 00022 #include "llvm/ADT/SmallString.h" 00023 00024 using namespace clang; 00025 using namespace ento; 00026 00027 namespace { 00028 00029 class WalkAST : public StmtVisitor<WalkAST> { 00030 BugReporter &BR; 00031 AnalysisDeclContext *AC; 00032 00033 typedef const CallExpr * WorkListUnit; 00034 typedef SmallVector<WorkListUnit, 20> DFSWorkList; 00035 00036 /// A vector representing the worklist which has a chain of CallExprs. 00037 DFSWorkList WList; 00038 00039 // PreVisited : A CallExpr to this FunctionDecl is in the worklist, but the 00040 // body has not been visited yet. 00041 // PostVisited : A CallExpr to this FunctionDecl is in the worklist, and the 00042 // body has been visited. 00043 enum Kind { NotVisited, 00044 PreVisited, /**< A CallExpr to this FunctionDecl is in the 00045 worklist, but the body has not yet been 00046 visited. */ 00047 PostVisited /**< A CallExpr to this FunctionDecl is in the 00048 worklist, and the body has been visited. */ 00049 } K; 00050 00051 /// A DenseMap that records visited states of FunctionDecls. 00052 llvm::DenseMap<const FunctionDecl *, Kind> VisitedFunctions; 00053 00054 /// The CallExpr whose body is currently being visited. This is used for 00055 /// generating bug reports. This is null while visiting the body of a 00056 /// constructor or destructor. 00057 const CallExpr *visitingCallExpr; 00058 00059 public: 00060 WalkAST(BugReporter &br, AnalysisDeclContext *ac) 00061 : BR(br), 00062 AC(ac), 00063 visitingCallExpr(0) {} 00064 00065 bool hasWork() const { return !WList.empty(); } 00066 00067 /// This method adds a CallExpr to the worklist and marks the callee as 00068 /// being PreVisited. 00069 void Enqueue(WorkListUnit WLUnit) { 00070 const FunctionDecl *FD = WLUnit->getDirectCallee(); 00071 if (!FD || !FD->getBody()) 00072 return; 00073 Kind &K = VisitedFunctions[FD]; 00074 if (K != NotVisited) 00075 return; 00076 K = PreVisited; 00077 WList.push_back(WLUnit); 00078 } 00079 00080 /// This method returns an item from the worklist without removing it. 00081 WorkListUnit Dequeue() { 00082 assert(!WList.empty()); 00083 return WList.back(); 00084 } 00085 00086 void Execute() { 00087 while (hasWork()) { 00088 WorkListUnit WLUnit = Dequeue(); 00089 const FunctionDecl *FD = WLUnit->getDirectCallee(); 00090 assert(FD && FD->getBody()); 00091 00092 if (VisitedFunctions[FD] == PreVisited) { 00093 // If the callee is PreVisited, walk its body. 00094 // Visit the body. 00095 SaveAndRestore<const CallExpr *> SaveCall(visitingCallExpr, WLUnit); 00096 Visit(FD->getBody()); 00097 00098 // Mark the function as being PostVisited to indicate we have 00099 // scanned the body. 00100 VisitedFunctions[FD] = PostVisited; 00101 continue; 00102 } 00103 00104 // Otherwise, the callee is PostVisited. 00105 // Remove it from the worklist. 00106 assert(VisitedFunctions[FD] == PostVisited); 00107 WList.pop_back(); 00108 } 00109 } 00110 00111 // Stmt visitor methods. 00112 void VisitCallExpr(CallExpr *CE); 00113 void VisitCXXMemberCallExpr(CallExpr *CE); 00114 void VisitStmt(Stmt *S) { VisitChildren(S); } 00115 void VisitChildren(Stmt *S); 00116 00117 void ReportVirtualCall(const CallExpr *CE, bool isPure); 00118 00119 }; 00120 } // end anonymous namespace 00121 00122 //===----------------------------------------------------------------------===// 00123 // AST walking. 00124 //===----------------------------------------------------------------------===// 00125 00126 void WalkAST::VisitChildren(Stmt *S) { 00127 for (Stmt::child_iterator I = S->child_begin(), E = S->child_end(); I!=E; ++I) 00128 if (Stmt *child = *I) 00129 Visit(child); 00130 } 00131 00132 void WalkAST::VisitCallExpr(CallExpr *CE) { 00133 VisitChildren(CE); 00134 Enqueue(CE); 00135 } 00136 00137 void WalkAST::VisitCXXMemberCallExpr(CallExpr *CE) { 00138 VisitChildren(CE); 00139 bool callIsNonVirtual = false; 00140 00141 // Several situations to elide for checking. 00142 if (MemberExpr *CME = dyn_cast<MemberExpr>(CE->getCallee())) { 00143 // If the member access is fully qualified (i.e., X::F), then treat 00144 // this as a non-virtual call and do not warn. 00145 if (CME->getQualifier()) 00146 callIsNonVirtual = true; 00147 00148 // Elide analyzing the call entirely if the base pointer is not 'this'. 00149 if (Expr *base = CME->getBase()->IgnoreImpCasts()) 00150 if (!isa<CXXThisExpr>(base)) 00151 return; 00152 } 00153 00154 // Get the callee. 00155 const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CE->getDirectCallee()); 00156 if (MD && MD->isVirtual() && !callIsNonVirtual) 00157 ReportVirtualCall(CE, MD->isPure()); 00158 00159 Enqueue(CE); 00160 } 00161 00162 void WalkAST::ReportVirtualCall(const CallExpr *CE, bool isPure) { 00163 SmallString<100> buf; 00164 llvm::raw_svector_ostream os(buf); 00165 00166 os << "Call Path : "; 00167 // Name of current visiting CallExpr. 00168 os << *CE->getDirectCallee(); 00169 00170 // Name of the CallExpr whose body is current walking. 00171 if (visitingCallExpr) 00172 os << " <-- " << *visitingCallExpr->getDirectCallee(); 00173 // Names of FunctionDecls in worklist with state PostVisited. 00174 for (SmallVectorImpl<const CallExpr *>::iterator I = WList.end(), 00175 E = WList.begin(); I != E; --I) { 00176 const FunctionDecl *FD = (*(I-1))->getDirectCallee(); 00177 assert(FD); 00178 if (VisitedFunctions[FD] == PostVisited) 00179 os << " <-- " << *FD; 00180 } 00181 00182 PathDiagnosticLocation CELoc = 00183 PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC); 00184 SourceRange R = CE->getCallee()->getSourceRange(); 00185 00186 if (isPure) { 00187 os << "\n" << "Call pure virtual functions during construction or " 00188 << "destruction may leads undefined behaviour"; 00189 BR.EmitBasicReport(AC->getDecl(), 00190 "Call pure virtual function during construction or " 00191 "Destruction", 00192 "Cplusplus", 00193 os.str(), CELoc, &R, 1); 00194 return; 00195 } 00196 else { 00197 os << "\n" << "Call virtual functions during construction or " 00198 << "destruction will never go to a more derived class"; 00199 BR.EmitBasicReport(AC->getDecl(), 00200 "Call virtual function during construction or " 00201 "Destruction", 00202 "Cplusplus", 00203 os.str(), CELoc, &R, 1); 00204 return; 00205 } 00206 } 00207 00208 //===----------------------------------------------------------------------===// 00209 // VirtualCallChecker 00210 //===----------------------------------------------------------------------===// 00211 00212 namespace { 00213 class VirtualCallChecker : public Checker<check::ASTDecl<CXXRecordDecl> > { 00214 public: 00215 void checkASTDecl(const CXXRecordDecl *RD, AnalysisManager& mgr, 00216 BugReporter &BR) const { 00217 WalkAST walker(BR, mgr.getAnalysisDeclContext(RD)); 00218 00219 // Check the constructors. 00220 for (CXXRecordDecl::ctor_iterator I = RD->ctor_begin(), E = RD->ctor_end(); 00221 I != E; ++I) { 00222 if (!I->isCopyOrMoveConstructor()) 00223 if (Stmt *Body = I->getBody()) { 00224 walker.Visit(Body); 00225 walker.Execute(); 00226 } 00227 } 00228 00229 // Check the destructor. 00230 if (CXXDestructorDecl *DD = RD->getDestructor()) 00231 if (Stmt *Body = DD->getBody()) { 00232 walker.Visit(Body); 00233 walker.Execute(); 00234 } 00235 } 00236 }; 00237 } 00238 00239 void ento::registerVirtualCallChecker(CheckerManager &mgr) { 00240 mgr.registerChecker<VirtualCallChecker>(); 00241 }