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