clang API Documentation

VirtualCallChecker.cpp
Go to the documentation of this file.
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 }