MallocSizeofChecker.cpp revision dc30967a4633186782e0e204c65dba2552301ec9
1// MallocSizeofChecker.cpp - Check for dubious malloc arguments ---*- 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// Reports inconsistencies between the casted type of the return value of a 11// malloc/calloc/realloc call and the operand of any sizeof expressions 12// contained within its argument(s). 13// 14//===----------------------------------------------------------------------===// 15 16#include "ClangSACheckers.h" 17#include "clang/StaticAnalyzer/Core/BugReporter/BugReporter.h" 18#include "clang/StaticAnalyzer/Core/Checker.h" 19#include "clang/StaticAnalyzer/Core/CheckerManager.h" 20#include "clang/StaticAnalyzer/Core/PathSensitive/AnalysisManager.h" 21#include "clang/AST/StmtVisitor.h" 22#include "clang/AST/TypeLoc.h" 23 24using namespace clang; 25using namespace ento; 26 27namespace { 28 29typedef std::pair<const TypeSourceInfo *, const CallExpr *> TypeCallPair; 30typedef llvm::PointerUnion<const Stmt *, const VarDecl *> ExprParent; 31 32class CastedAllocFinder 33 : public ConstStmtVisitor<CastedAllocFinder, TypeCallPair> { 34 IdentifierInfo *II_malloc, *II_calloc, *II_realloc; 35 36public: 37 struct CallRecord { 38 ExprParent CastedExprParent; 39 const Expr *CastedExpr; 40 const TypeSourceInfo *ExplicitCastType; 41 const CallExpr *AllocCall; 42 43 CallRecord(ExprParent CastedExprParent, const Expr *CastedExpr, 44 const TypeSourceInfo *ExplicitCastType, 45 const CallExpr *AllocCall) 46 : CastedExprParent(CastedExprParent), CastedExpr(CastedExpr), 47 ExplicitCastType(ExplicitCastType), AllocCall(AllocCall) {} 48 }; 49 50 typedef std::vector<CallRecord> CallVec; 51 CallVec Calls; 52 53 CastedAllocFinder(ASTContext *Ctx) : 54 II_malloc(&Ctx->Idents.get("malloc")), 55 II_calloc(&Ctx->Idents.get("calloc")), 56 II_realloc(&Ctx->Idents.get("realloc")) {} 57 58 void VisitChild(ExprParent Parent, const Stmt *S) { 59 TypeCallPair AllocCall = Visit(S); 60 if (AllocCall.second && AllocCall.second != S) 61 Calls.push_back(CallRecord(Parent, cast<Expr>(S), AllocCall.first, 62 AllocCall.second)); 63 } 64 65 void VisitChildren(const Stmt *S) { 66 for (Stmt::const_child_iterator I = S->child_begin(), E = S->child_end(); 67 I!=E; ++I) 68 if (const Stmt *child = *I) 69 VisitChild(S, child); 70 } 71 72 TypeCallPair VisitCastExpr(const CastExpr *E) { 73 return Visit(E->getSubExpr()); 74 } 75 76 TypeCallPair VisitExplicitCastExpr(const ExplicitCastExpr *E) { 77 return TypeCallPair(E->getTypeInfoAsWritten(), 78 Visit(E->getSubExpr()).second); 79 } 80 81 TypeCallPair VisitParenExpr(const ParenExpr *E) { 82 return Visit(E->getSubExpr()); 83 } 84 85 TypeCallPair VisitStmt(const Stmt *S) { 86 VisitChildren(S); 87 return TypeCallPair(); 88 } 89 90 TypeCallPair VisitCallExpr(const CallExpr *E) { 91 VisitChildren(E); 92 const FunctionDecl *FD = E->getDirectCallee(); 93 if (FD) { 94 IdentifierInfo *II = FD->getIdentifier(); 95 if (II == II_malloc || II == II_calloc || II == II_realloc) 96 return TypeCallPair(0, E); 97 } 98 return TypeCallPair(); 99 } 100 101 TypeCallPair VisitDeclStmt(const DeclStmt *S) { 102 for (DeclStmt::const_decl_iterator I = S->decl_begin(), E = S->decl_end(); 103 I!=E; ++I) 104 if (const VarDecl *VD = dyn_cast<VarDecl>(*I)) 105 if (const Expr *Init = VD->getInit()) 106 VisitChild(VD, Init); 107 return TypeCallPair(); 108 } 109}; 110 111class SizeofFinder : public ConstStmtVisitor<SizeofFinder> { 112public: 113 std::vector<const UnaryExprOrTypeTraitExpr *> Sizeofs; 114 115 void VisitBinMul(const BinaryOperator *E) { 116 Visit(E->getLHS()); 117 Visit(E->getRHS()); 118 } 119 120 void VisitBinAdd(const BinaryOperator *E) { 121 Visit(E->getLHS()); 122 Visit(E->getRHS()); 123 } 124 125 void VisitImplicitCastExpr(const ImplicitCastExpr *E) { 126 return Visit(E->getSubExpr()); 127 } 128 129 void VisitParenExpr(const ParenExpr *E) { 130 return Visit(E->getSubExpr()); 131 } 132 133 void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E) { 134 if (E->getKind() != UETT_SizeOf) 135 return; 136 137 Sizeofs.push_back(E); 138 } 139}; 140 141class MallocSizeofChecker : public Checker<check::ASTCodeBody> { 142public: 143 void checkASTCodeBody(const Decl *D, AnalysisManager& mgr, 144 BugReporter &BR) const { 145 AnalysisDeclContext *ADC = mgr.getAnalysisDeclContext(D); 146 CastedAllocFinder Finder(&BR.getContext()); 147 Finder.Visit(D->getBody()); 148 for (CastedAllocFinder::CallVec::iterator i = Finder.Calls.begin(), 149 e = Finder.Calls.end(); i != e; ++i) { 150 QualType CastedType = i->CastedExpr->getType(); 151 if (!CastedType->isPointerType()) 152 continue; 153 QualType PointeeType = CastedType->getAs<PointerType>()->getPointeeType(); 154 if (PointeeType->isVoidType()) 155 continue; 156 157 for (CallExpr::const_arg_iterator ai = i->AllocCall->arg_begin(), 158 ae = i->AllocCall->arg_end(); ai != ae; ++ai) { 159 if (!(*ai)->getType()->isIntegerType()) 160 continue; 161 162 SizeofFinder SFinder; 163 SFinder.Visit(*ai); 164 if (SFinder.Sizeofs.size() != 1) 165 continue; 166 167 QualType SizeofType = SFinder.Sizeofs[0]->getTypeOfArgument(); 168 if (!BR.getContext().hasSameUnqualifiedType(PointeeType, SizeofType)) { 169 const TypeSourceInfo *TSI = 0; 170 if (i->CastedExprParent.is<const VarDecl *>()) { 171 TSI = 172 i->CastedExprParent.get<const VarDecl *>()->getTypeSourceInfo(); 173 } else { 174 TSI = i->ExplicitCastType; 175 } 176 177 llvm::SmallString<64> buf; 178 llvm::raw_svector_ostream OS(buf); 179 180 OS << "Result of '" 181 << i->AllocCall->getDirectCallee()->getIdentifier()->getName() 182 << "' is converted to type '" 183 << CastedType.getAsString() << "', whose pointee type '" 184 << PointeeType.getAsString() << "' is incompatible with " 185 << "sizeof operand type '" << SizeofType.getAsString() << "'"; 186 llvm::SmallVector<SourceRange, 4> Ranges; 187 Ranges.push_back(i->AllocCall->getCallee()->getSourceRange()); 188 Ranges.push_back(SFinder.Sizeofs[0]->getSourceRange()); 189 if (TSI) 190 Ranges.push_back(TSI->getTypeLoc().getSourceRange()); 191 192 PathDiagnosticLocation L = 193 PathDiagnosticLocation::createBegin(i->AllocCall->getCallee(), 194 BR.getSourceManager(), ADC); 195 196 BR.EmitBasicReport("allocator sizeof operand mismatch", OS.str(), L, 197 Ranges.data(), Ranges.size()); 198 } 199 } 200 } 201 } 202}; 203 204} 205 206void ento::registerMallocSizeofChecker(CheckerManager &mgr) { 207 mgr.registerChecker<MallocSizeofChecker>(); 208} 209