10 #include "../utils/Matchers.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/ASTMatchers/ASTMatchFinder.h"
23 return Node.getValue().getZExtValue() > N;
26 AST_MATCHER_P2(Expr, hasSizeOfDescendant,
int, Depth,
27 ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
31 const Expr *
E = Node.IgnoreParenImpCasts();
32 if (InnerMatcher.matches(*
E, Finder,
Builder))
35 if (
const auto *
CE = dyn_cast<CastExpr>(
E)) {
36 const auto M = hasSizeOfDescendant(Depth - 1, InnerMatcher);
37 return M.matches(*
CE->getSubExpr(), Finder,
Builder);
38 }
else if (
const auto *UE = dyn_cast<UnaryOperator>(
E)) {
39 const auto M = hasSizeOfDescendant(Depth - 1, InnerMatcher);
40 return M.matches(*UE->getSubExpr(), Finder,
Builder);
41 }
else if (
const auto *BE = dyn_cast<BinaryOperator>(
E)) {
42 const auto LHS = hasSizeOfDescendant(Depth - 1, InnerMatcher);
43 const auto RHS = hasSizeOfDescendant(Depth - 1, InnerMatcher);
44 return LHS.matches(*BE->getLHS(), Finder,
Builder) ||
45 RHS.matches(*BE->getRHS(), Finder,
Builder);
51 CharUnits getSizeOfType(
const ASTContext &
Ctx,
const Type *Ty) {
52 if (!Ty || Ty->isIncompleteType() || Ty->isDependentType() ||
53 isa<DependentSizedArrayType>(Ty) || !Ty->isConstantSizeType())
54 return CharUnits::Zero();
55 return Ctx.getTypeSizeInChars(Ty);
60 SizeofExpressionCheck::SizeofExpressionCheck(StringRef
Name,
63 WarnOnSizeOfConstant(Options.get(
"WarnOnSizeOfConstant", true)),
64 WarnOnSizeOfIntegerExpression(
65 Options.get(
"WarnOnSizeOfIntegerExpression", false)),
66 WarnOnSizeOfThis(Options.get(
"WarnOnSizeOfThis", true)),
67 WarnOnSizeOfCompareToConstant(
68 Options.get(
"WarnOnSizeOfCompareToConstant", true)) {}
71 Options.
store(Opts,
"WarnOnSizeOfConstant", WarnOnSizeOfConstant);
73 WarnOnSizeOfIntegerExpression);
74 Options.
store(Opts,
"WarnOnSizeOfThis", WarnOnSizeOfThis);
76 WarnOnSizeOfCompareToConstant);
80 const auto IntegerExpr = ignoringParenImpCasts(integerLiteral());
81 const auto ConstantExpr = expr(ignoringParenImpCasts(
82 anyOf(integerLiteral(), unaryOperator(hasUnaryOperand(IntegerExpr)),
83 binaryOperator(hasLHS(IntegerExpr), hasRHS(IntegerExpr)))));
84 const auto IntegerCallExpr = expr(ignoringParenImpCasts(
85 callExpr(anyOf(hasType(isInteger()), hasType(enumType())),
86 unless(isInTemplateInstantiation()))));
87 const auto SizeOfExpr = expr(anyOf(
89 has(hasUnqualifiedDesugaredType(type().bind(
"sizeof-arg-type")))),
90 sizeOfExpr(has(expr(hasType(
91 hasUnqualifiedDesugaredType(type().bind(
"sizeof-arg-type"))))))));
92 const auto SizeOfZero = expr(
93 sizeOfExpr(has(ignoringParenImpCasts(expr(integerLiteral(equals(0)))))));
98 if (WarnOnSizeOfConstant) {
100 expr(sizeOfExpr(has(ignoringParenImpCasts(ConstantExpr))),
102 .bind(
"sizeof-constant"),
107 if (WarnOnSizeOfIntegerExpression) {
109 expr(sizeOfExpr(ignoringParenImpCasts(has(IntegerCallExpr))))
110 .bind(
"sizeof-integer-call"),
115 if (WarnOnSizeOfThis) {
117 expr(sizeOfExpr(has(ignoringParenImpCasts(expr(cxxThisExpr())))))
118 .bind(
"sizeof-this"),
123 const auto CharPtrType = pointerType(pointee(isAnyCharacter()));
124 const auto ConstStrLiteralDecl =
125 varDecl(isDefinition(), hasType(qualType(hasCanonicalType(CharPtrType))),
126 hasInitializer(ignoringParenImpCasts(stringLiteral())));
127 Finder->addMatcher(expr(sizeOfExpr(has(ignoringParenImpCasts(expr(
128 hasType(qualType(hasCanonicalType(CharPtrType))),
129 ignoringParenImpCasts(declRefExpr(
130 hasDeclaration(ConstStrLiteralDecl))))))))
131 .bind(
"sizeof-charp"),
135 const auto ArrayExpr = expr(ignoringParenImpCasts(
136 expr(hasType(qualType(hasCanonicalType(arrayType()))))));
137 const auto ArrayCastExpr = expr(anyOf(
138 unaryOperator(hasUnaryOperand(ArrayExpr), unless(hasOperatorName(
"*"))),
139 binaryOperator(hasEitherOperand(ArrayExpr)),
140 castExpr(hasSourceExpression(ArrayExpr))));
141 const auto PointerToArrayExpr = expr(ignoringParenImpCasts(expr(
142 hasType(qualType(hasCanonicalType(pointerType(pointee(arrayType()))))))));
144 const auto StructAddrOfExpr =
145 unaryOperator(hasOperatorName(
"&"),
146 hasUnaryOperand(ignoringParenImpCasts(expr(
147 hasType(qualType(hasCanonicalType(recordType())))))));
148 const auto PointerToStructType = type(hasUnqualifiedDesugaredType(
149 pointerType(pointee(recordType()))));
150 const auto PointerToStructExpr = expr(ignoringParenImpCasts(expr(
151 hasType(qualType(hasCanonicalType(PointerToStructType))),
152 unless(cxxThisExpr()))));
155 expr(anyOf(sizeOfExpr(has(expr(ignoringParenImpCasts(
156 anyOf(ArrayCastExpr, PointerToArrayExpr, StructAddrOfExpr,
157 PointerToStructExpr))))),
158 sizeOfExpr(has(PointerToStructType))))
159 .bind(
"sizeof-pointer-to-aggregate"),
163 if (WarnOnSizeOfCompareToConstant) {
165 binaryOperator(matchers::isRelationalOperator(),
166 hasOperands(ignoringParenImpCasts(SizeOfExpr),
167 ignoringParenImpCasts(anyOf(
168 integerLiteral(equals(0)),
169 integerLiteral(isBiggerThan(0x80000))))))
170 .bind(
"sizeof-compare-constant"),
175 Finder->addMatcher(expr(sizeOfExpr(has(expr(ignoringParenImpCasts(
176 binaryOperator(hasOperatorName(
",")))))))
177 .bind(
"sizeof-comma-expr"),
181 const auto ElemType =
182 arrayType(hasElementType(recordType().bind(
"elem-type")));
183 const auto ElemPtrType = pointerType(pointee(type().bind(
"elem-ptr-type")));
184 const auto NumType = qualType(hasCanonicalType(
185 type(anyOf(ElemType, ElemPtrType, type())).bind(
"num-type")));
186 const auto DenomType = qualType(hasCanonicalType(type().bind(
"denom-type")));
189 binaryOperator(hasOperatorName(
"/"),
190 hasLHS(expr(ignoringParenImpCasts(
191 anyOf(sizeOfExpr(has(NumType)),
192 sizeOfExpr(has(expr(hasType(NumType)))))))),
193 hasRHS(expr(ignoringParenImpCasts(
194 anyOf(sizeOfExpr(has(DenomType)),
195 sizeOfExpr(has(expr(hasType(DenomType)))))))))
196 .bind(
"sizeof-divide-expr"),
200 Finder->addMatcher(binaryOperator(hasOperatorName(
"*"),
201 hasLHS(ignoringParenImpCasts(SizeOfExpr)),
202 hasRHS(ignoringParenImpCasts(SizeOfExpr)))
203 .bind(
"sizeof-multiply-sizeof"),
207 binaryOperator(hasOperatorName(
"*"),
208 hasOperands(ignoringParenImpCasts(SizeOfExpr),
209 ignoringParenImpCasts(binaryOperator(
210 hasOperatorName(
"*"),
212 ignoringParenImpCasts(SizeOfExpr))))))
213 .bind(
"sizeof-multiply-sizeof"),
219 expr(sizeOfExpr(has(ignoringParenImpCasts(expr(
220 hasSizeOfDescendant(8, expr(SizeOfExpr, unless(SizeOfZero))))))))
221 .bind(
"sizeof-sizeof-expr"),
226 const auto PtrDiffExpr = binaryOperator(
227 hasOperatorName(
"-"),
228 hasLHS(expr(hasType(hasUnqualifiedDesugaredType(pointerType(pointee(
229 hasUnqualifiedDesugaredType(type().bind(
"left-ptr-type")))))))),
230 hasRHS(expr(hasType(hasUnqualifiedDesugaredType(pointerType(pointee(
231 hasUnqualifiedDesugaredType(type().bind(
"right-ptr-type")))))))));
235 hasAnyOperatorName(
"==",
"!=",
"<",
"<=",
">",
">=",
"+",
"-"),
236 hasOperands(expr(anyOf(ignoringParenImpCasts(SizeOfExpr),
237 ignoringParenImpCasts(binaryOperator(
238 hasOperatorName(
"*"),
240 ignoringParenImpCasts(SizeOfExpr)))))),
241 ignoringParenImpCasts(PtrDiffExpr)))
242 .bind(
"sizeof-in-ptr-arithmetic-mul"),
245 Finder->addMatcher(binaryOperator(hasOperatorName(
"/"),
246 hasLHS(ignoringParenImpCasts(PtrDiffExpr)),
247 hasRHS(ignoringParenImpCasts(SizeOfExpr)))
248 .bind(
"sizeof-in-ptr-arithmetic-div"),
253 const ASTContext &
Ctx = *Result.Context;
255 if (
const auto *
E = Result.Nodes.getNodeAs<Expr>(
"sizeof-constant")) {
256 diag(
E->getBeginLoc(),
257 "suspicious usage of 'sizeof(K)'; did you mean 'K'?");
258 }
else if (
const auto *
E =
259 Result.Nodes.getNodeAs<Expr>(
"sizeof-integer-call")) {
260 diag(
E->getBeginLoc(),
"suspicious usage of 'sizeof()' on an expression "
261 "that results in an integer");
262 }
else if (
const auto *
E = Result.Nodes.getNodeAs<Expr>(
"sizeof-this")) {
263 diag(
E->getBeginLoc(),
264 "suspicious usage of 'sizeof(this)'; did you mean 'sizeof(*this)'");
265 }
else if (
const auto *
E = Result.Nodes.getNodeAs<Expr>(
"sizeof-charp")) {
266 diag(
E->getBeginLoc(),
267 "suspicious usage of 'sizeof(char*)'; do you mean 'strlen'?");
268 }
else if (
const auto *
E =
269 Result.Nodes.getNodeAs<Expr>(
"sizeof-pointer-to-aggregate")) {
270 diag(
E->getBeginLoc(),
271 "suspicious usage of 'sizeof(A*)'; pointer to aggregate");
272 }
else if (
const auto *
E =
273 Result.Nodes.getNodeAs<Expr>(
"sizeof-compare-constant")) {
274 diag(
E->getBeginLoc(),
275 "suspicious comparison of 'sizeof(expr)' to a constant");
276 }
else if (
const auto *
E =
277 Result.Nodes.getNodeAs<Expr>(
"sizeof-comma-expr")) {
278 diag(
E->getBeginLoc(),
"suspicious usage of 'sizeof(..., ...)'");
279 }
else if (
const auto *
E =
280 Result.Nodes.getNodeAs<Expr>(
"sizeof-divide-expr")) {
281 const auto *NumTy = Result.Nodes.getNodeAs<
Type>(
"num-type");
282 const auto *DenomTy = Result.Nodes.getNodeAs<
Type>(
"denom-type");
283 const auto *ElementTy = Result.Nodes.getNodeAs<
Type>(
"elem-type");
284 const auto *PointedTy = Result.Nodes.getNodeAs<
Type>(
"elem-ptr-type");
286 CharUnits NumeratorSize = getSizeOfType(
Ctx, NumTy);
287 CharUnits DenominatorSize = getSizeOfType(
Ctx, DenomTy);
288 CharUnits ElementSize = getSizeOfType(
Ctx, ElementTy);
290 if (DenominatorSize > CharUnits::Zero() &&
291 !NumeratorSize.isMultipleOf(DenominatorSize)) {
292 diag(
E->getBeginLoc(),
"suspicious usage of 'sizeof(...)/sizeof(...)';"
293 " numerator is not a multiple of denominator");
294 }
else if (ElementSize > CharUnits::Zero() &&
295 DenominatorSize > CharUnits::Zero() &&
296 ElementSize != DenominatorSize) {
297 diag(
E->getBeginLoc(),
"suspicious usage of 'sizeof(...)/sizeof(...)';"
298 " numerator is not a multiple of denominator");
299 }
else if (NumTy && DenomTy && NumTy == DenomTy) {
300 diag(
E->getBeginLoc(),
301 "suspicious usage of sizeof pointer 'sizeof(T)/sizeof(T)'");
302 }
else if (PointedTy && DenomTy && PointedTy == DenomTy) {
303 diag(
E->getBeginLoc(),
304 "suspicious usage of sizeof pointer 'sizeof(T*)/sizeof(T)'");
305 }
else if (NumTy && DenomTy && NumTy->isPointerType() &&
306 DenomTy->isPointerType()) {
307 diag(
E->getBeginLoc(),
308 "suspicious usage of sizeof pointer 'sizeof(P*)/sizeof(Q*)'");
310 }
else if (
const auto *
E =
311 Result.Nodes.getNodeAs<Expr>(
"sizeof-sizeof-expr")) {
312 diag(
E->getBeginLoc(),
"suspicious usage of 'sizeof(sizeof(...))'");
313 }
else if (
const auto *
E =
314 Result.Nodes.getNodeAs<Expr>(
"sizeof-multiply-sizeof")) {
315 diag(
E->getBeginLoc(),
"suspicious 'sizeof' by 'sizeof' multiplication");
316 }
else if (
const auto *
E =
317 Result.Nodes.getNodeAs<Expr>(
"sizeof-in-ptr-arithmetic-mul")) {
318 const auto *LPtrTy = Result.Nodes.getNodeAs<
Type>(
"left-ptr-type");
319 const auto *RPtrTy = Result.Nodes.getNodeAs<
Type>(
"right-ptr-type");
320 const auto *SizeofArgTy = Result.Nodes.getNodeAs<
Type>(
"sizeof-arg-type");
322 if ((LPtrTy == RPtrTy) && (LPtrTy == SizeofArgTy)) {
323 diag(
E->getBeginLoc(),
"suspicious usage of 'sizeof(...)' in "
324 "pointer arithmetic");
326 }
else if (
const auto *
E =
327 Result.Nodes.getNodeAs<Expr>(
"sizeof-in-ptr-arithmetic-div")) {
328 const auto *LPtrTy = Result.Nodes.getNodeAs<
Type>(
"left-ptr-type");
329 const auto *RPtrTy = Result.Nodes.getNodeAs<
Type>(
"right-ptr-type");
330 const auto *SizeofArgTy = Result.Nodes.getNodeAs<
Type>(
"sizeof-arg-type");
332 if ((LPtrTy == RPtrTy) && (LPtrTy == SizeofArgTy)) {
333 diag(
E->getBeginLoc(),
"suspicious usage of 'sizeof(...)' in "
334 "pointer arithmetic");