528 lines · cpp
1//===----------------------------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "SizeofExpressionCheck.h"10#include "../utils/Matchers.h"11#include "clang/AST/ASTContext.h"12#include "clang/ASTMatchers/ASTMatchFinder.h"13 14using namespace clang::ast_matchers;15 16namespace clang::tidy::bugprone {17 18namespace {19 20AST_MATCHER_P(IntegerLiteral, isBiggerThan, unsigned, N) {21 return Node.getValue().ugt(N);22}23 24AST_MATCHER_P2(Expr, hasSizeOfDescendant, int, Depth,25 ast_matchers::internal::Matcher<Expr>, InnerMatcher) {26 if (Depth < 0)27 return false;28 29 const Expr *E = Node.IgnoreParenImpCasts();30 if (InnerMatcher.matches(*E, Finder, Builder))31 return true;32 33 if (const auto *CE = dyn_cast<CastExpr>(E)) {34 const auto M = hasSizeOfDescendant(Depth - 1, InnerMatcher);35 return M.matches(*CE->getSubExpr(), Finder, Builder);36 }37 if (const auto *UE = dyn_cast<UnaryOperator>(E)) {38 const auto M = hasSizeOfDescendant(Depth - 1, InnerMatcher);39 return M.matches(*UE->getSubExpr(), Finder, Builder);40 }41 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);46 }47 48 return false;49}50 51AST_MATCHER(Expr, offsetOfExpr) { return isa<OffsetOfExpr>(Node); }52 53} // namespace54 55static CharUnits getSizeOfType(const ASTContext &Ctx, const Type *Ty) {56 if (!Ty || Ty->isIncompleteType() || Ty->isDependentType() ||57 isa<DependentSizedArrayType>(Ty) || !Ty->isConstantSizeType())58 return CharUnits::Zero();59 return Ctx.getTypeSizeInChars(Ty);60}61 62SizeofExpressionCheck::SizeofExpressionCheck(StringRef Name,63 ClangTidyContext *Context)64 : ClangTidyCheck(Name, Context),65 WarnOnSizeOfConstant(Options.get("WarnOnSizeOfConstant", true)),66 WarnOnSizeOfIntegerExpression(67 Options.get("WarnOnSizeOfIntegerExpression", false)),68 WarnOnSizeOfThis(Options.get("WarnOnSizeOfThis", true)),69 WarnOnSizeOfCompareToConstant(70 Options.get("WarnOnSizeOfCompareToConstant", true)),71 WarnOnSizeOfPointerToAggregate(72 Options.get("WarnOnSizeOfPointerToAggregate", true)),73 WarnOnSizeOfPointer(Options.get("WarnOnSizeOfPointer", false)),74 WarnOnOffsetDividedBySizeOf(75 Options.get("WarnOnOffsetDividedBySizeOf", true)),76 WarnOnSizeOfInLoopTermination(77 Options.get("WarnOnSizeOfInLoopTermination", true)) {}78 79void SizeofExpressionCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {80 Options.store(Opts, "WarnOnSizeOfConstant", WarnOnSizeOfConstant);81 Options.store(Opts, "WarnOnSizeOfIntegerExpression",82 WarnOnSizeOfIntegerExpression);83 Options.store(Opts, "WarnOnSizeOfThis", WarnOnSizeOfThis);84 Options.store(Opts, "WarnOnSizeOfCompareToConstant",85 WarnOnSizeOfCompareToConstant);86 Options.store(Opts, "WarnOnSizeOfPointerToAggregate",87 WarnOnSizeOfPointerToAggregate);88 Options.store(Opts, "WarnOnSizeOfPointer", WarnOnSizeOfPointer);89 Options.store(Opts, "WarnOnOffsetDividedBySizeOf",90 WarnOnOffsetDividedBySizeOf);91 Options.store(Opts, "WarnOnSizeOfInLoopTermination",92 WarnOnSizeOfInLoopTermination);93}94 95void SizeofExpressionCheck::registerMatchers(MatchFinder *Finder) {96 // FIXME:97 // Some of the checks should not match in template code to avoid false98 // positives if sizeof is applied on template argument.99 100 auto LoopCondExpr =101 [](const ast_matchers::internal::Matcher<Stmt> &InnerMatcher) {102 return stmt(anyOf(forStmt(hasCondition(InnerMatcher)),103 whileStmt(hasCondition(InnerMatcher)),104 doStmt(hasCondition(InnerMatcher))));105 };106 107 const auto IntegerExpr = ignoringParenImpCasts(integerLiteral());108 const auto ConstantExpr = ignoringParenImpCasts(109 anyOf(integerLiteral(), unaryOperator(hasUnaryOperand(IntegerExpr)),110 binaryOperator(hasLHS(IntegerExpr), hasRHS(IntegerExpr))));111 const auto IntegerCallExpr = ignoringParenImpCasts(callExpr(112 anyOf(hasType(isInteger()), hasType(hasCanonicalType(enumType()))),113 unless(isInTemplateInstantiation())));114 const auto SizeOfExpr = sizeOfExpr(hasArgumentOfType(115 hasUnqualifiedDesugaredType(type().bind("sizeof-arg-type"))));116 const auto SizeOfZero =117 sizeOfExpr(has(ignoringParenImpCasts(integerLiteral(equals(0)))));118 119 // Detect expression like: sizeof(ARRAYLEN);120 // Note: The expression 'sizeof(sizeof(0))' is a portable trick used to know121 // the sizeof size_t.122 if (WarnOnSizeOfConstant) {123 Finder->addMatcher(124 expr(sizeOfExpr(has(ignoringParenImpCasts(ConstantExpr))),125 unless(SizeOfZero))126 .bind("sizeof-constant"),127 this);128 }129 130 // Detect sizeof(f())131 if (WarnOnSizeOfIntegerExpression) {132 Finder->addMatcher(sizeOfExpr(ignoringParenImpCasts(has(IntegerCallExpr)))133 .bind("sizeof-integer-call"),134 this);135 }136 137 // Detect expression like: sizeof(this);138 if (WarnOnSizeOfThis) {139 Finder->addMatcher(sizeOfExpr(has(ignoringParenImpCasts(cxxThisExpr())))140 .bind("sizeof-this"),141 this);142 }143 144 if (WarnOnSizeOfInLoopTermination) {145 auto CondExpr = binaryOperator(146 allOf(has(SizeOfExpr.bind("sizeof-expr")), isComparisonOperator()));147 Finder->addMatcher(LoopCondExpr(anyOf(CondExpr, hasDescendant(CondExpr)))148 .bind("loop-expr"),149 this);150 }151 152 // Detect sizeof(kPtr) where kPtr is 'const char* kPtr = "abc"';153 const auto CharPtrType = pointerType(pointee(isAnyCharacter()));154 const auto ConstStrLiteralDecl =155 varDecl(isDefinition(), hasType(hasCanonicalType(CharPtrType)),156 hasInitializer(ignoringParenImpCasts(stringLiteral())));157 const auto VarWithConstStrLiteralDecl = expr(158 hasType(hasCanonicalType(CharPtrType)),159 ignoringParenImpCasts(declRefExpr(hasDeclaration(ConstStrLiteralDecl))));160 Finder->addMatcher(161 sizeOfExpr(has(ignoringParenImpCasts(VarWithConstStrLiteralDecl)))162 .bind("sizeof-charp"),163 this);164 165 // Detect sizeof(ptr) where ptr is a pointer (CWE-467).166 //167 // In WarnOnSizeOfPointerToAggregate mode only report cases when ptr points168 // to an aggregate type or ptr is an expression that (implicitly or169 // explicitly) casts an array to a pointer type. (These are more suspicious170 // than other sizeof(ptr) expressions because they can appear as distorted171 // forms of the common sizeof(aggregate) expressions.)172 //173 // To avoid false positives, the check doesn't report expressions like174 // 'sizeof(pp[0])' and 'sizeof(*pp)' where `pp` is a pointer-to-pointer or175 // array of pointers. (This filters out both `sizeof(arr) / sizeof(arr[0])`176 // expressions and other cases like `p = realloc(p, newsize * sizeof(*p));`.)177 //178 // Moreover this generic message is suppressed in cases that are also matched179 // by the more concrete matchers 'sizeof-this' and 'sizeof-charp'.180 if (WarnOnSizeOfPointerToAggregate || WarnOnSizeOfPointer) {181 const auto ArrayExpr =182 ignoringParenImpCasts(hasType(hasCanonicalType(arrayType())));183 const auto ArrayCastExpr = expr(anyOf(184 unaryOperator(hasUnaryOperand(ArrayExpr), unless(hasOperatorName("*"))),185 binaryOperator(hasEitherOperand(ArrayExpr)),186 castExpr(hasSourceExpression(ArrayExpr))));187 const auto PointerToArrayExpr =188 hasType(hasCanonicalType(pointerType(pointee(arrayType()))));189 190 const auto PointerToStructType =191 hasUnqualifiedDesugaredType(pointerType(pointee(recordType())));192 const auto PointerToStructExpr =193 expr(hasType(hasCanonicalType(PointerToStructType)));194 195 const auto PointerToDetectedExpr =196 WarnOnSizeOfPointer197 ? expr(hasType(hasUnqualifiedDesugaredType(pointerType())))198 : expr(anyOf(ArrayCastExpr, PointerToArrayExpr,199 PointerToStructExpr));200 201 const auto ZeroLiteral = ignoringParenImpCasts(integerLiteral(equals(0)));202 const auto SubscriptExprWithZeroIndex =203 arraySubscriptExpr(hasIndex(ZeroLiteral));204 const auto DerefExpr =205 ignoringParenImpCasts(unaryOperator(hasOperatorName("*")));206 207 Finder->addMatcher(208 expr(sizeOfExpr(has(ignoringParenImpCasts(expr(209 PointerToDetectedExpr, unless(DerefExpr),210 unless(SubscriptExprWithZeroIndex),211 unless(VarWithConstStrLiteralDecl), unless(cxxThisExpr()))))))212 .bind("sizeof-pointer"),213 this);214 }215 216 // Detect expression like: sizeof(expr) <= k for a suspicious constant 'k'.217 if (WarnOnSizeOfCompareToConstant) {218 Finder->addMatcher(219 binaryOperator(matchers::isRelationalOperator(),220 hasOperands(ignoringParenImpCasts(SizeOfExpr),221 ignoringParenImpCasts(integerLiteral(anyOf(222 equals(0), isBiggerThan(0x80000))))))223 .bind("sizeof-compare-constant"),224 this);225 }226 227 // Detect expression like: sizeof(expr, expr); most likely an error.228 Finder->addMatcher(229 sizeOfExpr(230 has(ignoringParenImpCasts(231 binaryOperator(hasOperatorName(",")).bind("sizeof-comma-binop"))))232 .bind("sizeof-comma-expr"),233 this);234 235 // Detect sizeof(...) /sizeof(...));236 // FIXME:237 // Re-evaluate what cases to handle by the checker.238 // Probably any sizeof(A)/sizeof(B) should be error if239 // 'A' is not an array (type) and 'B' the (type of the) first element of it.240 // Except if 'A' and 'B' are non-pointers, then use the existing size division241 // rule.242 const auto ElemType =243 arrayType(hasElementType(recordType().bind("elem-type")));244 const auto ElemPtrType = pointerType(pointee(type().bind("elem-ptr-type")));245 const auto SizeofDivideExpr = binaryOperator(246 hasOperatorName("/"),247 hasLHS(248 ignoringParenImpCasts(sizeOfExpr(hasArgumentOfType(hasCanonicalType(249 type(anyOf(ElemType, ElemPtrType, type())).bind("num-type")))))),250 hasRHS(ignoringParenImpCasts(sizeOfExpr(251 hasArgumentOfType(hasCanonicalType(type().bind("denom-type")))))));252 253 Finder->addMatcher(SizeofDivideExpr.bind("sizeof-divide-expr"), this);254 255 // Detect expression like: sizeof(...) * sizeof(...)); most likely an error.256 Finder->addMatcher(binaryOperator(hasOperatorName("*"),257 hasLHS(ignoringParenImpCasts(SizeOfExpr)),258 hasRHS(ignoringParenImpCasts(SizeOfExpr)))259 .bind("sizeof-multiply-sizeof"),260 this);261 262 Finder->addMatcher(263 binaryOperator(hasOperatorName("*"),264 hasOperands(ignoringParenImpCasts(SizeOfExpr),265 ignoringParenImpCasts(binaryOperator(266 hasOperatorName("*"),267 hasEitherOperand(268 ignoringParenImpCasts(SizeOfExpr))))))269 .bind("sizeof-multiply-sizeof"),270 this);271 272 // Detect strange double-sizeof expression like: sizeof(sizeof(...));273 // Note: The expression 'sizeof(sizeof(0))' is accepted.274 Finder->addMatcher(sizeOfExpr(has(ignoringParenImpCasts(hasSizeOfDescendant(275 8, allOf(SizeOfExpr, unless(SizeOfZero))))))276 .bind("sizeof-sizeof-expr"),277 this);278 279 // Detect sizeof usage in comparisons involving pointer arithmetics, such as280 // N * sizeof(T) == P1 - P2 or (P1 - P2) / sizeof(T), where P1 and P2 are281 // pointers to a type T.282 const auto PtrDiffExpr = binaryOperator(283 hasOperatorName("-"),284 hasLHS(hasType(hasUnqualifiedDesugaredType(pointerType(pointee(285 hasUnqualifiedDesugaredType(type().bind("left-ptr-type"))))))),286 hasRHS(hasType(hasUnqualifiedDesugaredType(pointerType(pointee(287 hasUnqualifiedDesugaredType(type().bind("right-ptr-type"))))))));288 289 Finder->addMatcher(290 binaryOperator(291 hasAnyOperatorName("==", "!=", "<", "<=", ">", ">=", "+", "-"),292 hasOperands(anyOf(ignoringParenImpCasts(293 SizeOfExpr.bind("sizeof-ptr-mul-expr")),294 ignoringParenImpCasts(binaryOperator(295 hasOperatorName("*"),296 hasEitherOperand(ignoringParenImpCasts(297 SizeOfExpr.bind("sizeof-ptr-mul-expr")))))),298 ignoringParenImpCasts(PtrDiffExpr)))299 .bind("sizeof-in-ptr-arithmetic-mul"),300 this);301 302 Finder->addMatcher(303 binaryOperator(304 hasOperatorName("/"), hasLHS(ignoringParenImpCasts(PtrDiffExpr)),305 hasRHS(ignoringParenImpCasts(SizeOfExpr.bind("sizeof-ptr-div-expr"))))306 .bind("sizeof-in-ptr-arithmetic-div"),307 this);308 309 // SEI CERT ARR39-C. Do not add or subtract a scaled integer to a pointer.310 // Detect sizeof, alignof and offsetof usage in pointer arithmetics where311 // they are used to scale the numeric distance, which is scaled again by312 // the pointer arithmetic operator. This can result in forming invalid313 // offsets.314 //315 // Examples, where P is a pointer, N is some integer (both compile-time and316 // run-time): P + sizeof(T), P + sizeof(*P), P + N * sizeof(*P).317 //318 // This check does not warn on cases where the pointee type is "1 byte",319 // as those cases can often come from generics and also do not constitute a320 // problem because the size does not affect the scale used.321 const auto InterestingPtrTyForPtrArithmetic =322 pointerType(pointee(qualType().bind("pointee-type")));323 const auto SizeofLikeScaleExpr =324 expr(anyOf(unaryExprOrTypeTraitExpr(ofKind(UETT_SizeOf)),325 unaryExprOrTypeTraitExpr(ofKind(UETT_AlignOf)),326 offsetOfExpr()))327 .bind("sizeof-in-ptr-arithmetic-scale-expr");328 const auto PtrArithmeticIntegerScaleExpr = binaryOperator(329 WarnOnOffsetDividedBySizeOf ? binaryOperator(hasAnyOperatorName("*", "/"))330 : binaryOperator(hasOperatorName("*")),331 // sizeof(...) * sizeof(...) and sizeof(...) / sizeof(...) is handled332 // by this check on another path.333 hasOperands(expr(hasType(isInteger()), unless(SizeofLikeScaleExpr)),334 SizeofLikeScaleExpr));335 const auto PtrArithmeticScaledIntegerExpr =336 expr(anyOf(SizeofLikeScaleExpr, PtrArithmeticIntegerScaleExpr),337 unless(SizeofDivideExpr));338 339 Finder->addMatcher(340 expr(anyOf(341 binaryOperator(hasAnyOperatorName("+", "-"),342 hasOperands(hasType(InterestingPtrTyForPtrArithmetic),343 PtrArithmeticScaledIntegerExpr))344 .bind("sizeof-in-ptr-arithmetic-plusminus"),345 binaryOperator(hasAnyOperatorName("+=", "-="),346 hasLHS(hasType(InterestingPtrTyForPtrArithmetic)),347 hasRHS(PtrArithmeticScaledIntegerExpr))348 .bind("sizeof-in-ptr-arithmetic-plusminus"))),349 this);350}351 352void SizeofExpressionCheck::check(const MatchFinder::MatchResult &Result) {353 const ASTContext &Ctx = *Result.Context;354 355 if (const auto *E = Result.Nodes.getNodeAs<Expr>("sizeof-constant")) {356 diag(E->getBeginLoc(), "suspicious usage of 'sizeof(K)'; did you mean 'K'?")357 << E->getSourceRange();358 } else if (const auto *E =359 Result.Nodes.getNodeAs<Expr>("sizeof-integer-call")) {360 diag(E->getBeginLoc(), "suspicious usage of 'sizeof()' on an expression "361 "of integer type")362 << E->getSourceRange();363 } else if (const auto *E = Result.Nodes.getNodeAs<Expr>("sizeof-this")) {364 diag(E->getBeginLoc(),365 "suspicious usage of 'sizeof(this)'; did you mean 'sizeof(*this)'")366 << E->getSourceRange();367 } else if (const auto *E = Result.Nodes.getNodeAs<Expr>("sizeof-charp")) {368 diag(E->getBeginLoc(),369 "suspicious usage of 'sizeof(char*)'; do you mean 'strlen'?")370 << E->getSourceRange();371 } else if (Result.Nodes.getNodeAs<Stmt>("loop-expr")) {372 auto *SizeofArgTy = Result.Nodes.getNodeAs<Type>("sizeof-arg-type");373 if (const auto *Member = dyn_cast<MemberPointerType>(SizeofArgTy))374 SizeofArgTy = Member->getPointeeType().getTypePtr();375 376 const auto *SzOfExpr = Result.Nodes.getNodeAs<Expr>("sizeof-expr");377 378 if (const auto *Type = dyn_cast<ArrayType>(SizeofArgTy)) {379 // check if the array element size is larger than one. If true,380 // the size of the array is higher than the number of elements381 if (!getSizeOfType(Ctx, Type->getElementType().getTypePtr()).isOne()) {382 diag(SzOfExpr->getBeginLoc(),383 "suspicious usage of 'sizeof' in the loop")384 << SzOfExpr->getSourceRange();385 }386 }387 } else if (const auto *E = Result.Nodes.getNodeAs<Expr>("sizeof-pointer")) {388 diag(E->getBeginLoc(), "suspicious usage of 'sizeof()' on an expression "389 "of pointer type")390 << E->getSourceRange();391 } else if (const auto *E = Result.Nodes.getNodeAs<BinaryOperator>(392 "sizeof-compare-constant")) {393 diag(E->getOperatorLoc(),394 "suspicious comparison of 'sizeof(expr)' to a constant")395 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();396 } else if (const auto *E =397 Result.Nodes.getNodeAs<Expr>("sizeof-comma-expr")) {398 const auto *BO =399 Result.Nodes.getNodeAs<BinaryOperator>("sizeof-comma-binop");400 assert(BO);401 diag(BO->getOperatorLoc(), "suspicious usage of 'sizeof(..., ...)'")402 << E->getSourceRange();403 } else if (const auto *E =404 Result.Nodes.getNodeAs<BinaryOperator>("sizeof-divide-expr")) {405 const auto *NumTy = Result.Nodes.getNodeAs<Type>("num-type");406 const auto *DenomTy = Result.Nodes.getNodeAs<Type>("denom-type");407 const auto *ElementTy = Result.Nodes.getNodeAs<Type>("elem-type");408 const auto *PointedTy = Result.Nodes.getNodeAs<Type>("elem-ptr-type");409 410 const CharUnits NumeratorSize = getSizeOfType(Ctx, NumTy);411 const CharUnits DenominatorSize = getSizeOfType(Ctx, DenomTy);412 const CharUnits ElementSize = getSizeOfType(Ctx, ElementTy);413 414 if (DenominatorSize > CharUnits::Zero() &&415 !NumeratorSize.isMultipleOf(DenominatorSize)) {416 diag(E->getOperatorLoc(), "suspicious usage of 'sizeof(...)/sizeof(...)';"417 " numerator is not a multiple of denominator")418 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();419 } else if (ElementSize > CharUnits::Zero() &&420 DenominatorSize > CharUnits::Zero() &&421 ElementSize != DenominatorSize) {422 // FIXME: Apparently there are no testcases that cover this branch!423 diag(E->getOperatorLoc(),424 "suspicious usage of 'sizeof(array)/sizeof(...)';"425 " denominator differs from the size of array elements")426 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();427 } else if (NumTy && DenomTy && ASTContext::hasSameType(NumTy, DenomTy) &&428 !NumTy->isDependentType()) {429 // Dependent type should not be compared.430 diag(E->getOperatorLoc(),431 "suspicious usage of 'sizeof(...)/sizeof(...)'; both expressions "432 "have the same type")433 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();434 } else if (!WarnOnSizeOfPointer) {435 // When 'WarnOnSizeOfPointer' is enabled, these messages become redundant:436 if (PointedTy && DenomTy && ASTContext::hasSameType(PointedTy, DenomTy)) {437 diag(E->getOperatorLoc(),438 "suspicious usage of 'sizeof(...)/sizeof(...)'; size of pointer "439 "is divided by size of pointed type")440 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();441 } else if (NumTy && DenomTy && NumTy->isPointerType() &&442 DenomTy->isPointerType()) {443 diag(E->getOperatorLoc(),444 "suspicious usage of 'sizeof(...)/sizeof(...)'; both expressions "445 "have pointer types")446 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();447 }448 }449 } else if (const auto *E =450 Result.Nodes.getNodeAs<Expr>("sizeof-sizeof-expr")) {451 diag(E->getBeginLoc(), "suspicious usage of 'sizeof(sizeof(...))'")452 << E->getSourceRange();453 } else if (const auto *E = Result.Nodes.getNodeAs<BinaryOperator>(454 "sizeof-multiply-sizeof")) {455 diag(E->getOperatorLoc(), "suspicious 'sizeof' by 'sizeof' multiplication")456 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();457 } else if (const auto *E = Result.Nodes.getNodeAs<BinaryOperator>(458 "sizeof-in-ptr-arithmetic-mul")) {459 const auto *LPtrTy = Result.Nodes.getNodeAs<Type>("left-ptr-type");460 const auto *RPtrTy = Result.Nodes.getNodeAs<Type>("right-ptr-type");461 const auto *SizeofArgTy = Result.Nodes.getNodeAs<Type>("sizeof-arg-type");462 const auto *SizeOfExpr =463 Result.Nodes.getNodeAs<UnaryExprOrTypeTraitExpr>("sizeof-ptr-mul-expr");464 465 if (ASTContext::hasSameType(LPtrTy, RPtrTy) &&466 ASTContext::hasSameType(LPtrTy, SizeofArgTy)) {467 diag(SizeOfExpr->getBeginLoc(), "suspicious usage of 'sizeof(...)' in "468 "pointer arithmetic")469 << SizeOfExpr->getSourceRange() << E->getOperatorLoc()470 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();471 }472 } else if (const auto *E = Result.Nodes.getNodeAs<BinaryOperator>(473 "sizeof-in-ptr-arithmetic-div")) {474 const auto *LPtrTy = Result.Nodes.getNodeAs<Type>("left-ptr-type");475 const auto *RPtrTy = Result.Nodes.getNodeAs<Type>("right-ptr-type");476 const auto *SizeofArgTy = Result.Nodes.getNodeAs<Type>("sizeof-arg-type");477 const auto *SizeOfExpr =478 Result.Nodes.getNodeAs<UnaryExprOrTypeTraitExpr>("sizeof-ptr-div-expr");479 480 if (ASTContext::hasSameType(LPtrTy, RPtrTy) &&481 ASTContext::hasSameType(LPtrTy, SizeofArgTy)) {482 diag(SizeOfExpr->getBeginLoc(), "suspicious usage of 'sizeof(...)' in "483 "pointer arithmetic")484 << SizeOfExpr->getSourceRange() << E->getOperatorLoc()485 << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();486 }487 } else if (const auto *E = Result.Nodes.getNodeAs<BinaryOperator>(488 "sizeof-in-ptr-arithmetic-plusminus")) {489 const auto *PointeeTy = Result.Nodes.getNodeAs<QualType>("pointee-type");490 const auto *ScaleExpr =491 Result.Nodes.getNodeAs<Expr>("sizeof-in-ptr-arithmetic-scale-expr");492 const CharUnits PointeeSize = getSizeOfType(Ctx, PointeeTy->getTypePtr());493 const int ScaleKind = [ScaleExpr]() {494 if (const auto *UTTE = dyn_cast<UnaryExprOrTypeTraitExpr>(ScaleExpr))495 switch (UTTE->getKind()) {496 case UETT_SizeOf:497 return 0;498 case UETT_AlignOf:499 return 1;500 default:501 return -1;502 }503 504 if (isa<OffsetOfExpr>(ScaleExpr))505 return 2;506 507 return -1;508 }();509 510 if (ScaleKind != -1 && PointeeSize > CharUnits::One()) {511 diag(E->getExprLoc(),512 "suspicious usage of '%select{sizeof|alignof|offsetof}0(...)' in "513 "pointer arithmetic; this scaled value will be scaled again by the "514 "'%1' operator")515 << ScaleKind << E->getOpcodeStr() << ScaleExpr->getSourceRange();516 diag(E->getExprLoc(),517 "'%0' in pointer arithmetic internally scales with 'sizeof(%1)' == "518 "%2",519 DiagnosticIDs::Note)520 << E->getOpcodeStr()521 << PointeeTy->getAsString(Ctx.getPrintingPolicy())522 << PointeeSize.getQuantity();523 }524 }525}526 527} // namespace clang::tidy::bugprone528