22 #include "llvm/ADT/SmallString.h"
23 #include "llvm/Support/raw_ostream.h"
25 using namespace clang;
30 typedef std::pair<const TypeSourceInfo *, const CallExpr *> TypeCallPair;
31 typedef llvm::PointerUnion<const Stmt *, const VarDecl *> ExprParent;
33 class CastedAllocFinder
39 ExprParent CastedExprParent;
40 const Expr *CastedExpr;
44 CallRecord(ExprParent CastedExprParent,
const Expr *CastedExpr,
47 : CastedExprParent(CastedExprParent), CastedExpr(CastedExpr),
48 ExplicitCastType(ExplicitCastType), AllocCall(AllocCall) {}
51 typedef std::vector<CallRecord> CallVec;
55 II_malloc(&Ctx->Idents.get(
"malloc")),
56 II_calloc(&Ctx->Idents.get(
"calloc")),
57 II_realloc(&Ctx->Idents.get(
"realloc")) {}
59 void VisitChild(ExprParent
Parent,
const Stmt *S) {
60 TypeCallPair AllocCall = Visit(S);
61 if (AllocCall.second && AllocCall.second != S)
62 Calls.push_back(CallRecord(
Parent, cast<Expr>(S), AllocCall.first,
66 void VisitChildren(
const Stmt *S) {
67 for (
const Stmt *Child : S->children())
72 TypeCallPair VisitCastExpr(
const CastExpr *E) {
81 TypeCallPair VisitParenExpr(
const ParenExpr *E) {
85 TypeCallPair VisitStmt(
const Stmt *S) {
87 return TypeCallPair();
90 TypeCallPair VisitCallExpr(
const CallExpr *E) {
95 if (II == II_malloc || II == II_calloc || II == II_realloc)
98 return TypeCallPair();
101 TypeCallPair VisitDeclStmt(
const DeclStmt *S) {
102 for (
const auto *I : S->decls())
103 if (
const VarDecl *VD = dyn_cast<VarDecl>(I))
104 if (
const Expr *Init = VD->getInit())
105 VisitChild(VD, Init);
106 return TypeCallPair();
112 std::vector<const UnaryExprOrTypeTraitExpr *> Sizeofs;
123 void VisitParenExpr(
const ParenExpr *E) {
128 if (E->
getKind() != UETT_SizeOf)
131 Sizeofs.push_back(E);
169 QualType ElemType = AT->getElementType();
170 if (typesCompatible(C, PT, AT->getElementType()))
178 class MallocSizeofChecker :
public Checker<check::ASTCodeBody> {
180 void checkASTCodeBody(
const Decl *D, AnalysisManager& mgr,
181 BugReporter &BR)
const {
183 CastedAllocFinder Finder(&BR.getContext());
185 for (CastedAllocFinder::CallVec::iterator i = Finder.Calls.begin(),
186 e = Finder.Calls.end(); i != e; ++i) {
187 QualType CastedType = i->CastedExpr->getType();
195 ae = i->AllocCall->arg_end(); ai != ae; ++ai) {
196 if (!(*ai)->getType()->isIntegralOrUnscopedEnumerationType())
199 SizeofFinder SFinder;
201 if (SFinder.Sizeofs.size() != 1)
204 QualType SizeofType = SFinder.Sizeofs[0]->getTypeOfArgument();
206 if (typesCompatible(BR.getContext(), PointeeType, SizeofType))
211 if (compatibleWithArrayType(BR.getContext(), PointeeType, SizeofType))
215 if (i->CastedExprParent.is<
const VarDecl *>()) {
217 i->CastedExprParent.get<
const VarDecl *>()->getTypeSourceInfo();
219 TSI = i->ExplicitCastType;
223 llvm::raw_svector_ostream
OS(buf);
227 if (Callee &&
Callee->getIdentifier())
228 OS <<
'\'' <<
Callee->getIdentifier()->getName() <<
'\'';
231 OS <<
" is converted to a pointer of type '" << PointeeType
232 <<
"', which is incompatible with "
233 <<
"sizeof operand type '" << SizeofType <<
"'";
235 Ranges.push_back(i->AllocCall->getCallee()->getSourceRange());
236 Ranges.push_back(SFinder.Sizeofs[0]->getSourceRange());
240 PathDiagnosticLocation L =
242 BR.getSourceManager(), ADC);
244 BR.EmitBasicReport(D,
this,
"Allocator sizeof operand mismatch",
253 void ento::registerMallocSizeofChecker(CheckerManager &mgr) {
254 mgr.registerChecker<MallocSizeofChecker>();
257 bool ento::shouldRegisterMallocSizeofChecker(
const CheckerManager &mgr) {