clang API Documentation
00001 // MallocSizeofChecker.cpp - Check for dubious malloc arguments ---*- 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 // Reports inconsistencies between the casted type of the return value of a 00011 // malloc/calloc/realloc call and the operand of any sizeof expressions 00012 // contained within its argument(s). 00013 // 00014 //===----------------------------------------------------------------------===// 00015 00016 #include "ClangSACheckers.h" 00017 #include "clang/AST/StmtVisitor.h" 00018 #include "clang/AST/TypeLoc.h" 00019 #include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 00020 #include "clang/StaticAnalyzer/Core/Checker.h" 00021 #include "clang/StaticAnalyzer/Core/CheckerManager.h" 00022 #include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 00023 #include "llvm/ADT/SmallString.h" 00024 #include "llvm/Support/raw_ostream.h" 00025 00026 using namespace clang; 00027 using namespace ento; 00028 00029 namespace { 00030 00031 typedef std::pair<const TypeSourceInfo *, const CallExpr *> TypeCallPair; 00032 typedef llvm::PointerUnion<const Stmt *, const VarDecl *> ExprParent; 00033 00034 class CastedAllocFinder 00035 : public ConstStmtVisitor<CastedAllocFinder, TypeCallPair> { 00036 IdentifierInfo *II_malloc, *II_calloc, *II_realloc; 00037 00038 public: 00039 struct CallRecord { 00040 ExprParent CastedExprParent; 00041 const Expr *CastedExpr; 00042 const TypeSourceInfo *ExplicitCastType; 00043 const CallExpr *AllocCall; 00044 00045 CallRecord(ExprParent CastedExprParent, const Expr *CastedExpr, 00046 const TypeSourceInfo *ExplicitCastType, 00047 const CallExpr *AllocCall) 00048 : CastedExprParent(CastedExprParent), CastedExpr(CastedExpr), 00049 ExplicitCastType(ExplicitCastType), AllocCall(AllocCall) {} 00050 }; 00051 00052 typedef std::vector<CallRecord> CallVec; 00053 CallVec Calls; 00054 00055 CastedAllocFinder(ASTContext *Ctx) : 00056 II_malloc(&Ctx->Idents.get("malloc")), 00057 II_calloc(&Ctx->Idents.get("calloc")), 00058 II_realloc(&Ctx->Idents.get("realloc")) {} 00059 00060 void VisitChild(ExprParent Parent, const Stmt *S) { 00061 TypeCallPair AllocCall = Visit(S); 00062 if (AllocCall.second && AllocCall.second != S) 00063 Calls.push_back(CallRecord(Parent, cast<Expr>(S), AllocCall.first, 00064 AllocCall.second)); 00065 } 00066 00067 void VisitChildren(const Stmt *S) { 00068 for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end(); 00069 I!=E; ++I) 00070 if (const Stmt *child = *I) 00071 VisitChild(S, child); 00072 } 00073 00074 TypeCallPair VisitCastExpr(const CastExpr *E) { 00075 return Visit(E->getSubExpr()); 00076 } 00077 00078 TypeCallPair VisitExplicitCastExpr(const ExplicitCastExpr *E) { 00079 return TypeCallPair(E->getTypeInfoAsWritten(), 00080 Visit(E->getSubExpr()).second); 00081 } 00082 00083 TypeCallPair VisitParenExpr(const ParenExpr *E) { 00084 return Visit(E->getSubExpr()); 00085 } 00086 00087 TypeCallPair VisitStmt(const Stmt *S) { 00088 VisitChildren(S); 00089 return TypeCallPair(); 00090 } 00091 00092 TypeCallPair VisitCallExpr(const CallExpr *E) { 00093 VisitChildren(E); 00094 const FunctionDecl *FD = E->getDirectCallee(); 00095 if (FD) { 00096 IdentifierInfo *II = FD->getIdentifier(); 00097 if (II == II_malloc || II == II_calloc || II == II_realloc) 00098 return TypeCallPair((const TypeSourceInfo *)nullptr, E); 00099 } 00100 return TypeCallPair(); 00101 } 00102 00103 TypeCallPair VisitDeclStmt(const DeclStmt *S) { 00104 for (const auto *I : S->decls()) 00105 if (const VarDecl *VD = dyn_cast<VarDecl>(I)) 00106 if (const Expr *Init = VD->getInit()) 00107 VisitChild(VD, Init); 00108 return TypeCallPair(); 00109 } 00110 }; 00111 00112 class SizeofFinder : public ConstStmtVisitor<SizeofFinder> { 00113 public: 00114 std::vector<const UnaryExprOrTypeTraitExpr *> Sizeofs; 00115 00116 void VisitBinMul(const BinaryOperator *E) { 00117 Visit(E->getLHS()); 00118 Visit(E->getRHS()); 00119 } 00120 00121 void VisitImplicitCastExpr(const ImplicitCastExpr *E) { 00122 return Visit(E->getSubExpr()); 00123 } 00124 00125 void VisitParenExpr(const ParenExpr *E) { 00126 return Visit(E->getSubExpr()); 00127 } 00128 00129 void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E) { 00130 if (E->getKind() != UETT_SizeOf) 00131 return; 00132 00133 Sizeofs.push_back(E); 00134 } 00135 }; 00136 00137 // Determine if the pointee and sizeof types are compatible. Here 00138 // we ignore constness of pointer types. 00139 static bool typesCompatible(ASTContext &C, QualType A, QualType B) { 00140 // sizeof(void*) is compatible with any other pointer. 00141 if (B->isVoidPointerType() && A->getAs<PointerType>()) 00142 return true; 00143 00144 while (true) { 00145 A = A.getCanonicalType(); 00146 B = B.getCanonicalType(); 00147 00148 if (A.getTypePtr() == B.getTypePtr()) 00149 return true; 00150 00151 if (const PointerType *ptrA = A->getAs<PointerType>()) 00152 if (const PointerType *ptrB = B->getAs<PointerType>()) { 00153 A = ptrA->getPointeeType(); 00154 B = ptrB->getPointeeType(); 00155 continue; 00156 } 00157 00158 break; 00159 } 00160 00161 return false; 00162 } 00163 00164 static bool compatibleWithArrayType(ASTContext &C, QualType PT, QualType T) { 00165 // Ex: 'int a[10][2]' is compatible with 'int', 'int[2]', 'int[10][2]'. 00166 while (const ArrayType *AT = T->getAsArrayTypeUnsafe()) { 00167 QualType ElemType = AT->getElementType(); 00168 if (typesCompatible(C, PT, AT->getElementType())) 00169 return true; 00170 T = ElemType; 00171 } 00172 00173 return false; 00174 } 00175 00176 class MallocSizeofChecker : public Checker<check::ASTCodeBody> { 00177 public: 00178 void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 00179 BugReporter &BR) const { 00180 AnalysisDeclContext *ADC = mgr.getAnalysisDeclContext(D); 00181 CastedAllocFinder Finder(&BR.getContext()); 00182 Finder.Visit(D->getBody()); 00183 for (CastedAllocFinder::CallVec::iterator i = Finder.Calls.begin(), 00184 e = Finder.Calls.end(); i != e; ++i) { 00185 QualType CastedType = i->CastedExpr->getType(); 00186 if (!CastedType->isPointerType()) 00187 continue; 00188 QualType PointeeType = CastedType->getAs<PointerType>()->getPointeeType(); 00189 if (PointeeType->isVoidType()) 00190 continue; 00191 00192 for (CallExpr::const_arg_iterator ai = i->AllocCall->arg_begin(), 00193 ae = i->AllocCall->arg_end(); ai != ae; ++ai) { 00194 if (!(*ai)->getType()->isIntegralOrUnscopedEnumerationType()) 00195 continue; 00196 00197 SizeofFinder SFinder; 00198 SFinder.Visit(*ai); 00199 if (SFinder.Sizeofs.size() != 1) 00200 continue; 00201 00202 QualType SizeofType = SFinder.Sizeofs[0]->getTypeOfArgument(); 00203 00204 if (typesCompatible(BR.getContext(), PointeeType, SizeofType)) 00205 continue; 00206 00207 // If the argument to sizeof is an array, the result could be a 00208 // pointer to any array element. 00209 if (compatibleWithArrayType(BR.getContext(), PointeeType, SizeofType)) 00210 continue; 00211 00212 const TypeSourceInfo *TSI = nullptr; 00213 if (i->CastedExprParent.is<const VarDecl *>()) { 00214 TSI = 00215 i->CastedExprParent.get<const VarDecl *>()->getTypeSourceInfo(); 00216 } else { 00217 TSI = i->ExplicitCastType; 00218 } 00219 00220 SmallString<64> buf; 00221 llvm::raw_svector_ostream OS(buf); 00222 00223 OS << "Result of "; 00224 const FunctionDecl *Callee = i->AllocCall->getDirectCallee(); 00225 if (Callee && Callee->getIdentifier()) 00226 OS << '\'' << Callee->getIdentifier()->getName() << '\''; 00227 else 00228 OS << "call"; 00229 OS << " is converted to a pointer of type '" 00230 << PointeeType.getAsString() << "', which is incompatible with " 00231 << "sizeof operand type '" << SizeofType.getAsString() << "'"; 00232 SmallVector<SourceRange, 4> Ranges; 00233 Ranges.push_back(i->AllocCall->getCallee()->getSourceRange()); 00234 Ranges.push_back(SFinder.Sizeofs[0]->getSourceRange()); 00235 if (TSI) 00236 Ranges.push_back(TSI->getTypeLoc().getSourceRange()); 00237 00238 PathDiagnosticLocation L = 00239 PathDiagnosticLocation::createBegin(i->AllocCall->getCallee(), 00240 BR.getSourceManager(), ADC); 00241 00242 BR.EmitBasicReport(D, this, "Allocator sizeof operand mismatch", 00243 categories::UnixAPI, OS.str(), L, Ranges); 00244 } 00245 } 00246 } 00247 }; 00248 00249 } 00250 00251 void ento::registerMallocSizeofChecker(CheckerManager &mgr) { 00252 mgr.registerChecker<MallocSizeofChecker>(); 00253 }