LLVMConventionsChecker.cpp 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318
  1. //=== LLVMConventionsChecker.cpp - Check LLVM codebase conventions ---*- 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 defines LLVMConventionsChecker, a bunch of small little checks
  11. // for checking specific coding conventions in the LLVM/Clang codebase.
  12. //
  13. //===----------------------------------------------------------------------===//
  14. #include "ClangSACheckers.h"
  15. #include "clang/AST/DeclTemplate.h"
  16. #include "clang/AST/StmtVisitor.h"
  17. #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h"
  18. #include "clang/StaticAnalyzer/Core/Checker.h"
  19. #include "llvm/ADT/SmallString.h"
  20. #include "llvm/Support/raw_ostream.h"
  21. using namespace clang;
  22. using namespace ento;
  23. //===----------------------------------------------------------------------===//
  24. // Generic type checking routines.
  25. //===----------------------------------------------------------------------===//
  26. static bool IsLLVMStringRef(QualType T) {
  27. const RecordType *RT = T->getAs<RecordType>();
  28. if (!RT)
  29. return false;
  30. return StringRef(QualType(RT, 0).getAsString()) ==
  31. "class StringRef";
  32. }
  33. /// Check whether the declaration is semantically inside the top-level
  34. /// namespace named by ns.
  35. static bool InNamespace(const Decl *D, StringRef NS) {
  36. const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext());
  37. if (!ND)
  38. return false;
  39. const IdentifierInfo *II = ND->getIdentifier();
  40. if (!II || !II->getName().equals(NS))
  41. return false;
  42. return isa<TranslationUnitDecl>(ND->getDeclContext());
  43. }
  44. static bool IsStdString(QualType T) {
  45. if (const ElaboratedType *QT = T->getAs<ElaboratedType>())
  46. T = QT->getNamedType();
  47. const TypedefType *TT = T->getAs<TypedefType>();
  48. if (!TT)
  49. return false;
  50. const TypedefNameDecl *TD = TT->getDecl();
  51. if (!TD->isInStdNamespace())
  52. return false;
  53. return TD->getName() == "string";
  54. }
  55. static bool IsClangType(const RecordDecl *RD) {
  56. return RD->getName() == "Type" && InNamespace(RD, "clang");
  57. }
  58. static bool IsClangDecl(const RecordDecl *RD) {
  59. return RD->getName() == "Decl" && InNamespace(RD, "clang");
  60. }
  61. static bool IsClangStmt(const RecordDecl *RD) {
  62. return RD->getName() == "Stmt" && InNamespace(RD, "clang");
  63. }
  64. static bool IsClangAttr(const RecordDecl *RD) {
  65. return RD->getName() == "Attr" && InNamespace(RD, "clang");
  66. }
  67. static bool IsStdVector(QualType T) {
  68. const TemplateSpecializationType *TS = T->getAs<TemplateSpecializationType>();
  69. if (!TS)
  70. return false;
  71. TemplateName TM = TS->getTemplateName();
  72. TemplateDecl *TD = TM.getAsTemplateDecl();
  73. if (!TD || !InNamespace(TD, "std"))
  74. return false;
  75. return TD->getName() == "vector";
  76. }
  77. static bool IsSmallVector(QualType T) {
  78. const TemplateSpecializationType *TS = T->getAs<TemplateSpecializationType>();
  79. if (!TS)
  80. return false;
  81. TemplateName TM = TS->getTemplateName();
  82. TemplateDecl *TD = TM.getAsTemplateDecl();
  83. if (!TD || !InNamespace(TD, "llvm"))
  84. return false;
  85. return TD->getName() == "SmallVector";
  86. }
  87. //===----------------------------------------------------------------------===//
  88. // CHECK: a StringRef should not be bound to a temporary std::string whose
  89. // lifetime is shorter than the StringRef's.
  90. //===----------------------------------------------------------------------===//
  91. namespace {
  92. class StringRefCheckerVisitor : public StmtVisitor<StringRefCheckerVisitor> {
  93. const Decl *DeclWithIssue;
  94. BugReporter &BR;
  95. const CheckerBase *Checker;
  96. public:
  97. StringRefCheckerVisitor(const Decl *declWithIssue, BugReporter &br,
  98. const CheckerBase *checker)
  99. : DeclWithIssue(declWithIssue), BR(br), Checker(checker) {}
  100. void VisitChildren(Stmt *S) {
  101. for (Stmt *Child : S->children())
  102. if (Child)
  103. Visit(Child);
  104. }
  105. void VisitStmt(Stmt *S) { VisitChildren(S); }
  106. void VisitDeclStmt(DeclStmt *DS);
  107. private:
  108. void VisitVarDecl(VarDecl *VD);
  109. };
  110. } // end anonymous namespace
  111. static void CheckStringRefAssignedTemporary(const Decl *D, BugReporter &BR,
  112. const CheckerBase *Checker) {
  113. StringRefCheckerVisitor walker(D, BR, Checker);
  114. walker.Visit(D->getBody());
  115. }
  116. void StringRefCheckerVisitor::VisitDeclStmt(DeclStmt *S) {
  117. VisitChildren(S);
  118. for (auto *I : S->decls())
  119. if (VarDecl *VD = dyn_cast<VarDecl>(I))
  120. VisitVarDecl(VD);
  121. }
  122. void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) {
  123. Expr *Init = VD->getInit();
  124. if (!Init)
  125. return;
  126. // Pattern match for:
  127. // StringRef x = call() (where call returns std::string)
  128. if (!IsLLVMStringRef(VD->getType()))
  129. return;
  130. ExprWithCleanups *Ex1 = dyn_cast<ExprWithCleanups>(Init);
  131. if (!Ex1)
  132. return;
  133. CXXConstructExpr *Ex2 = dyn_cast<CXXConstructExpr>(Ex1->getSubExpr());
  134. if (!Ex2 || Ex2->getNumArgs() != 1)
  135. return;
  136. ImplicitCastExpr *Ex3 = dyn_cast<ImplicitCastExpr>(Ex2->getArg(0));
  137. if (!Ex3)
  138. return;
  139. CXXConstructExpr *Ex4 = dyn_cast<CXXConstructExpr>(Ex3->getSubExpr());
  140. if (!Ex4 || Ex4->getNumArgs() != 1)
  141. return;
  142. ImplicitCastExpr *Ex5 = dyn_cast<ImplicitCastExpr>(Ex4->getArg(0));
  143. if (!Ex5)
  144. return;
  145. CXXBindTemporaryExpr *Ex6 = dyn_cast<CXXBindTemporaryExpr>(Ex5->getSubExpr());
  146. if (!Ex6 || !IsStdString(Ex6->getType()))
  147. return;
  148. // Okay, badness! Report an error.
  149. const char *desc = "StringRef should not be bound to temporary "
  150. "std::string that it outlives";
  151. PathDiagnosticLocation VDLoc =
  152. PathDiagnosticLocation::createBegin(VD, BR.getSourceManager());
  153. BR.EmitBasicReport(DeclWithIssue, Checker, desc, "LLVM Conventions", desc,
  154. VDLoc, Init->getSourceRange());
  155. }
  156. //===----------------------------------------------------------------------===//
  157. // CHECK: Clang AST nodes should not have fields that can allocate
  158. // memory.
  159. //===----------------------------------------------------------------------===//
  160. static bool AllocatesMemory(QualType T) {
  161. return IsStdVector(T) || IsStdString(T) || IsSmallVector(T);
  162. }
  163. // This type checking could be sped up via dynamic programming.
  164. static bool IsPartOfAST(const CXXRecordDecl *R) {
  165. if (IsClangStmt(R) || IsClangType(R) || IsClangDecl(R) || IsClangAttr(R))
  166. return true;
  167. for (const auto &BS : R->bases()) {
  168. QualType T = BS.getType();
  169. if (const RecordType *baseT = T->getAs<RecordType>()) {
  170. CXXRecordDecl *baseD = cast<CXXRecordDecl>(baseT->getDecl());
  171. if (IsPartOfAST(baseD))
  172. return true;
  173. }
  174. }
  175. return false;
  176. }
  177. namespace {
  178. class ASTFieldVisitor {
  179. SmallVector<FieldDecl*, 10> FieldChain;
  180. const CXXRecordDecl *Root;
  181. BugReporter &BR;
  182. const CheckerBase *Checker;
  183. public:
  184. ASTFieldVisitor(const CXXRecordDecl *root, BugReporter &br,
  185. const CheckerBase *checker)
  186. : Root(root), BR(br), Checker(checker) {}
  187. void Visit(FieldDecl *D);
  188. void ReportError(QualType T);
  189. };
  190. } // end anonymous namespace
  191. static void CheckASTMemory(const CXXRecordDecl *R, BugReporter &BR,
  192. const CheckerBase *Checker) {
  193. if (!IsPartOfAST(R))
  194. return;
  195. for (auto *I : R->fields()) {
  196. ASTFieldVisitor walker(R, BR, Checker);
  197. walker.Visit(I);
  198. }
  199. }
  200. void ASTFieldVisitor::Visit(FieldDecl *D) {
  201. FieldChain.push_back(D);
  202. QualType T = D->getType();
  203. if (AllocatesMemory(T))
  204. ReportError(T);
  205. if (const RecordType *RT = T->getAs<RecordType>()) {
  206. const RecordDecl *RD = RT->getDecl()->getDefinition();
  207. for (auto *I : RD->fields())
  208. Visit(I);
  209. }
  210. FieldChain.pop_back();
  211. }
  212. void ASTFieldVisitor::ReportError(QualType T) {
  213. SmallString<1024> buf;
  214. llvm::raw_svector_ostream os(buf);
  215. os << "AST class '" << Root->getName() << "' has a field '"
  216. << FieldChain.front()->getName() << "' that allocates heap memory";
  217. if (FieldChain.size() > 1) {
  218. os << " via the following chain: ";
  219. bool isFirst = true;
  220. for (SmallVectorImpl<FieldDecl*>::iterator I=FieldChain.begin(),
  221. E=FieldChain.end(); I!=E; ++I) {
  222. if (!isFirst)
  223. os << '.';
  224. else
  225. isFirst = false;
  226. os << (*I)->getName();
  227. }
  228. }
  229. os << " (type " << FieldChain.back()->getType().getAsString() << ")";
  230. os.flush();
  231. // Note that this will fire for every translation unit that uses this
  232. // class. This is suboptimal, but at least scan-build will merge
  233. // duplicate HTML reports. In the future we need a unified way of merging
  234. // duplicate reports across translation units. For C++ classes we cannot
  235. // just report warnings when we see an out-of-line method definition for a
  236. // class, as that heuristic doesn't always work (the complete definition of
  237. // the class may be in the header file, for example).
  238. PathDiagnosticLocation L = PathDiagnosticLocation::createBegin(
  239. FieldChain.front(), BR.getSourceManager());
  240. BR.EmitBasicReport(Root, Checker, "AST node allocates heap memory",
  241. "LLVM Conventions", os.str(), L);
  242. }
  243. //===----------------------------------------------------------------------===//
  244. // LLVMConventionsChecker
  245. //===----------------------------------------------------------------------===//
  246. namespace {
  247. class LLVMConventionsChecker : public Checker<
  248. check::ASTDecl<CXXRecordDecl>,
  249. check::ASTCodeBody > {
  250. public:
  251. void checkASTDecl(const CXXRecordDecl *R, AnalysisManager& mgr,
  252. BugReporter &BR) const {
  253. if (R->isCompleteDefinition())
  254. CheckASTMemory(R, BR, this);
  255. }
  256. void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
  257. BugReporter &BR) const {
  258. CheckStringRefAssignedTemporary(D, BR, this);
  259. }
  260. };
  261. }
  262. void ento::registerLLVMConventionsChecker(CheckerManager &mgr) {
  263. mgr.registerChecker<LLVMConventionsChecker>();
  264. }