clang  6.0.0svn
MallocSizeofChecker.cpp
Go to the documentation of this file.
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/AST/StmtVisitor.h"
18 #include "clang/AST/TypeLoc.h"
23 #include "llvm/ADT/SmallString.h"
24 #include "llvm/Support/raw_ostream.h"
25 
26 using namespace clang;
27 using namespace ento;
28 
29 namespace {
30 
31 typedef std::pair<const TypeSourceInfo *, const CallExpr *> TypeCallPair;
32 typedef llvm::PointerUnion<const Stmt *, const VarDecl *> ExprParent;
33 
34 class CastedAllocFinder
35  : public ConstStmtVisitor<CastedAllocFinder, TypeCallPair> {
36  IdentifierInfo *II_malloc, *II_calloc, *II_realloc;
37 
38 public:
39  struct CallRecord {
40  ExprParent CastedExprParent;
41  const Expr *CastedExpr;
42  const TypeSourceInfo *ExplicitCastType;
43  const CallExpr *AllocCall;
44 
45  CallRecord(ExprParent CastedExprParent, const Expr *CastedExpr,
46  const TypeSourceInfo *ExplicitCastType,
47  const CallExpr *AllocCall)
48  : CastedExprParent(CastedExprParent), CastedExpr(CastedExpr),
49  ExplicitCastType(ExplicitCastType), AllocCall(AllocCall) {}
50  };
51 
52  typedef std::vector<CallRecord> CallVec;
53  CallVec Calls;
54 
55  CastedAllocFinder(ASTContext *Ctx) :
56  II_malloc(&Ctx->Idents.get("malloc")),
57  II_calloc(&Ctx->Idents.get("calloc")),
58  II_realloc(&Ctx->Idents.get("realloc")) {}
59 
60  void VisitChild(ExprParent Parent, const Stmt *S) {
61  TypeCallPair AllocCall = Visit(S);
62  if (AllocCall.second && AllocCall.second != S)
63  Calls.push_back(CallRecord(Parent, cast<Expr>(S), AllocCall.first,
64  AllocCall.second));
65  }
66 
67  void VisitChildren(const Stmt *S) {
68  for (const Stmt *Child : S->children())
69  if (Child)
70  VisitChild(S, Child);
71  }
72 
73  TypeCallPair VisitCastExpr(const CastExpr *E) {
74  return Visit(E->getSubExpr());
75  }
76 
77  TypeCallPair VisitExplicitCastExpr(const ExplicitCastExpr *E) {
78  return TypeCallPair(E->getTypeInfoAsWritten(),
79  Visit(E->getSubExpr()).second);
80  }
81 
82  TypeCallPair VisitParenExpr(const ParenExpr *E) {
83  return Visit(E->getSubExpr());
84  }
85 
86  TypeCallPair VisitStmt(const Stmt *S) {
87  VisitChildren(S);
88  return TypeCallPair();
89  }
90 
91  TypeCallPair VisitCallExpr(const CallExpr *E) {
92  VisitChildren(E);
93  const FunctionDecl *FD = E->getDirectCallee();
94  if (FD) {
95  IdentifierInfo *II = FD->getIdentifier();
96  if (II == II_malloc || II == II_calloc || II == II_realloc)
97  return TypeCallPair((const TypeSourceInfo *)nullptr, E);
98  }
99  return TypeCallPair();
100  }
101 
102  TypeCallPair VisitDeclStmt(const DeclStmt *S) {
103  for (const auto *I : S->decls())
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 
111 class SizeofFinder : public ConstStmtVisitor<SizeofFinder> {
112 public:
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 VisitImplicitCastExpr(const ImplicitCastExpr *E) {
121  return Visit(E->getSubExpr());
122  }
123 
124  void VisitParenExpr(const ParenExpr *E) {
125  return Visit(E->getSubExpr());
126  }
127 
128  void VisitUnaryExprOrTypeTraitExpr(const UnaryExprOrTypeTraitExpr *E) {
129  if (E->getKind() != UETT_SizeOf)
130  return;
131 
132  Sizeofs.push_back(E);
133  }
134 };
135 
136 // Determine if the pointee and sizeof types are compatible. Here
137 // we ignore constness of pointer types.
138 static bool typesCompatible(ASTContext &C, QualType A, QualType B) {
139  // sizeof(void*) is compatible with any other pointer.
140  if (B->isVoidPointerType() && A->getAs<PointerType>())
141  return true;
142 
143  while (true) {
144  A = A.getCanonicalType();
145  B = B.getCanonicalType();
146 
147  if (A.getTypePtr() == B.getTypePtr())
148  return true;
149 
150  if (const PointerType *ptrA = A->getAs<PointerType>())
151  if (const PointerType *ptrB = B->getAs<PointerType>()) {
152  A = ptrA->getPointeeType();
153  B = ptrB->getPointeeType();
154  continue;
155  }
156 
157  break;
158  }
159 
160  return false;
161 }
162 
163 static bool compatibleWithArrayType(ASTContext &C, QualType PT, QualType T) {
164  // Ex: 'int a[10][2]' is compatible with 'int', 'int[2]', 'int[10][2]'.
165  while (const ArrayType *AT = T->getAsArrayTypeUnsafe()) {
166  QualType ElemType = AT->getElementType();
167  if (typesCompatible(C, PT, AT->getElementType()))
168  return true;
169  T = ElemType;
170  }
171 
172  return false;
173 }
174 
175 class MallocSizeofChecker : public Checker<check::ASTCodeBody> {
176 public:
177  void checkASTCodeBody(const Decl *D, AnalysisManager& mgr,
178  BugReporter &BR) const {
180  CastedAllocFinder Finder(&BR.getContext());
181  Finder.Visit(D->getBody());
182  for (CastedAllocFinder::CallVec::iterator i = Finder.Calls.begin(),
183  e = Finder.Calls.end(); i != e; ++i) {
184  QualType CastedType = i->CastedExpr->getType();
185  if (!CastedType->isPointerType())
186  continue;
187  QualType PointeeType = CastedType->getAs<PointerType>()->getPointeeType();
188  if (PointeeType->isVoidType())
189  continue;
190 
191  for (CallExpr::const_arg_iterator ai = i->AllocCall->arg_begin(),
192  ae = i->AllocCall->arg_end(); ai != ae; ++ai) {
193  if (!(*ai)->getType()->isIntegralOrUnscopedEnumerationType())
194  continue;
195 
196  SizeofFinder SFinder;
197  SFinder.Visit(*ai);
198  if (SFinder.Sizeofs.size() != 1)
199  continue;
200 
201  QualType SizeofType = SFinder.Sizeofs[0]->getTypeOfArgument();
202 
203  if (typesCompatible(BR.getContext(), PointeeType, SizeofType))
204  continue;
205 
206  // If the argument to sizeof is an array, the result could be a
207  // pointer to any array element.
208  if (compatibleWithArrayType(BR.getContext(), PointeeType, SizeofType))
209  continue;
210 
211  const TypeSourceInfo *TSI = nullptr;
212  if (i->CastedExprParent.is<const VarDecl *>()) {
213  TSI =
214  i->CastedExprParent.get<const VarDecl *>()->getTypeSourceInfo();
215  } else {
216  TSI = i->ExplicitCastType;
217  }
218 
219  SmallString<64> buf;
220  llvm::raw_svector_ostream OS(buf);
221 
222  OS << "Result of ";
223  const FunctionDecl *Callee = i->AllocCall->getDirectCallee();
224  if (Callee && Callee->getIdentifier())
225  OS << '\'' << Callee->getIdentifier()->getName() << '\'';
226  else
227  OS << "call";
228  OS << " is converted to a pointer of type '"
229  << PointeeType.getAsString() << "', which is incompatible with "
230  << "sizeof operand type '" << SizeofType.getAsString() << "'";
232  Ranges.push_back(i->AllocCall->getCallee()->getSourceRange());
233  Ranges.push_back(SFinder.Sizeofs[0]->getSourceRange());
234  if (TSI)
235  Ranges.push_back(TSI->getTypeLoc().getSourceRange());
236 
238  PathDiagnosticLocation::createBegin(i->AllocCall->getCallee(),
239  BR.getSourceManager(), ADC);
240 
241  BR.EmitBasicReport(D, this, "Allocator sizeof operand mismatch",
242  categories::UnixAPI, OS.str(), L, Ranges);
243  }
244  }
245  }
246 };
247 
248 }
249 
250 void ento::registerMallocSizeofChecker(CheckerManager &mgr) {
251  mgr.registerChecker<MallocSizeofChecker>();
252 }
FunctionDecl - An instance of this class is created to represent a function declaration or definition...
Definition: Decl.h:1698
PointerType - C99 6.7.5.1 - Pointer Declarators.
Definition: Type.h:2285
A (possibly-)qualified type.
Definition: Type.h:653
ConstStmtVisitor - This class implements a simple visitor for Stmt subclasses.
Definition: StmtVisitor.h:192
virtual Stmt * getBody() const
getBody - If this Decl represents a declaration for a body of code, such as a function or method defi...
Definition: DeclBase.h:974
Stmt - This represents one statement.
Definition: Stmt.h:66
QualType getPointeeType() const
If this is a pointer, ObjC object pointer, or block pointer, this returns the respective pointee...
Definition: Type.cpp:456
Decl - This represents one declaration (or definition), e.g.
Definition: DeclBase.h:86
ParenExpr - This represents a parethesized expression, e.g.
Definition: Expr.h:1665
Represents an array type, per C99 6.7.5.2 - Array Declarators.
Definition: Type.h:2560
TypeSourceInfo * getTypeInfoAsWritten() const
getTypeInfoAsWritten - Returns the type source info for the type that this expression is casting to...
Definition: Expr.h:2906
A container of type source information.
Definition: Decl.h:86
VarDecl - An instance of this class is created to represent a variable declaration or definition...
Definition: Decl.h:807
const T * getAs() const
Member-template getAs<specific type>&#39;.
Definition: Type.h:6307
IdentifierInfo * getIdentifier() const
getIdentifier - Get the identifier that names this declaration, if there is one.
Definition: Decl.h:265
One of these records is kept for each identifier that is lexed.
Holds long-lived AST nodes (such as types and decls) that can be referred to throughout the semantic ...
Definition: ASTContext.h:149
AnalysisDeclContext contains the context data for the function or method under analysis.
Expr * getSubExpr()
Definition: Expr.h:2761
const ArrayType * getAsArrayTypeUnsafe() const
A variant of getAs<> for array types which silently discards qualifiers from the outermost type...
Definition: Type.h:6356
ASTContext & getContext()
Definition: BugReporter.h:461
child_range children()
Definition: Stmt.cpp:226
A builtin binary operation expression such as "x + y" or "x <= y".
Definition: Expr.h:2985
std::string getAsString() const
Definition: Type.h:979
const Type * getTypePtr() const
Retrieves a pointer to the underlying (unqualified) type.
Definition: Type.h:5720
CastExpr - Base class for type casts, including both implicit casts (ImplicitCastExpr) and explicit c...
Definition: Expr.h:2710
AnalysisDeclContext * getAnalysisDeclContext(const Decl *D)
NodeId Parent
Definition: ASTDiff.cpp:192
Const iterator for iterating over Stmt * arrays that contain only Expr *.
Definition: Stmt.h:346
UnaryExprOrTypeTraitExpr - expression with either a type or (unevaluated) expression operand...
Definition: Expr.h:2031
Expr - This represents one expression.
Definition: Expr.h:106
const FunctionProtoType * T
Defines the clang::TypeLoc interface and its subclasses.
const Expr * getSubExpr() const
Definition: Expr.h:1681
bool isVoidPointerType() const
Definition: Type.cpp:426
BugReporter is a utility class for generating PathDiagnostics for analysis.
Definition: BugReporter.h:403
static PathDiagnosticLocation createBegin(const Decl *D, const SourceManager &SM)
Create a location for the beginning of the declaration.
QualType getCanonicalType() const
Definition: Type.h:5759
CHECKER * registerChecker()
Used to register checkers.
void EmitBasicReport(const Decl *DeclWithIssue, const CheckerBase *Checker, StringRef BugName, StringRef BugCategory, StringRef BugStr, PathDiagnosticLocation Loc, ArrayRef< SourceRange > Ranges=None)
DeclStmt - Adaptor class for mixing declarations with statements and expressions. ...
Definition: Stmt.h:487
UnaryExprOrTypeTrait getKind() const
Definition: Expr.h:2062
ImplicitCastExpr - Allows us to explicitly represent implicit type conversions, which have no direct ...
Definition: Expr.h:2822
Expr * getLHS() const
Definition: Expr.h:3029
StringRef getName() const
Return the actual identifier string.
Dataflow Directional Tag Classes.
FunctionDecl * getDirectCallee()
If the callee is a FunctionDecl, return it. Otherwise return 0.
Definition: Expr.cpp:1216
ExplicitCastExpr - An explicit cast written in the source code.
Definition: Expr.h:2888
SourceRange getSourceRange() const LLVM_READONLY
Get the full source range.
Definition: TypeLoc.h:150
decl_range decls()
Definition: Stmt.h:534
TypeLoc getTypeLoc() const
Return the TypeLoc wrapper for the type source info.
Definition: TypeLoc.h:239
SourceManager & getSourceManager()
Definition: BugReporter.h:463
bool isVoidType() const
Definition: Type.h:6171
CallExpr - Represents a function call (C99 6.5.2.2, C++ [expr.call]).
Definition: Expr.h:2209
Expr * getRHS() const
Definition: Expr.h:3031
bool isPointerType() const
Definition: Type.h:5944