VirtualCallChecker.cpp 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  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. #include "ClangSACheckers.h"
  15. #include "clang/AST/DeclCXX.h"
  16. #include "clang/AST/StmtVisitor.h"
  17. #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
  18. #include "clang/StaticAnalyzer/Core/Checker.h"
  19. #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h"
  20. #include "llvm/ADT/SmallString.h"
  21. #include "llvm/Support/SaveAndRestore.h"
  22. #include "llvm/Support/raw_ostream.h"
  23. using namespace clang;
  24. using namespace ento;
  25. namespace {
  26. class WalkAST : public StmtVisitor<WalkAST> {
  27. const CheckerBase *Checker;
  28. BugReporter &BR;
  29. AnalysisDeclContext *AC;
  30. typedef const CallExpr * WorkListUnit;
  31. typedef SmallVector<WorkListUnit, 20> DFSWorkList;
  32. /// A vector representing the worklist which has a chain of CallExprs.
  33. DFSWorkList WList;
  34. // PreVisited : A CallExpr to this FunctionDecl is in the worklist, but the
  35. // body has not been visited yet.
  36. // PostVisited : A CallExpr to this FunctionDecl is in the worklist, and the
  37. // body has been visited.
  38. enum Kind { NotVisited,
  39. PreVisited, /**< A CallExpr to this FunctionDecl is in the
  40. worklist, but the body has not yet been
  41. visited. */
  42. PostVisited /**< A CallExpr to this FunctionDecl is in the
  43. worklist, and the body has been visited. */
  44. };
  45. /// A DenseMap that records visited states of FunctionDecls.
  46. llvm::DenseMap<const FunctionDecl *, Kind> VisitedFunctions;
  47. /// The CallExpr whose body is currently being visited. This is used for
  48. /// generating bug reports. This is null while visiting the body of a
  49. /// constructor or destructor.
  50. const CallExpr *visitingCallExpr;
  51. public:
  52. WalkAST(const CheckerBase *checker, BugReporter &br,
  53. AnalysisDeclContext *ac)
  54. : Checker(checker), BR(br), AC(ac), visitingCallExpr(nullptr) {}
  55. bool hasWork() const { return !WList.empty(); }
  56. /// This method adds a CallExpr to the worklist and marks the callee as
  57. /// being PreVisited.
  58. void Enqueue(WorkListUnit WLUnit) {
  59. const FunctionDecl *FD = WLUnit->getDirectCallee();
  60. if (!FD || !FD->getBody())
  61. return;
  62. Kind &K = VisitedFunctions[FD];
  63. if (K != NotVisited)
  64. return;
  65. K = PreVisited;
  66. WList.push_back(WLUnit);
  67. }
  68. /// This method returns an item from the worklist without removing it.
  69. WorkListUnit Dequeue() {
  70. assert(!WList.empty());
  71. return WList.back();
  72. }
  73. void Execute() {
  74. while (hasWork()) {
  75. WorkListUnit WLUnit = Dequeue();
  76. const FunctionDecl *FD = WLUnit->getDirectCallee();
  77. assert(FD && FD->getBody());
  78. if (VisitedFunctions[FD] == PreVisited) {
  79. // If the callee is PreVisited, walk its body.
  80. // Visit the body.
  81. SaveAndRestore<const CallExpr *> SaveCall(visitingCallExpr, WLUnit);
  82. Visit(FD->getBody());
  83. // Mark the function as being PostVisited to indicate we have
  84. // scanned the body.
  85. VisitedFunctions[FD] = PostVisited;
  86. continue;
  87. }
  88. // Otherwise, the callee is PostVisited.
  89. // Remove it from the worklist.
  90. assert(VisitedFunctions[FD] == PostVisited);
  91. WList.pop_back();
  92. }
  93. }
  94. // Stmt visitor methods.
  95. void VisitCallExpr(CallExpr *CE);
  96. void VisitCXXMemberCallExpr(CallExpr *CE);
  97. void VisitStmt(Stmt *S) { VisitChildren(S); }
  98. void VisitChildren(Stmt *S);
  99. void ReportVirtualCall(const CallExpr *CE, bool isPure);
  100. };
  101. } // end anonymous namespace
  102. //===----------------------------------------------------------------------===//
  103. // AST walking.
  104. //===----------------------------------------------------------------------===//
  105. void WalkAST::VisitChildren(Stmt *S) {
  106. for (Stmt *Child : S->children())
  107. if (Child)
  108. Visit(Child);
  109. }
  110. void WalkAST::VisitCallExpr(CallExpr *CE) {
  111. VisitChildren(CE);
  112. Enqueue(CE);
  113. }
  114. void WalkAST::VisitCXXMemberCallExpr(CallExpr *CE) {
  115. VisitChildren(CE);
  116. bool callIsNonVirtual = false;
  117. // Several situations to elide for checking.
  118. if (MemberExpr *CME = dyn_cast<MemberExpr>(CE->getCallee())) {
  119. // If the member access is fully qualified (i.e., X::F), then treat
  120. // this as a non-virtual call and do not warn.
  121. if (CME->getQualifier())
  122. callIsNonVirtual = true;
  123. if (Expr *base = CME->getBase()->IgnoreImpCasts()) {
  124. // Elide analyzing the call entirely if the base pointer is not 'this'.
  125. if (!isa<CXXThisExpr>(base))
  126. return;
  127. // If the most derived class is marked final, we know that now subclass
  128. // can override this member.
  129. if (base->getBestDynamicClassType()->hasAttr<FinalAttr>())
  130. callIsNonVirtual = true;
  131. }
  132. }
  133. // Get the callee.
  134. const CXXMethodDecl *MD = dyn_cast<CXXMethodDecl>(CE->getDirectCallee());
  135. if (MD && MD->isVirtual() && !callIsNonVirtual && !MD->hasAttr<FinalAttr>() &&
  136. !MD->getParent()->hasAttr<FinalAttr>())
  137. ReportVirtualCall(CE, MD->isPure());
  138. Enqueue(CE);
  139. }
  140. void WalkAST::ReportVirtualCall(const CallExpr *CE, bool isPure) {
  141. SmallString<100> buf;
  142. llvm::raw_svector_ostream os(buf);
  143. os << "Call Path : ";
  144. // Name of current visiting CallExpr.
  145. os << *CE->getDirectCallee();
  146. // Name of the CallExpr whose body is current walking.
  147. if (visitingCallExpr)
  148. os << " <-- " << *visitingCallExpr->getDirectCallee();
  149. // Names of FunctionDecls in worklist with state PostVisited.
  150. for (SmallVectorImpl<const CallExpr *>::iterator I = WList.end(),
  151. E = WList.begin(); I != E; --I) {
  152. const FunctionDecl *FD = (*(I-1))->getDirectCallee();
  153. assert(FD);
  154. if (VisitedFunctions[FD] == PostVisited)
  155. os << " <-- " << *FD;
  156. }
  157. PathDiagnosticLocation CELoc =
  158. PathDiagnosticLocation::createBegin(CE, BR.getSourceManager(), AC);
  159. SourceRange R = CE->getCallee()->getSourceRange();
  160. if (isPure) {
  161. os << "\n" << "Call pure virtual functions during construction or "
  162. << "destruction may leads undefined behaviour";
  163. BR.EmitBasicReport(AC->getDecl(), Checker,
  164. "Call pure virtual function during construction or "
  165. "Destruction",
  166. "Cplusplus", os.str(), CELoc, R);
  167. return;
  168. }
  169. else {
  170. os << "\n" << "Call virtual functions during construction or "
  171. << "destruction will never go to a more derived class";
  172. BR.EmitBasicReport(AC->getDecl(), Checker,
  173. "Call virtual function during construction or "
  174. "Destruction",
  175. "Cplusplus", os.str(), CELoc, R);
  176. return;
  177. }
  178. }
  179. //===----------------------------------------------------------------------===//
  180. // VirtualCallChecker
  181. //===----------------------------------------------------------------------===//
  182. namespace {
  183. class VirtualCallChecker : public Checker<check::ASTDecl<CXXRecordDecl> > {
  184. public:
  185. void checkASTDecl(const CXXRecordDecl *RD, AnalysisManager& mgr,
  186. BugReporter &BR) const {
  187. WalkAST walker(this, BR, mgr.getAnalysisDeclContext(RD));
  188. // Check the constructors.
  189. for (const auto *I : RD->ctors()) {
  190. if (!I->isCopyOrMoveConstructor())
  191. if (Stmt *Body = I->getBody()) {
  192. walker.Visit(Body);
  193. walker.Execute();
  194. }
  195. }
  196. // Check the destructor.
  197. if (CXXDestructorDecl *DD = RD->getDestructor())
  198. if (Stmt *Body = DD->getBody()) {
  199. walker.Visit(Body);
  200. walker.Execute();
  201. }
  202. }
  203. };
  204. }
  205. void ento::registerVirtualCallChecker(CheckerManager &mgr) {
  206. mgr.registerChecker<VirtualCallChecker>();
  207. }