clang API Documentation
00001 //=== LLVMConventionsChecker.cpp - Check LLVM codebase conventions ---*- 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 defines LLVMConventionsChecker, a bunch of small little checks 00011 // for checking specific coding conventions in the LLVM/Clang codebase. 00012 // 00013 //===----------------------------------------------------------------------===// 00014 00015 #include "ClangSACheckers.h" 00016 #include "clang/AST/DeclTemplate.h" 00017 #include "clang/AST/StmtVisitor.h" 00018 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 00019 #include "clang/StaticAnalyzer/Core/Checker.h" 00020 #include "llvm/ADT/SmallString.h" 00021 #include "llvm/Support/raw_ostream.h" 00022 00023 using namespace clang; 00024 using namespace ento; 00025 00026 //===----------------------------------------------------------------------===// 00027 // Generic type checking routines. 00028 //===----------------------------------------------------------------------===// 00029 00030 static bool IsLLVMStringRef(QualType T) { 00031 const RecordType *RT = T->getAs<RecordType>(); 00032 if (!RT) 00033 return false; 00034 00035 return StringRef(QualType(RT, 0).getAsString()) == 00036 "class StringRef"; 00037 } 00038 00039 /// Check whether the declaration is semantically inside the top-level 00040 /// namespace named by ns. 00041 static bool InNamespace(const Decl *D, StringRef NS) { 00042 const NamespaceDecl *ND = dyn_cast<NamespaceDecl>(D->getDeclContext()); 00043 if (!ND) 00044 return false; 00045 const IdentifierInfo *II = ND->getIdentifier(); 00046 if (!II || !II->getName().equals(NS)) 00047 return false; 00048 return isa<TranslationUnitDecl>(ND->getDeclContext()); 00049 } 00050 00051 static bool IsStdString(QualType T) { 00052 if (const ElaboratedType *QT = T->getAs<ElaboratedType>()) 00053 T = QT->getNamedType(); 00054 00055 const TypedefType *TT = T->getAs<TypedefType>(); 00056 if (!TT) 00057 return false; 00058 00059 const TypedefNameDecl *TD = TT->getDecl(); 00060 00061 if (!TD->isInStdNamespace()) 00062 return false; 00063 00064 return TD->getName() == "string"; 00065 } 00066 00067 static bool IsClangType(const RecordDecl *RD) { 00068 return RD->getName() == "Type" && InNamespace(RD, "clang"); 00069 } 00070 00071 static bool IsClangDecl(const RecordDecl *RD) { 00072 return RD->getName() == "Decl" && InNamespace(RD, "clang"); 00073 } 00074 00075 static bool IsClangStmt(const RecordDecl *RD) { 00076 return RD->getName() == "Stmt" && InNamespace(RD, "clang"); 00077 } 00078 00079 static bool IsClangAttr(const RecordDecl *RD) { 00080 return RD->getName() == "Attr" && InNamespace(RD, "clang"); 00081 } 00082 00083 static bool IsStdVector(QualType T) { 00084 const TemplateSpecializationType *TS = T->getAs<TemplateSpecializationType>(); 00085 if (!TS) 00086 return false; 00087 00088 TemplateName TM = TS->getTemplateName(); 00089 TemplateDecl *TD = TM.getAsTemplateDecl(); 00090 00091 if (!TD || !InNamespace(TD, "std")) 00092 return false; 00093 00094 return TD->getName() == "vector"; 00095 } 00096 00097 static bool IsSmallVector(QualType T) { 00098 const TemplateSpecializationType *TS = T->getAs<TemplateSpecializationType>(); 00099 if (!TS) 00100 return false; 00101 00102 TemplateName TM = TS->getTemplateName(); 00103 TemplateDecl *TD = TM.getAsTemplateDecl(); 00104 00105 if (!TD || !InNamespace(TD, "llvm")) 00106 return false; 00107 00108 return TD->getName() == "SmallVector"; 00109 } 00110 00111 //===----------------------------------------------------------------------===// 00112 // CHECK: a StringRef should not be bound to a temporary std::string whose 00113 // lifetime is shorter than the StringRef's. 00114 //===----------------------------------------------------------------------===// 00115 00116 namespace { 00117 class StringRefCheckerVisitor : public StmtVisitor<StringRefCheckerVisitor> { 00118 const Decl *DeclWithIssue; 00119 BugReporter &BR; 00120 const CheckerBase *Checker; 00121 00122 public: 00123 StringRefCheckerVisitor(const Decl *declWithIssue, BugReporter &br, 00124 const CheckerBase *checker) 00125 : DeclWithIssue(declWithIssue), BR(br), Checker(checker) {} 00126 void VisitChildren(Stmt *S) { 00127 for (Stmt::child_iterator I = S->child_begin(), E = S->child_end() ; 00128 I != E; ++I) 00129 if (Stmt *child = *I) 00130 Visit(child); 00131 } 00132 void VisitStmt(Stmt *S) { VisitChildren(S); } 00133 void VisitDeclStmt(DeclStmt *DS); 00134 private: 00135 void VisitVarDecl(VarDecl *VD); 00136 }; 00137 } // end anonymous namespace 00138 00139 static void CheckStringRefAssignedTemporary(const Decl *D, BugReporter &BR, 00140 const CheckerBase *Checker) { 00141 StringRefCheckerVisitor walker(D, BR, Checker); 00142 walker.Visit(D->getBody()); 00143 } 00144 00145 void StringRefCheckerVisitor::VisitDeclStmt(DeclStmt *S) { 00146 VisitChildren(S); 00147 00148 for (auto *I : S->decls()) 00149 if (VarDecl *VD = dyn_cast<VarDecl>(I)) 00150 VisitVarDecl(VD); 00151 } 00152 00153 void StringRefCheckerVisitor::VisitVarDecl(VarDecl *VD) { 00154 Expr *Init = VD->getInit(); 00155 if (!Init) 00156 return; 00157 00158 // Pattern match for: 00159 // StringRef x = call() (where call returns std::string) 00160 if (!IsLLVMStringRef(VD->getType())) 00161 return; 00162 ExprWithCleanups *Ex1 = dyn_cast<ExprWithCleanups>(Init); 00163 if (!Ex1) 00164 return; 00165 CXXConstructExpr *Ex2 = dyn_cast<CXXConstructExpr>(Ex1->getSubExpr()); 00166 if (!Ex2 || Ex2->getNumArgs() != 1) 00167 return; 00168 ImplicitCastExpr *Ex3 = dyn_cast<ImplicitCastExpr>(Ex2->getArg(0)); 00169 if (!Ex3) 00170 return; 00171 CXXConstructExpr *Ex4 = dyn_cast<CXXConstructExpr>(Ex3->getSubExpr()); 00172 if (!Ex4 || Ex4->getNumArgs() != 1) 00173 return; 00174 ImplicitCastExpr *Ex5 = dyn_cast<ImplicitCastExpr>(Ex4->getArg(0)); 00175 if (!Ex5) 00176 return; 00177 CXXBindTemporaryExpr *Ex6 = dyn_cast<CXXBindTemporaryExpr>(Ex5->getSubExpr()); 00178 if (!Ex6 || !IsStdString(Ex6->getType())) 00179 return; 00180 00181 // Okay, badness! Report an error. 00182 const char *desc = "StringRef should not be bound to temporary " 00183 "std::string that it outlives"; 00184 PathDiagnosticLocation VDLoc = 00185 PathDiagnosticLocation::createBegin(VD, BR.getSourceManager()); 00186 BR.EmitBasicReport(DeclWithIssue, Checker, desc, "LLVM Conventions", desc, 00187 VDLoc, Init->getSourceRange()); 00188 } 00189 00190 //===----------------------------------------------------------------------===// 00191 // CHECK: Clang AST nodes should not have fields that can allocate 00192 // memory. 00193 //===----------------------------------------------------------------------===// 00194 00195 static bool AllocatesMemory(QualType T) { 00196 return IsStdVector(T) || IsStdString(T) || IsSmallVector(T); 00197 } 00198 00199 // This type checking could be sped up via dynamic programming. 00200 static bool IsPartOfAST(const CXXRecordDecl *R) { 00201 if (IsClangStmt(R) || IsClangType(R) || IsClangDecl(R) || IsClangAttr(R)) 00202 return true; 00203 00204 for (const auto &BS : R->bases()) { 00205 QualType T = BS.getType(); 00206 if (const RecordType *baseT = T->getAs<RecordType>()) { 00207 CXXRecordDecl *baseD = cast<CXXRecordDecl>(baseT->getDecl()); 00208 if (IsPartOfAST(baseD)) 00209 return true; 00210 } 00211 } 00212 00213 return false; 00214 } 00215 00216 namespace { 00217 class ASTFieldVisitor { 00218 SmallVector<FieldDecl*, 10> FieldChain; 00219 const CXXRecordDecl *Root; 00220 BugReporter &BR; 00221 const CheckerBase *Checker; 00222 00223 public: 00224 ASTFieldVisitor(const CXXRecordDecl *root, BugReporter &br, 00225 const CheckerBase *checker) 00226 : Root(root), BR(br), Checker(checker) {} 00227 00228 void Visit(FieldDecl *D); 00229 void ReportError(QualType T); 00230 }; 00231 } // end anonymous namespace 00232 00233 static void CheckASTMemory(const CXXRecordDecl *R, BugReporter &BR, 00234 const CheckerBase *Checker) { 00235 if (!IsPartOfAST(R)) 00236 return; 00237 00238 for (auto *I : R->fields()) { 00239 ASTFieldVisitor walker(R, BR, Checker); 00240 walker.Visit(I); 00241 } 00242 } 00243 00244 void ASTFieldVisitor::Visit(FieldDecl *D) { 00245 FieldChain.push_back(D); 00246 00247 QualType T = D->getType(); 00248 00249 if (AllocatesMemory(T)) 00250 ReportError(T); 00251 00252 if (const RecordType *RT = T->getAs<RecordType>()) { 00253 const RecordDecl *RD = RT->getDecl()->getDefinition(); 00254 for (auto *I : RD->fields()) 00255 Visit(I); 00256 } 00257 00258 FieldChain.pop_back(); 00259 } 00260 00261 void ASTFieldVisitor::ReportError(QualType T) { 00262 SmallString<1024> buf; 00263 llvm::raw_svector_ostream os(buf); 00264 00265 os << "AST class '" << Root->getName() << "' has a field '" 00266 << FieldChain.front()->getName() << "' that allocates heap memory"; 00267 if (FieldChain.size() > 1) { 00268 os << " via the following chain: "; 00269 bool isFirst = true; 00270 for (SmallVectorImpl<FieldDecl*>::iterator I=FieldChain.begin(), 00271 E=FieldChain.end(); I!=E; ++I) { 00272 if (!isFirst) 00273 os << '.'; 00274 else 00275 isFirst = false; 00276 os << (*I)->getName(); 00277 } 00278 } 00279 os << " (type " << FieldChain.back()->getType().getAsString() << ")"; 00280 os.flush(); 00281 00282 // Note that this will fire for every translation unit that uses this 00283 // class. This is suboptimal, but at least scan-build will merge 00284 // duplicate HTML reports. In the future we need a unified way of merging 00285 // duplicate reports across translation units. For C++ classes we cannot 00286 // just report warnings when we see an out-of-line method definition for a 00287 // class, as that heuristic doesn't always work (the complete definition of 00288 // the class may be in the header file, for example). 00289 PathDiagnosticLocation L = PathDiagnosticLocation::createBegin( 00290 FieldChain.front(), BR.getSourceManager()); 00291 BR.EmitBasicReport(Root, Checker, "AST node allocates heap memory", 00292 "LLVM Conventions", os.str(), L); 00293 } 00294 00295 //===----------------------------------------------------------------------===// 00296 // LLVMConventionsChecker 00297 //===----------------------------------------------------------------------===// 00298 00299 namespace { 00300 class LLVMConventionsChecker : public Checker< 00301 check::ASTDecl<CXXRecordDecl>, 00302 check::ASTCodeBody > { 00303 public: 00304 void checkASTDecl(const CXXRecordDecl *R, AnalysisManager& mgr, 00305 BugReporter &BR) const { 00306 if (R->isCompleteDefinition()) 00307 CheckASTMemory(R, BR, this); 00308 } 00309 00310 void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 00311 BugReporter &BR) const { 00312 CheckStringRefAssignedTemporary(D, BR, this); 00313 } 00314 }; 00315 } 00316 00317 void ento::registerLLVMConventionsChecker(CheckerManager &mgr) { 00318 mgr.registerChecker<LLVMConventionsChecker>(); 00319 }