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