VirtualCallChecker.cpp revision 07189521a15d9c088216b943649cb9fe231cbb57
19e49fb63d355446b91d20ff78ad78b297e89a50dcaryclark@google.com//=======- VirtualCallChecker.cpp --------------------------------*- C++ -*-==// 29e49fb63d355446b91d20ff78ad78b297e89a50dcaryclark@google.com// 39e49fb63d355446b91d20ff78ad78b297e89a50dcaryclark@google.com// The LLVM Compiler Infrastructure 49e49fb63d355446b91d20ff78ad78b297e89a50dcaryclark@google.com// 59e49fb63d355446b91d20ff78ad78b297e89a50dcaryclark@google.com// This file is distributed under the University of Illinois Open Source 69e49fb63d355446b91d20ff78ad78b297e89a50dcaryclark@google.com// License. See LICENSE.TXT for details. 7a3f05facab01712a1b58e60a70b0dbdb90a39830caryclark@google.com// 88dcf114db9762c02d217beba6e29dffa4e92d298caryclark@google.com//===----------------------------------------------------------------------===// 9fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com// 10fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com// This file defines a checker that checks virtual function calls during 11fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com// construction or destruction of C++ objects. 12fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com// 13fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com//===----------------------------------------------------------------------===// 14fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com 15fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#include "ClangSACheckers.h" 16fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#include "clang/AST/DeclCXX.h" 17fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#include "clang/AST/StmtVisitor.h" 18fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#include "llvm/Support/SaveAndRestore.h" 19fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 20fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#include "clang/StaticAnalyzer/Core/Checker.h" 21fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 22fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com#include "llvm/ADT/SmallString.h" 23fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com 24fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comusing namespace clang; 25fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comusing namespace ento; 26fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com 27fa0588ff672564af1c235a63589573829035a60bcaryclark@google.comnamespace { 28fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com 2945a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.comclass WalkAST : public StmtVisitor<WalkAST> { 30fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com BugReporter &BR; 31fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com AnalysisDeclContext *AC; 3245a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com 3345a8fc6a8b00451f807783f2a6ec640e9bcc7256caryclark@google.com typedef const CallExpr * WorkListUnit; 34fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com typedef SmallVector<WorkListUnit, 20> DFSWorkList; 35fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com 36fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com /// A vector representing the worklist which has a chain of CallExprs. 37fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com DFSWorkList WList; 38fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com 39fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com // PreVisited : A CallExpr to this FunctionDecl is in the worklist, but the 40fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com // body has not been visited yet. 41fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com // PostVisited : A CallExpr to this FunctionDecl is in the worklist, and the 42fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com // body has been visited. 43fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com enum Kind { NotVisited, 44fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com PreVisited, /**< A CallExpr to this FunctionDecl is in the 45fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com worklist, but the body has not yet been 46fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com visited. */ 47fa0588ff672564af1c235a63589573829035a60bcaryclark@google.com 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 59public: 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 126void 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 132void WalkAST::VisitCallExpr(CallExpr *CE) { 133 VisitChildren(CE); 134 Enqueue(CE); 135} 136 137void 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 162void 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 212namespace { 213class VirtualCallChecker : public Checker<check::ASTDecl<CXXRecordDecl> > { 214public: 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 239void ento::registerVirtualCallChecker(CheckerManager &mgr) { 240 mgr.registerChecker<VirtualCallChecker>(); 241} 242