[clang-tools-extra] [clang-tidy] Extend `bugprone-sizeof-expression` with matching `P +- sizeof(T)` and `P +- N * sizeof(T)` cases, add `cert-arr39-c` alias (PR #106061)

via cfe-commits cfe-commits at lists.llvm.org
Wed Aug 28 03:40:28 PDT 2024


https://github.com/whisperity updated https://github.com/llvm/llvm-project/pull/106061

>From 0202caa773928bfc395b850f52191ab15afe0eb4 Mon Sep 17 00:00:00 2001
From: zporky <zporky at gmail.com>
Date: Thu, 26 Oct 2023 20:40:39 +0200
Subject: [PATCH 01/22] Initial pointer arithmetics using sizeof matcher

---
 .../bugprone/BugproneTidyModule.cpp           |  3 ++
 .../clang-tidy/bugprone/CMakeLists.txt        |  1 +
 ...iousPointerArithmeticsUsingSizeofCheck.cpp | 36 +++++++++++++++++++
 ...iciousPointerArithmeticsUsingSizeofCheck.h | 30 ++++++++++++++++
 .../clang-tidy/cert/CERTTidyModule.cpp        |  4 +++
 5 files changed, 74 insertions(+)
 create mode 100644 clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
 create mode 100644 clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.h

diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 543c522899d7a5..4f74fd9fd50543 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -67,6 +67,7 @@
 #include "SuspiciousMemoryComparisonCheck.h"
 #include "SuspiciousMemsetUsageCheck.h"
 #include "SuspiciousMissingCommaCheck.h"
+#include "SuspiciousPointerArithmeticsUsingSizeofCheck.h"
 #include "SuspiciousReallocUsageCheck.h"
 #include "SuspiciousSemicolonCheck.h"
 #include "SuspiciousStringCompareCheck.h"
@@ -204,6 +205,8 @@ class BugproneModule : public ClangTidyModule {
         "bugprone-suspicious-memset-usage");
     CheckFactories.registerCheck<SuspiciousMissingCommaCheck>(
         "bugprone-suspicious-missing-comma");
+    CheckFactories.registerCheck<SuspiciousPointerArithmeticsUsingSizeofCheck>(
+        "bugprone-suspicious-pointer-arithmetics-using-sizeof");
     CheckFactories.registerCheck<SuspiciousReallocUsageCheck>(
         "bugprone-suspicious-realloc-usage");
     CheckFactories.registerCheck<SuspiciousSemicolonCheck>(
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index 0df9e439b715e5..c9877e6f5a7ddc 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -64,6 +64,7 @@ add_clang_library(clangTidyBugproneModule
   SuspiciousMemoryComparisonCheck.cpp
   SuspiciousMemsetUsageCheck.cpp
   SuspiciousMissingCommaCheck.cpp
+  SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
   SuspiciousReallocUsageCheck.cpp
   SuspiciousSemicolonCheck.cpp
   SuspiciousStringCompareCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
new file mode 100644
index 00000000000000..abfa1bc7f037ea
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
@@ -0,0 +1,36 @@
+//===--- SuspiciousPointerArithmeticsUsingSizeofCheck.cpp - clang-tidy --===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "SuspiciousPointerArithmeticsUsingSizeofCheck.h"
+#include "../utils/Matchers.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+SuspiciousPointerArithmeticsUsingSizeofCheck::SuspiciousPointerArithmeticsUsingSizeofCheck(
+    StringRef Name, ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context) {
+}
+
+void SuspiciousPointerArithmeticsUsingSizeofCheck::registerMatchers(MatchFinder *Finder) {
+    Finder->addMatcher(
+		   sizeOfExpr(expr())
+            .bind("sizeof-expression"),
+        this);
+}
+
+void SuspiciousPointerArithmeticsUsingSizeofCheck::check(
+    const MatchFinder::MatchResult &Result) {
+}
+
+} // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.h b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.h
new file mode 100644
index 00000000000000..d39e15f0ccc3a0
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.h
@@ -0,0 +1,30 @@
+//===--- SuspiciousPointerArithmeticsUsingSizeofCheck.h - clang-tidy -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSPOINTERARITHMETICSSIZEOFCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSPOINTERARITHMETICSSIZEOFCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::bugprone {
+
+/// Find suspicious calls to string compare functions.
+///
+/// For the user-facing documentation see:
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-sizeof.html
+class SuspiciousPointerArithmeticsUsingSizeofCheck : public ClangTidyCheck {
+public:
+  SuspiciousPointerArithmeticsUsingSizeofCheck(StringRef Name, ClangTidyContext *Context);
+//  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+};
+
+} // namespace clang::tidy::bugprone
+
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSPOINTERARITHMETICSSIZEOFCHECK_H
diff --git a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
index d448d9ba614548..17a7e4bc51049d 100644
--- a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
@@ -15,6 +15,7 @@
 #include "../bugprone/SignedCharMisuseCheck.h"
 #include "../bugprone/SpuriouslyWakeUpFunctionsCheck.h"
 #include "../bugprone/SuspiciousMemoryComparisonCheck.h"
+#include "../bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.h"
 #include "../bugprone/UnhandledSelfAssignmentCheck.h"
 #include "../bugprone/UnsafeFunctionsCheck.h"
 #include "../bugprone/UnusedReturnValueCheck.h"
@@ -278,6 +279,9 @@ class CERTModule : public ClangTidyModule {
         "cert-oop58-cpp");
 
     // C checkers
+    // ARR
+    CheckFactories.registerCheck<bugprone::SuspiciousPointerArithmeticsUsingSizeofCheck>(
+        "cert-arr39-c");		    
     // CON
     CheckFactories.registerCheck<bugprone::SpuriouslyWakeUpFunctionsCheck>(
         "cert-con36-c");

>From f2d7d25549101d3250e65dc3a76dac766ccfc476 Mon Sep 17 00:00:00 2001
From: zporky <zporky at gmail.com>
Date: Fri, 3 Nov 2023 01:15:17 +0100
Subject: [PATCH 02/22] Working version of the checker.

---
 ...iousPointerArithmeticsUsingSizeofCheck.cpp | 21 +++++++++++++++----
 1 file changed, 17 insertions(+), 4 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
index abfa1bc7f037ea..de7c7e62e99282 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
@@ -12,6 +12,7 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Lex/Lexer.h"
+#include <iostream>
 
 using namespace clang::ast_matchers;
 
@@ -24,13 +25,25 @@ SuspiciousPointerArithmeticsUsingSizeofCheck::SuspiciousPointerArithmeticsUsingS
 
 void SuspiciousPointerArithmeticsUsingSizeofCheck::registerMatchers(MatchFinder *Finder) {
     Finder->addMatcher(
-		   sizeOfExpr(expr())
-            .bind("sizeof-expression"),
+	     expr(anyOf(
+                    binaryOperator(hasAnyOperatorName("+","-"),
+                      hasEitherOperand(hasType(pointerType())),
+		      hasEitherOperand(sizeOfExpr(expr())),
+		      unless(allOf(hasLHS(hasType(pointerType())),
+				   hasRHS(hasType(pointerType()))))
+		      ).bind("ptr-sizeof-expression"),
+		    binaryOperator(hasAnyOperatorName("+=","-="),
+	              hasLHS(hasType(pointerType())),
+		      hasRHS(sizeOfExpr(expr()))
+		      ).bind("ptr-sizeof-expression")
+            )),
         this);
 }
 
-void SuspiciousPointerArithmeticsUsingSizeofCheck::check(
-    const MatchFinder::MatchResult &Result) {
+void SuspiciousPointerArithmeticsUsingSizeofCheck::check(const MatchFinder::MatchResult &Result) {
+    static const char *diag_msg	= "Suspicious pointer arithmetics using sizeof() operator";
+    auto Matched = Result.Nodes.getNodeAs<BinaryOperator>("ptr-sizeof-expression");
+    diag(Matched->getExprLoc(),diag_msg)<< Matched->getSourceRange();
 }
 
 } // namespace clang::tidy::bugprone

>From 330dc16f6b7db1a34596f03105c1560bf94fea07 Mon Sep 17 00:00:00 2001
From: zporky <zporky at gmail.com>
Date: Fri, 3 Nov 2023 21:23:26 +0100
Subject: [PATCH 03/22] Code simplification with elevating string constants.

---
 .../SuspiciousPointerArithmeticsUsingSizeofCheck.cpp   | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
index de7c7e62e99282..90a8d308596cf6 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
@@ -12,10 +12,12 @@
 #include "clang/AST/ASTContext.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Lex/Lexer.h"
-#include <iostream>
 
 using namespace clang::ast_matchers;
 
+namespace {
+  static const char *bin_op_bind = "ptr-sizeof-expression";	
+}
 namespace clang::tidy::bugprone {
 
 SuspiciousPointerArithmeticsUsingSizeofCheck::SuspiciousPointerArithmeticsUsingSizeofCheck(
@@ -31,18 +33,18 @@ void SuspiciousPointerArithmeticsUsingSizeofCheck::registerMatchers(MatchFinder
 		      hasEitherOperand(sizeOfExpr(expr())),
 		      unless(allOf(hasLHS(hasType(pointerType())),
 				   hasRHS(hasType(pointerType()))))
-		      ).bind("ptr-sizeof-expression"),
+		      ).bind(bin_op_bind),
 		    binaryOperator(hasAnyOperatorName("+=","-="),
 	              hasLHS(hasType(pointerType())),
 		      hasRHS(sizeOfExpr(expr()))
-		      ).bind("ptr-sizeof-expression")
+		      ).bind(bin_op_bind)
             )),
         this);
 }
 
 void SuspiciousPointerArithmeticsUsingSizeofCheck::check(const MatchFinder::MatchResult &Result) {
     static const char *diag_msg	= "Suspicious pointer arithmetics using sizeof() operator";
-    auto Matched = Result.Nodes.getNodeAs<BinaryOperator>("ptr-sizeof-expression");
+    auto Matched = Result.Nodes.getNodeAs<BinaryOperator>(bin_op_bind);
     diag(Matched->getExprLoc(),diag_msg)<< Matched->getSourceRange();
 }
 

>From 27a2ac5e7e6168c43dd9fec14994176b7ed18ea0 Mon Sep 17 00:00:00 2001
From: zporky <zporky at gmail.com>
Date: Thu, 9 Nov 2023 20:02:38 +0100
Subject: [PATCH 04/22] filtering out char* like matches

---
 ...iousPointerArithmeticsUsingSizeofCheck.cpp | 19 ++++++++++++++-----
 1 file changed, 14 insertions(+), 5 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
index 90a8d308596cf6..02275a2cdfe747 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
@@ -15,11 +15,13 @@
 
 using namespace clang::ast_matchers;
 
-namespace {
-  static const char *bin_op_bind = "ptr-sizeof-expression";	
-}
 namespace clang::tidy::bugprone {
 
+//static const char *bin_op_bind = "ptr-sizeof-expression";	
+static constexpr llvm::StringLiteral BinOp{"bin-op"};
+static const auto IgnoredType = qualType(anyOf(asString("char"),asString("unsigned char"),asString("signed char"),asString("int8_t"),asString("uint8_t"),asString("std::byte"),asString("const char"),asString("const unsigned char"),asString("const signed char"),asString("const int8_t"),asString("const uint8_t"),asString("const std::byte")));
+static const auto InterestingPointer = pointerType(unless(pointee(IgnoredType)));
+
 SuspiciousPointerArithmeticsUsingSizeofCheck::SuspiciousPointerArithmeticsUsingSizeofCheck(
     StringRef Name, ClangTidyContext *Context)
     : ClangTidyCheck(Name, Context) {
@@ -28,7 +30,7 @@ SuspiciousPointerArithmeticsUsingSizeofCheck::SuspiciousPointerArithmeticsUsingS
 void SuspiciousPointerArithmeticsUsingSizeofCheck::registerMatchers(MatchFinder *Finder) {
     Finder->addMatcher(
 	     expr(anyOf(
-                    binaryOperator(hasAnyOperatorName("+","-"),
+/*                    binaryOperator(hasAnyOperatorName("+","-"),
                       hasEitherOperand(hasType(pointerType())),
 		      hasEitherOperand(sizeOfExpr(expr())),
 		      unless(allOf(hasLHS(hasType(pointerType())),
@@ -38,13 +40,20 @@ void SuspiciousPointerArithmeticsUsingSizeofCheck::registerMatchers(MatchFinder
 	              hasLHS(hasType(pointerType())),
 		      hasRHS(sizeOfExpr(expr()))
 		      ).bind(bin_op_bind)
+*/
+		    binaryOperator(hasAnyOperatorName("+=","-=","+","-" ),
+	              hasLHS(hasType(InterestingPointer)),
+		      hasRHS(sizeOfExpr(expr()))).bind(BinOp),
+		    binaryOperator(hasAnyOperatorName("+","-" ),
+	              hasRHS(hasType(InterestingPointer)),
+		      hasLHS(sizeOfExpr(expr()))).bind(BinOp)
             )),
         this);
 }
 
 void SuspiciousPointerArithmeticsUsingSizeofCheck::check(const MatchFinder::MatchResult &Result) {
     static const char *diag_msg	= "Suspicious pointer arithmetics using sizeof() operator";
-    auto Matched = Result.Nodes.getNodeAs<BinaryOperator>(bin_op_bind);
+    auto Matched = Result.Nodes.getNodeAs<BinaryOperator>(BinOp);
     diag(Matched->getExprLoc(),diag_msg)<< Matched->getSourceRange();
 }
 

>From 3ed1e4fd39e9efd88e509637a345118a9a7b3300 Mon Sep 17 00:00:00 2001
From: zporky <zporky at gmail.com>
Date: Wed, 15 Nov 2023 23:03:45 +0100
Subject: [PATCH 05/22] Filtering out the uninteresting types in imperative
 way.

---
 ...iousPointerArithmeticsUsingSizeofCheck.cpp | 29 +++++++++++++++++--
 1 file changed, 26 insertions(+), 3 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
index 02275a2cdfe747..91f5ac55c508b6 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
@@ -19,6 +19,7 @@ namespace clang::tidy::bugprone {
 
 //static const char *bin_op_bind = "ptr-sizeof-expression";	
 static constexpr llvm::StringLiteral BinOp{"bin-op"};
+static constexpr llvm::StringLiteral PointedType{"pointed-type"};
 static const auto IgnoredType = qualType(anyOf(asString("char"),asString("unsigned char"),asString("signed char"),asString("int8_t"),asString("uint8_t"),asString("std::byte"),asString("const char"),asString("const unsigned char"),asString("const signed char"),asString("const int8_t"),asString("const uint8_t"),asString("const std::byte")));
 static const auto InterestingPointer = pointerType(unless(pointee(IgnoredType)));
 
@@ -40,21 +41,43 @@ void SuspiciousPointerArithmeticsUsingSizeofCheck::registerMatchers(MatchFinder
 	              hasLHS(hasType(pointerType())),
 		      hasRHS(sizeOfExpr(expr()))
 		      ).bind(bin_op_bind)
-*/
+
 		    binaryOperator(hasAnyOperatorName("+=","-=","+","-" ),
 	              hasLHS(hasType(InterestingPointer)),
 		      hasRHS(sizeOfExpr(expr()))).bind(BinOp),
 		    binaryOperator(hasAnyOperatorName("+","-" ),
 	              hasRHS(hasType(InterestingPointer)),
 		      hasLHS(sizeOfExpr(expr()))).bind(BinOp)
+*/		    
+		    binaryOperator(hasAnyOperatorName("+=","-=","+","-" ),
+	              hasLHS(hasType(pointerType(pointee(qualType().bind(PointedType))))),
+		      hasRHS(sizeOfExpr(expr()))).bind(BinOp),
+		    binaryOperator(hasAnyOperatorName("+","-" ),
+	              hasRHS(hasType(pointerType(pointee(qualType().bind(PointedType))))),
+		      hasLHS(sizeOfExpr(expr()))).bind(BinOp)
             )),
         this);
 }
 
+static CharUnits getSizeOfType(const ASTContext &Ctx, const Type *Ty) {
+  if (!Ty || Ty->isIncompleteType() || Ty->isDependentType() ||
+      isa<DependentSizedArrayType>(Ty) || !Ty->isConstantSizeType())
+    return CharUnits::Zero();
+  return Ctx.getTypeSizeInChars(Ty);
+}
+
 void SuspiciousPointerArithmeticsUsingSizeofCheck::check(const MatchFinder::MatchResult &Result) {
     static const char *diag_msg	= "Suspicious pointer arithmetics using sizeof() operator";
-    auto Matched = Result.Nodes.getNodeAs<BinaryOperator>(BinOp);
-    diag(Matched->getExprLoc(),diag_msg)<< Matched->getSourceRange();
+    const ASTContext &Ctx = *Result.Context;
+    const auto Matched = Result.Nodes.getNodeAs<BinaryOperator>(BinOp);
+    const auto SuspiciousQualTypePtr = Result.Nodes.getNodeAs<QualType>(PointedType);
+    const auto SuspiciousTypePtr = SuspiciousQualTypePtr->getTypePtr();
+
+    auto sz = getSizeOfType(Ctx,SuspiciousTypePtr).getQuantity();
+    if ( sz > 1 )
+    {
+        diag(Matched->getExprLoc(),diag_msg)<< Matched->getSourceRange();
+    }
 }
 
 } // namespace clang::tidy::bugprone

>From 7e3b35dbf09d99fba55d42d9c4c5c571dd4703a6 Mon Sep 17 00:00:00 2001
From: zporky <zporky at gmail.com>
Date: Thu, 16 Nov 2023 20:35:03 +0100
Subject: [PATCH 06/22] Reporting the suspicious type and its size.

---
 ...SuspiciousPointerArithmeticsUsingSizeofCheck.cpp | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
index 91f5ac55c508b6..a1710916f762ff 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
@@ -67,16 +67,17 @@ static CharUnits getSizeOfType(const ASTContext &Ctx, const Type *Ty) {
 }
 
 void SuspiciousPointerArithmeticsUsingSizeofCheck::check(const MatchFinder::MatchResult &Result) {
-    static const char *diag_msg	= "Suspicious pointer arithmetics using sizeof() operator";
     const ASTContext &Ctx = *Result.Context;
-    const auto Matched = Result.Nodes.getNodeAs<BinaryOperator>(BinOp);
-    const auto SuspiciousQualTypePtr = Result.Nodes.getNodeAs<QualType>(PointedType);
-    const auto SuspiciousTypePtr = SuspiciousQualTypePtr->getTypePtr();
+    const BinaryOperator* Matched = Result.Nodes.getNodeAs<BinaryOperator>(BinOp);
+    const QualType* SuspiciousQualTypePtr = Result.Nodes.getNodeAs<QualType>(PointedType);
+    const Type* SuspiciousTypePtr = SuspiciousQualTypePtr->getTypePtr();
 
-    auto sz = getSizeOfType(Ctx,SuspiciousTypePtr).getQuantity();
+    std::size_t sz = getSizeOfType(Ctx,SuspiciousTypePtr).getQuantity();
     if ( sz > 1 )
     {
-        diag(Matched->getExprLoc(),diag_msg)<< Matched->getSourceRange();
+        diag(Matched->getExprLoc(),"Suspicious pointer arithmetics using sizeof() operator: sizeof(%0) is %1") << SuspiciousQualTypePtr->getAsString(Ctx.getPrintingPolicy())
+	                       << sz
+		               << Matched->getSourceRange();
     }
 }
 

>From fbbc8d2e75472ad8cdfdaef7f97083994f1ad3ef Mon Sep 17 00:00:00 2001
From: zporky <zporky at gmail.com>
Date: Fri, 5 Apr 2024 16:00:00 +0200
Subject: [PATCH 07/22] add initial test file

---
 ...picious-pointer-arithmetics-using-sizeof.c | 209 ++++++++++++++++++
 1 file changed, 209 insertions(+)
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c

diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c
new file mode 100644
index 00000000000000..353cbcc9e683ae
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c
@@ -0,0 +1,209 @@
+
+struct mystruct {
+  long a;
+  long b;
+  long c;
+};
+void noncompliant_f1(void);
+void compliant_f1(void);
+void noncompliant_f3(struct mystruct *msptr); 
+void compliant_f3(struct mystruct *msptr);
+extern void sink(const char *);
+
+enum { bufsize = 1024 };
+
+void noncompliant_f1(void) {
+  int buffer[bufsize]; 
+
+  int *bptr = &buffer[0]; 
+  int *ptr  = bptr; 
+  while ( ptr < bptr + sizeof(buffer) ) { // noncompliant
+    *ptr++ = 0;	// compliant  
+  }
+}
+void noncompliant_f1a(void) {
+  typedef int my_int_t;	
+  my_int_t buffer[bufsize]; 
+
+  my_int_t *bptr = &buffer[0]; 
+  my_int_t *ptr  = bptr; 
+  while ( ptr < bptr + sizeof(buffer) ) { // noncompliant
+    *ptr++ = 0;	// compliant  
+  }
+}
+void compliant_f1(void) {
+  int buffer[bufsize]; 
+
+  int *bptr = &buffer[0]; 
+  int *ptr  = bptr; 
+  while ( ptr < bptr + bufsize ) { // compliant
+    *ptr++ = 0;	// compliant  
+  }
+}
+
+void noncompliant_f2(void) {
+  int buffer[bufsize];
+  int *ptr = buffer;
+
+  while ( ptr < buffer + sizeof(buffer) ) { // noncompliant
+    *ptr++ = 0;	// compliant
+  }
+}
+
+void compliant_f2(void) {
+  int buffer[bufsize];
+  int *ptr  = buffer; 
+
+  while ( ptr < buffer + bufsize ) { // compliant
+    *ptr++ = 0;	// compliant  
+  }
+}
+
+void memset2(void*, int, unsigned int);
+
+void noncompliant_f3(struct mystruct *msptr) {
+  const unsigned int skip = sizeof(long); // why offsetof is declared?
+  struct mystruct *ptr = msptr;
+  
+  memset2(ptr + skip, // noncompliant, impossible with tidy
+                     0, sizeof(struct mystruct) - skip);
+}
+
+void compliant_f3(struct mystruct *msptr) {
+  const unsigned int skip = sizeof(long);
+  char *ptr = (char*)msptr;
+
+  memset2(ptr + skip, // compliant
+                     0, sizeof(struct mystruct) - skip); 
+}
+
+void noncompliant_f4(void) {
+  int buffer[bufsize]; 
+
+  int *bptr = &buffer[0]; 
+  int *ptr  = bptr; 
+  while ( ptr < bptr + bufsize ) { // compliant
+    *ptr = 0;	  
+    ptr += sizeof(*ptr); // noncompliant
+  }
+}
+void noncompliant_f4w(void) { /* accidentally good */
+  char buffer[bufsize]; 
+
+  char *bptr = &buffer[0]; 
+  char *ptr  = bptr; 
+  while ( ptr < bptr + bufsize ) { // compliant
+    *ptr = 0;	  
+    ptr += sizeof(*ptr);  // silenced
+  }
+}
+void compliant_f4w(void) {
+  char buffer[bufsize]; 
+
+  char *bptr = &buffer[0]; 
+  char *ptr  = bptr; 
+  while ( ptr < bptr + bufsize ) { // compliant
+    *ptr = 0;	  
+    ptr += 1;  // compliant
+  }
+}
+
+void noncompliant_f5(void) {
+  int buffer[bufsize]; 
+
+  int *bptr = &buffer[0]; 
+  int *ptr  = bptr; 
+  while ( ptr < bptr + bufsize ) { // compliant
+    *ptr = 0;	  
+    ptr = ptr + sizeof(*ptr); // noncompliant
+  }
+}
+void noncompliant_f5w(void) {
+  char buffer[bufsize]; 
+
+  char*bptr = &buffer[0]; 
+  char *ptr  = bptr; 
+  while ( ptr < bptr + bufsize ) { // compliant
+    *ptr = 0;	  
+    ptr = ptr + sizeof(*ptr); // silenced
+  }
+}
+void noncompliant_f5c(void) {
+  char buffer[bufsize]; 
+
+  char*bptr = &buffer[0]; 
+  const char *ptr  = bptr; 
+  while ( ptr < bptr + bufsize ) { // compliant
+    sink(ptr);	  
+    ptr = ptr + sizeof(*ptr); // silenced
+  }
+}
+void compliant_f5c(void) {
+  char buffer[bufsize]; 
+
+  char *bptr = &buffer[0]; 
+  const char *ptr  = bptr; 
+  while ( ptr < bptr + bufsize ) { // compliant
+    sink(ptr);	  
+    ptr = ptr + 1;  // compliant
+  }
+}
+
+void noncompliant_f6(void) {
+  int buffer[bufsize]; 
+
+  int *bptr = &buffer[0]; 
+  int *ptr  = bptr + bufsize; // compliant
+  while ( ptr >= bptr ) {
+    *ptr = 0;	  
+    ptr = ptr - sizeof(*ptr); // noncompliant
+  }
+}
+void noncompliant_f6w(void) {
+  char buffer[bufsize]; 
+
+  char *bptr = &buffer[0]; 
+  char *ptr  = bptr + bufsize; // compliant
+  while ( ptr >= bptr ) {
+    *ptr = 0;	  
+    ptr = ptr - sizeof(*ptr); // silenced
+  }
+}
+void compliant_f6(void) {
+  int buffer[bufsize]; 
+
+  int *bptr = &buffer[0]; 
+  int *ptr  = bptr + bufsize; // compliant
+  while ( ptr >= bptr ) {
+    *ptr = 0;	  
+    ptr = ptr - 1; // compliant
+  }
+}
+
+void compliant_f7(void) {
+  int buffer[bufsize]; 
+
+  int *bptr = &buffer[0]; 
+  int *ptr  = bptr + bufsize; // compliant
+  int i = ptr - bptr; // compliant
+  while ( i >= 0 ) {
+    ptr[i] = 0;	  
+    i = i - 1; // compliant
+  }
+}
+
+void compliant_f8(void) {
+  int buffer[bufsize]; 
+
+  int *bptr = &buffer[0]; 
+  int *ptr  = bptr + bufsize; // compliant
+  int i = sizeof(*ptr) - sizeof(*bptr); // compliant
+}
+void compliant_f9(void) {
+  int buffer[bufsize]; 
+
+  int *bptr = &buffer[0]; 
+  int *ptr  = bptr + bufsize; // compliant
+  int i = sizeof(ptr) - sizeof(*bptr); // compliant
+}
+

>From 80c67e581ad2debed748d7142ed72a468936122a Mon Sep 17 00:00:00 2001
From: Whisperity <whisperity at gmail.com>
Date: Mon, 26 Aug 2024 16:38:22 +0200
Subject: [PATCH 08/22] doc: Add documentation for the check

---
 ...iciousPointerArithmeticsUsingSizeofCheck.h | 15 ++++---
 ...cious-pointer-arithmetics-using-sizeof.rst | 44 +++++++++++++++++++
 .../docs/clang-tidy/checks/cert/arr39-c.rst   | 10 +++++
 3 files changed, 62 insertions(+), 7 deletions(-)
 create mode 100644 clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof.rst
 create mode 100644 clang-tools-extra/docs/clang-tidy/checks/cert/arr39-c.rst

diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.h b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.h
index d39e15f0ccc3a0..1dbc51dd3df84f 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.h
@@ -6,25 +6,26 @@
 //
 //===----------------------------------------------------------------------===//
 
-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSPOINTERARITHMETICSSIZEOFCHECK_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSPOINTERARITHMETICSSIZEOFCHECK_H
+#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSPOINTERARITHMETICSUSINGSIZEOFCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSPOINTERARITHMETICSUSINGSIZEOFCHECK_H
 
 #include "../ClangTidyCheck.h"
 
 namespace clang::tidy::bugprone {
 
-/// Find suspicious calls to string compare functions.
+/// Finds suspicious pointer arithmetic calculations where the pointer is
+/// offset by a sizeof() expression.
 ///
 /// For the user-facing documentation see:
-/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-sizeof.html
+/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof.html
 class SuspiciousPointerArithmeticsUsingSizeofCheck : public ClangTidyCheck {
 public:
-  SuspiciousPointerArithmeticsUsingSizeofCheck(StringRef Name, ClangTidyContext *Context);
-//  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+  SuspiciousPointerArithmeticsUsingSizeofCheck(StringRef Name,
+                                               ClangTidyContext *Context);
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
 };
 
 } // namespace clang::tidy::bugprone
 
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSPOINTERARITHMETICSSIZEOFCHECK_H
+#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSPOINTERARITHMETICSUSINGSIZEOFCHECK_H
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof.rst
new file mode 100644
index 00000000000000..5188f947627ab0
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof.rst
@@ -0,0 +1,44 @@
+.. title:: clang-tidy - bugprone-suspicious-pointer-arithmetics-using-sizeof
+
+bugprone-suspicious-pointer-arithmetics-using-sizeof
+====================================================
+
+Finds suspicious pointer arithmetic calculations where the pointer is offset by a ``sizeof()`` expression.
+
+Pointer arithmetic expressions implicitly scale the offset added to or subtracted from the address by the size of the pointee type.
+Scaling the offset expression manually effectively results in a squared offset, which creates an invalid pointer that points beyond the end of the intended array.
+
+.. code-block:: c++
+
+  void printEveryEvenIndexElement(int *Array, size_t N) {
+    int *P = Array;
+    while (P <= Array + N * sizeof(int)) { // Suspicious pointer arithmetics using sizeof()!
+      printf("%d ", *P);
+
+      P += 2 * sizeof(int); // Suspicious pointer arithmetics using sizeof()!
+    }
+  }
+
+The above example should be in the following, correct form:
+
+.. code-block:: c++
+
+  void printEveryEvenIndexElement(int *Array, size_t N) {
+    int *P = Array;
+    while (P <= Array + N) {
+      printf("%d ", *P);
+
+      P += 2;
+    }
+  }
+
+`cert-arr39-c` redirects here as an alias of this check.
+
+This check corresponds to the CERT C Coding Standard rule
+`ARR39-C. Do not add or subtract a scaled integer to a pointer
+<http://wiki.sei.cmu.edu/confluence/display/c/ARR39-C.+Do+not+add+or+subtract+a+scaled+integer+to+a+pointer>`_.
+
+Limitations
+-----------
+
+While incorrect from a technically rigorous point of view, the check does not warn for pointer arithmetics where the pointee type is ``char`` (``sizeof(char) == 1``, by definition) on purpose.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/cert/arr39-c.rst b/clang-tools-extra/docs/clang-tidy/checks/cert/arr39-c.rst
new file mode 100644
index 00000000000000..91e02e39952be9
--- /dev/null
+++ b/clang-tools-extra/docs/clang-tidy/checks/cert/arr39-c.rst
@@ -0,0 +1,10 @@
+.. title:: clang-tidy - cert-arr39-c
+.. meta::
+   :http-equiv=refresh: 5;URL=../bugprone/suspicious-pointer-arithmetics-using-sizeof.html
+
+cert-arr39-c
+============
+
+The `cert-arr39-c` check is an alias, please see
+:doc:`bugprone-suspicious-pointer-arithmetics-using-sizeof <../bugprone/suspicious-pointer-arithmetics-using-sizeof>`
+for more information.

>From be6c05aa90caa29b7e6a7b9aff5fd3e3c7082c73 Mon Sep 17 00:00:00 2001
From: Whisperity <whisperity at gmail.com>
Date: Mon, 26 Aug 2024 17:09:51 +0200
Subject: [PATCH 09/22] chore(doc): Added release notes entries

---
 clang-tools-extra/docs/ReleaseNotes.rst | 10 ++++++++++
 1 file changed, 10 insertions(+)

diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 1b025e8f90f7ba..ba2ffb6f8970ff 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -98,9 +98,19 @@ Improvements to clang-tidy
 New checks
 ^^^^^^^^^^
 
+- New :doc:`bugprone-suspicious-pointer-arithmetics-using-sizeof
+  <clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof>`
+  check that finds suspicious pointer arithmetic calculations where the pointer
+  is offset by a ``sizeof()`` expression.
+
 New check aliases
 ^^^^^^^^^^^^^^^^^
 
+- New alias :doc:`cert-arr39-c <clang-tidy/checks/cert/arr39-c>` to
+  :doc:`bugprone-suspicious-pointer-arithmetics-using-sizeof
+  <clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof>`
+  was added.
+
 Changes in existing checks
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 

>From cc5de412e09f44df8489a817edc8f219d71f6557 Mon Sep 17 00:00:00 2001
From: Whisperity <whisperity at gmail.com>
Date: Mon, 26 Aug 2024 17:11:50 +0200
Subject: [PATCH 10/22] style: Format out line break from `CERTModule`

---
 clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
index 9e90f363367496..39ba55142da4bc 100644
--- a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
@@ -283,8 +283,9 @@ class CERTModule : public ClangTidyModule {
 
     // C checkers
     // ARR
-    CheckFactories.registerCheck<bugprone::SuspiciousPointerArithmeticsUsingSizeofCheck>(
-        "cert-arr39-c");		    
+    CheckFactories
+      .registerCheck<bugprone::SuspiciousPointerArithmeticsUsingSizeofCheck>(
+        "cert-arr39-c");
     // CON
     CheckFactories.registerCheck<bugprone::SpuriouslyWakeUpFunctionsCheck>(
         "cert-con36-c");

>From 590a7718fb39c918ca8182ab2782c2d235dc8c07 Mon Sep 17 00:00:00 2001
From: Whisperity <whisperity at gmail.com>
Date: Mon, 26 Aug 2024 17:50:16 +0200
Subject: [PATCH 11/22] style: Apply some formatting fixes

---
 .../SuspiciousPointerArithmeticsUsingSizeofCheck.cpp     | 9 +++++----
 1 file changed, 5 insertions(+), 4 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
index a1710916f762ff..fc9c6eac38f91f 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
@@ -1,4 +1,4 @@
-//===--- SuspiciousPointerArithmeticsUsingSizeofCheck.cpp - clang-tidy --===//
+//===--- SuspiciousPointerArithmeticsUsingSizeofCheck.cpp - clang-tidy ----===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -68,9 +68,10 @@ static CharUnits getSizeOfType(const ASTContext &Ctx, const Type *Ty) {
 
 void SuspiciousPointerArithmeticsUsingSizeofCheck::check(const MatchFinder::MatchResult &Result) {
     const ASTContext &Ctx = *Result.Context;
-    const BinaryOperator* Matched = Result.Nodes.getNodeAs<BinaryOperator>(BinOp);
-    const QualType* SuspiciousQualTypePtr = Result.Nodes.getNodeAs<QualType>(PointedType);
-    const Type* SuspiciousTypePtr = SuspiciousQualTypePtr->getTypePtr();
+    const auto *Matched = Result.Nodes.getNodeAs<BinaryOperator>(BinOp);
+    const auto *SuspiciousQualTypePtr =
+        Result.Nodes.getNodeAs<QualType>(PointedType);
+    const auto *SuspiciousTypePtr = SuspiciousQualTypePtr->getTypePtr();
 
     std::size_t sz = getSizeOfType(Ctx,SuspiciousTypePtr).getQuantity();
     if ( sz > 1 )

>From 294ed749fea17a0a5f654347afee8c69a36a2844 Mon Sep 17 00:00:00 2001
From: Whisperity <whisperity at gmail.com>
Date: Mon, 26 Aug 2024 18:27:20 +0200
Subject: [PATCH 12/22] test: [wip] Start rewriting the test file (+ tear out
 line ending whitespace)

---
 ...picious-pointer-arithmetics-using-sizeof.c | 156 ++++++++++--------
 1 file changed, 83 insertions(+), 73 deletions(-)

diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c
index 353cbcc9e683ae..7acd7c17681fb9 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c
@@ -1,3 +1,32 @@
+// RUN: %check_clang_tidy %s bugprone-suspicious-pointer-arithmetics-using-sizeof %t
+
+enum { BufferSize = 1024 };
+
+void bad1(void) {
+  int Buffer[BufferSize];
+
+  int *P = &Buffer[0];
+  int *Q = P;
+  while (Q < P + sizeof(Buffer)) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: pointer arithmetic using a number scaled by 'sizeof()'; this distance will be scaled again by the '+' operator [bugprone-suspicious-pointer-arithemetics-using-sizeof]
+    // CHECK-MESSAGES: :[[@LINE-2]]:18: note: 'sizeof(int)' == {{[0-9]+}}
+    *Q++ = 0;
+  }
+}
+
+void good1(void) {
+  int Buffer[BufferSize];
+
+  int *P = &Buffer[0];
+  int *Q = P;
+  while (Q < P + BufferSize) {
+    *Q++ = 0;
+  }
+}
+
+
+// ----------------------------------------------------------------------------
+
 
 struct mystruct {
   long a;
@@ -6,38 +35,20 @@ struct mystruct {
 };
 void noncompliant_f1(void);
 void compliant_f1(void);
-void noncompliant_f3(struct mystruct *msptr); 
+void noncompliant_f3(struct mystruct *msptr);
 void compliant_f3(struct mystruct *msptr);
 extern void sink(const char *);
 
 enum { bufsize = 1024 };
 
-void noncompliant_f1(void) {
-  int buffer[bufsize]; 
-
-  int *bptr = &buffer[0]; 
-  int *ptr  = bptr; 
-  while ( ptr < bptr + sizeof(buffer) ) { // noncompliant
-    *ptr++ = 0;	// compliant  
-  }
-}
 void noncompliant_f1a(void) {
-  typedef int my_int_t;	
-  my_int_t buffer[bufsize]; 
+  typedef int my_int_t;
+  my_int_t buffer[bufsize];
 
-  my_int_t *bptr = &buffer[0]; 
-  my_int_t *ptr  = bptr; 
+  my_int_t *bptr = &buffer[0];
+  my_int_t *ptr  = bptr;
   while ( ptr < bptr + sizeof(buffer) ) { // noncompliant
-    *ptr++ = 0;	// compliant  
-  }
-}
-void compliant_f1(void) {
-  int buffer[bufsize]; 
-
-  int *bptr = &buffer[0]; 
-  int *ptr  = bptr; 
-  while ( ptr < bptr + bufsize ) { // compliant
-    *ptr++ = 0;	// compliant  
+    *ptr++ = 0;	// compliant
   }
 }
 
@@ -52,10 +63,10 @@ void noncompliant_f2(void) {
 
 void compliant_f2(void) {
   int buffer[bufsize];
-  int *ptr  = buffer; 
+  int *ptr  = buffer;
 
   while ( ptr < buffer + bufsize ) { // compliant
-    *ptr++ = 0;	// compliant  
+    *ptr++ = 0;	// compliant
   }
 }
 
@@ -64,7 +75,7 @@ void memset2(void*, int, unsigned int);
 void noncompliant_f3(struct mystruct *msptr) {
   const unsigned int skip = sizeof(long); // why offsetof is declared?
   struct mystruct *ptr = msptr;
-  
+
   memset2(ptr + skip, // noncompliant, impossible with tidy
                      0, sizeof(struct mystruct) - skip);
 }
@@ -74,136 +85,135 @@ void compliant_f3(struct mystruct *msptr) {
   char *ptr = (char*)msptr;
 
   memset2(ptr + skip, // compliant
-                     0, sizeof(struct mystruct) - skip); 
+                     0, sizeof(struct mystruct) - skip);
 }
 
 void noncompliant_f4(void) {
-  int buffer[bufsize]; 
+  int buffer[bufsize];
 
-  int *bptr = &buffer[0]; 
-  int *ptr  = bptr; 
+  int *bptr = &buffer[0];
+  int *ptr  = bptr;
   while ( ptr < bptr + bufsize ) { // compliant
-    *ptr = 0;	  
+    *ptr = 0;
     ptr += sizeof(*ptr); // noncompliant
   }
 }
 void noncompliant_f4w(void) { /* accidentally good */
-  char buffer[bufsize]; 
+  char buffer[bufsize];
 
-  char *bptr = &buffer[0]; 
-  char *ptr  = bptr; 
+  char *bptr = &buffer[0];
+  char *ptr  = bptr;
   while ( ptr < bptr + bufsize ) { // compliant
-    *ptr = 0;	  
+    *ptr = 0;
     ptr += sizeof(*ptr);  // silenced
   }
 }
 void compliant_f4w(void) {
-  char buffer[bufsize]; 
+  char buffer[bufsize];
 
-  char *bptr = &buffer[0]; 
-  char *ptr  = bptr; 
+  char *bptr = &buffer[0];
+  char *ptr  = bptr;
   while ( ptr < bptr + bufsize ) { // compliant
-    *ptr = 0;	  
+    *ptr = 0;
     ptr += 1;  // compliant
   }
 }
 
 void noncompliant_f5(void) {
-  int buffer[bufsize]; 
+  int buffer[bufsize];
 
-  int *bptr = &buffer[0]; 
-  int *ptr  = bptr; 
+  int *bptr = &buffer[0];
+  int *ptr  = bptr;
   while ( ptr < bptr + bufsize ) { // compliant
-    *ptr = 0;	  
+    *ptr = 0;
     ptr = ptr + sizeof(*ptr); // noncompliant
   }
 }
 void noncompliant_f5w(void) {
-  char buffer[bufsize]; 
+  char buffer[bufsize];
 
-  char*bptr = &buffer[0]; 
-  char *ptr  = bptr; 
+  char*bptr = &buffer[0];
+  char *ptr  = bptr;
   while ( ptr < bptr + bufsize ) { // compliant
-    *ptr = 0;	  
+    *ptr = 0;
     ptr = ptr + sizeof(*ptr); // silenced
   }
 }
 void noncompliant_f5c(void) {
-  char buffer[bufsize]; 
+  char buffer[bufsize];
 
-  char*bptr = &buffer[0]; 
-  const char *ptr  = bptr; 
+  char*bptr = &buffer[0];
+  const char *ptr  = bptr;
   while ( ptr < bptr + bufsize ) { // compliant
-    sink(ptr);	  
+    sink(ptr);
     ptr = ptr + sizeof(*ptr); // silenced
   }
 }
 void compliant_f5c(void) {
-  char buffer[bufsize]; 
+  char buffer[bufsize];
 
-  char *bptr = &buffer[0]; 
-  const char *ptr  = bptr; 
+  char *bptr = &buffer[0];
+  const char *ptr  = bptr;
   while ( ptr < bptr + bufsize ) { // compliant
-    sink(ptr);	  
+    sink(ptr);
     ptr = ptr + 1;  // compliant
   }
 }
 
 void noncompliant_f6(void) {
-  int buffer[bufsize]; 
+  int buffer[bufsize];
 
-  int *bptr = &buffer[0]; 
+  int *bptr = &buffer[0];
   int *ptr  = bptr + bufsize; // compliant
   while ( ptr >= bptr ) {
-    *ptr = 0;	  
+    *ptr = 0;
     ptr = ptr - sizeof(*ptr); // noncompliant
   }
 }
 void noncompliant_f6w(void) {
-  char buffer[bufsize]; 
+  char buffer[bufsize];
 
-  char *bptr = &buffer[0]; 
+  char *bptr = &buffer[0];
   char *ptr  = bptr + bufsize; // compliant
   while ( ptr >= bptr ) {
-    *ptr = 0;	  
+    *ptr = 0;
     ptr = ptr - sizeof(*ptr); // silenced
   }
 }
 void compliant_f6(void) {
-  int buffer[bufsize]; 
+  int buffer[bufsize];
 
-  int *bptr = &buffer[0]; 
+  int *bptr = &buffer[0];
   int *ptr  = bptr + bufsize; // compliant
   while ( ptr >= bptr ) {
-    *ptr = 0;	  
+    *ptr = 0;
     ptr = ptr - 1; // compliant
   }
 }
 
 void compliant_f7(void) {
-  int buffer[bufsize]; 
+  int buffer[bufsize];
 
-  int *bptr = &buffer[0]; 
+  int *bptr = &buffer[0];
   int *ptr  = bptr + bufsize; // compliant
   int i = ptr - bptr; // compliant
   while ( i >= 0 ) {
-    ptr[i] = 0;	  
+    ptr[i] = 0;
     i = i - 1; // compliant
   }
 }
 
 void compliant_f8(void) {
-  int buffer[bufsize]; 
+  int buffer[bufsize];
 
-  int *bptr = &buffer[0]; 
+  int *bptr = &buffer[0];
   int *ptr  = bptr + bufsize; // compliant
   int i = sizeof(*ptr) - sizeof(*bptr); // compliant
 }
 void compliant_f9(void) {
-  int buffer[bufsize]; 
+  int buffer[bufsize];
 
-  int *bptr = &buffer[0]; 
+  int *bptr = &buffer[0];
   int *ptr  = bptr + bufsize; // compliant
   int i = sizeof(ptr) - sizeof(*bptr); // compliant
 }
-

>From 7e44b452010bc978811aae57d362571146f68afa Mon Sep 17 00:00:00 2001
From: Whisperity <whisperity at gmail.com>
Date: Tue, 27 Aug 2024 15:19:40 +0200
Subject: [PATCH 13/22] test: Implemented the tests with proper format and `//
 CHECK` lines

---
 ...picious-pointer-arithmetics-using-sizeof.c | 352 +++++++++++-------
 1 file changed, 223 insertions(+), 129 deletions(-)

diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c
index 7acd7c17681fb9..8f2046ebdfa585 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c
@@ -1,15 +1,33 @@
 // RUN: %check_clang_tidy %s bugprone-suspicious-pointer-arithmetics-using-sizeof %t
 
+typedef __typeof__(sizeof(void*)) size_t;
+#define offsetof(type, member) __builtin_offsetof(type, member)
+extern void *memset(void *Dst, int Ch, size_t Count);
+extern void sink(const void *P);
+
 enum { BufferSize = 1024 };
 
-void bad1(void) {
+void bad1a(void) {
   int Buffer[BufferSize];
 
   int *P = &Buffer[0];
   int *Q = P;
   while (Q < P + sizeof(Buffer)) {
     // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: pointer arithmetic using a number scaled by 'sizeof()'; this distance will be scaled again by the '+' operator [bugprone-suspicious-pointer-arithemetics-using-sizeof]
-    // CHECK-MESSAGES: :[[@LINE-2]]:18: note: 'sizeof(int)' == {{[0-9]+}}
+    // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' scales with 'sizeof(Buffer)' == {{[0-9]+}}
+    *Q++ = 0;
+  }
+}
+
+void bad1b(void) {
+  typedef int Integer;
+  Integer Buffer[BufferSize];
+
+  Integer *P = &Buffer[0];
+  Integer *Q = P;
+  while (Q < P + sizeof(Buffer)) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: pointer arithmetic using a number scaled by 'sizeof()'; this distance will be scaled again by the '+' operator
+    // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' scales with 'sizeof(Buffer)' == {{[0-9]+}}
     *Q++ = 0;
   }
 }
@@ -24,196 +42,272 @@ void good1(void) {
   }
 }
 
+void bad2(void) {
+  int Buffer[BufferSize];
+  int *P = Buffer;
+
+  while (P < Buffer + sizeof(Buffer)) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: pointer arithmetic using a number scaled by 'sizeof()'; this value will be scaled again by the '+' operator
+    // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' scales with 'sizeof(int)' == {{[0-9]+}}
+    *P++ = 0;
+  }
+}
 
-// ----------------------------------------------------------------------------
+void good2(void) {
+  int Buffer[BufferSize];
+  int *P = Buffer;
 
+  while (P < Buffer + BufferSize) {
+    *P++ = 0;
+  }
+}
 
-struct mystruct {
-  long a;
-  long b;
-  long c;
+struct S {
+  long A, B, C;
 };
-void noncompliant_f1(void);
-void compliant_f1(void);
-void noncompliant_f3(struct mystruct *msptr);
-void compliant_f3(struct mystruct *msptr);
-extern void sink(const char *);
 
-enum { bufsize = 1024 };
+void bad3a(struct S *S) {
+  const size_t Offset = offsetof(struct S, B);
+  struct S *P = S;
+
+  // This is not captureable by Tidy because the size/offset expression is
+  // not a direct child of the pointer arithmetics.
+  memset(P + Offset, 0, sizeof(struct S) - Offset);
+}
+
+void good3a(struct S *S) {
+  const size_t Offset = offsetof(struct S, B);
+  char *P = (char*)S;
 
-void noncompliant_f1a(void) {
-  typedef int my_int_t;
-  my_int_t buffer[bufsize];
+  // This is not captureable by Tidy because the size/offset expression is
+  // not a direct child of the pointer arithmetics.
+  memset(P + Offset, 0, sizeof(struct S) - Offset);
+}
+
+void bad3b(struct S *S) {
+  memset(S + offsetof(struct S, B), 0,
+         sizeof(struct S) - offsetof(struct S, B));
+  // NCHECK-MESSAGES: :[[@LINE-1]]:12: warning: pointer arithmetic using a number scaled by 'offsetof()'; this value will be scaled again by the '+' operator
+  // NCHECK-MESSAGES: :[[@LINE-2]]:12: note: '+' scales with 'sizeof(int)' == {{[0-9]+}}
+}
 
-  my_int_t *bptr = &buffer[0];
-  my_int_t *ptr  = bptr;
-  while ( ptr < bptr + sizeof(buffer) ) { // noncompliant
-    *ptr++ = 0;	// compliant
+void good3b(struct S *S) {
+  char *P = (char*)S;
+  memset(P + offsetof(struct S, B), 0,
+         sizeof(struct S) - offsetof(struct S, B));
+}
+
+void bad3c(void) {
+  struct S Buffer[BufferSize];
+
+  struct S *P = &Buffer[0];
+  struct S *Q = P;
+  while (Q < P + sizeof(Buffer)) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: pointer arithmetic using a number scaled by 'sizeof()'; this value will be scaled again by the '+' operator
+    // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' scales with 'sizeof(struct S)' == {{[0-9]+}}
+    sink(Q++);
   }
 }
 
-void noncompliant_f2(void) {
-  int buffer[bufsize];
-  int *ptr = buffer;
+void bad4(void) {
+  int Buffer[BufferSize];
 
-  while ( ptr < buffer + sizeof(buffer) ) { // noncompliant
-    *ptr++ = 0;	// compliant
+  int *P = &Buffer[0];
+  int *Q = P;
+  while (Q < P + BufferSize) {
+    *Q = 0;
+    Q += sizeof(*Q);
+    // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic using a number scaled by 'sizeof()'; this value will be scaled again by the '+' operator
+    // CHECK-MESSAGES: :[[@LINE-2]]:7: note: '+' scales with 'sizeof(int)' == {{[0-9]+}}
   }
 }
 
-void compliant_f2(void) {
-  int buffer[bufsize];
-  int *ptr  = buffer;
+void silenced4(void) {
+  char Buffer[BufferSize];
 
-  while ( ptr < buffer + bufsize ) { // compliant
-    *ptr++ = 0;	// compliant
+  char *P = &Buffer[0];
+  char *Q = P;
+  while (Q < P + BufferSize) {
+    *Q = 0;
+    Q += sizeof(*Q);
   }
 }
 
-void memset2(void*, int, unsigned int);
+void good4(void) {
+  char Buffer[BufferSize];
 
-void noncompliant_f3(struct mystruct *msptr) {
-  const unsigned int skip = sizeof(long); // why offsetof is declared?
-  struct mystruct *ptr = msptr;
+  char *P = &Buffer[0];
+  char *Q = P;
+  while (Q < P + BufferSize) {
+    *Q = 0;
+    Q += 1;
+  }
+}
 
-  memset2(ptr + skip, // noncompliant, impossible with tidy
-                     0, sizeof(struct mystruct) - skip);
+void good5aa(void) {
+  int Buffer[BufferSize];
+
+  int *P = &Buffer[0];
+  int *Q = P;
+  while (Q < P + BufferSize) {
+    *Q = 0;
+    Q += ( sizeof(Buffer)/ sizeof(Buffer[0]) );
+  }
 }
 
-void compliant_f3(struct mystruct *msptr) {
-  const unsigned int skip = sizeof(long);
-  char *ptr = (char*)msptr;
+void good5ab(void) {
+  int Buffer[BufferSize];
 
-  memset2(ptr + skip, // compliant
-                     0, sizeof(struct mystruct) - skip);
+  int *P = &Buffer[0];
+  int *Q = P;
+  while (Q < P + BufferSize) {
+    *Q = 0;
+    Q = Q + ( sizeof(Buffer)/ sizeof(Buffer[0]) );
+  }
 }
 
-void noncompliant_f4(void) {
-  int buffer[bufsize];
+void good5ba(void) {
+  int Buffer[BufferSize];
 
-  int *bptr = &buffer[0];
-  int *ptr  = bptr;
-  while ( ptr < bptr + bufsize ) { // compliant
-    *ptr = 0;
-    ptr += sizeof(*ptr); // noncompliant
+  int *P = &Buffer[0];
+  int *Q = P;
+  while (Q < P + BufferSize) {
+    *Q = 0;
+    Q -= ( sizeof(Buffer)/ sizeof(Buffer[0]) );
   }
 }
-void noncompliant_f4w(void) { /* accidentally good */
-  char buffer[bufsize];
 
-  char *bptr = &buffer[0];
-  char *ptr  = bptr;
-  while ( ptr < bptr + bufsize ) { // compliant
-    *ptr = 0;
-    ptr += sizeof(*ptr);  // silenced
+void good5bb(void) {
+  int Buffer[BufferSize];
+
+  int *P = &Buffer[0];
+  int *Q = P;
+  while (Q < P + BufferSize) {
+    *Q = 0;
+    Q = Q - ( sizeof(Buffer)/ sizeof(Buffer[0]) );
   }
 }
-void compliant_f4w(void) {
-  char buffer[bufsize];
 
-  char *bptr = &buffer[0];
-  char *ptr  = bptr;
-  while ( ptr < bptr + bufsize ) { // compliant
-    *ptr = 0;
-    ptr += 1;  // compliant
+void bad6(void) {
+  int Buffer[BufferSize];
+
+  int *P = &Buffer[0];
+  int *Q = P;
+  while (Q < P + BufferSize) {
+    *Q = 0;
+    Q = Q + sizeof(*Q);
+    // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: pointer arithmetic using a number scaled by 'sizeof()'; this value will be scaled again by the '+' operator
+    // CHECK-MESSAGES: :[[@LINE-2]]:11: note: '+' scales with 'sizeof(int)' == {{[0-9]+}}
   }
 }
 
-void noncompliant_f5(void) {
-  int buffer[bufsize];
+void silenced6(void) {
+  char Buffer[BufferSize];
 
-  int *bptr = &buffer[0];
-  int *ptr  = bptr;
-  while ( ptr < bptr + bufsize ) { // compliant
-    *ptr = 0;
-    ptr = ptr + sizeof(*ptr); // noncompliant
+  char *P = &Buffer[0];
+  char *Q = P;
+  while (Q < P + BufferSize) {
+    *Q = 0;
+    Q = Q + sizeof(*Q);
   }
 }
-void noncompliant_f5w(void) {
-  char buffer[bufsize];
 
-  char*bptr = &buffer[0];
-  char *ptr  = bptr;
-  while ( ptr < bptr + bufsize ) { // compliant
-    *ptr = 0;
-    ptr = ptr + sizeof(*ptr); // silenced
+void good6(void) {
+  char Buffer[BufferSize];
+
+  char *P = &Buffer[0];
+  char *Q = P;
+  while (Q < P + BufferSize) {
+    *Q = 0;
+    Q = Q + 1;
   }
 }
-void noncompliant_f5c(void) {
-  char buffer[bufsize];
 
-  char*bptr = &buffer[0];
-  const char *ptr  = bptr;
-  while ( ptr < bptr + bufsize ) { // compliant
-    sink(ptr);
-    ptr = ptr + sizeof(*ptr); // silenced
+void silenced7(void) {
+  char Buffer[BufferSize];
+
+  char *P = &Buffer[0];
+  const char *Q = P;
+  while (Q < P + BufferSize) {
+    sink(Q);
+    Q = Q + sizeof(*Q);
   }
 }
-void compliant_f5c(void) {
-  char buffer[bufsize];
 
-  char *bptr = &buffer[0];
-  const char *ptr  = bptr;
-  while ( ptr < bptr + bufsize ) { // compliant
-    sink(ptr);
-    ptr = ptr + 1;  // compliant
+void good7(void) {
+  char Buffer[BufferSize];
+
+  char *P = &Buffer[0];
+  const char *Q = P;
+  while (Q < P + BufferSize) {
+    sink(Q);
+    Q = Q + 1;
   }
 }
 
-void noncompliant_f6(void) {
-  int buffer[bufsize];
+void bad8(void) {
+  int Buffer[BufferSize];
 
-  int *bptr = &buffer[0];
-  int *ptr  = bptr + bufsize; // compliant
-  while ( ptr >= bptr ) {
-    *ptr = 0;
-    ptr = ptr - sizeof(*ptr); // noncompliant
+  int *P = &Buffer[0];
+  int *Q = P;
+  while (Q >= P) {
+    *Q = 0;
+    Q = Q - sizeof(*Q);
+    // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: pointer arithmetic using a number scaled by 'sizeof()'; this value will be scaled again by the '-' operator
+    // CHECK-MESSAGES: :[[@LINE-2]]:11: note: '-' scales with 'sizeof(int)' == {{[0-9]+}}
   }
 }
-void noncompliant_f6w(void) {
-  char buffer[bufsize];
 
-  char *bptr = &buffer[0];
-  char *ptr  = bptr + bufsize; // compliant
-  while ( ptr >= bptr ) {
-    *ptr = 0;
-    ptr = ptr - sizeof(*ptr); // silenced
+void silenced8(void) {
+  char Buffer[BufferSize];
+
+  char *P = &Buffer[0];
+  char *Q = P;
+  while (Q >= P) {
+    *Q = 0;
+    Q = Q - sizeof(*Q);
   }
 }
-void compliant_f6(void) {
-  int buffer[bufsize];
 
-  int *bptr = &buffer[0];
-  int *ptr  = bptr + bufsize; // compliant
-  while ( ptr >= bptr ) {
-    *ptr = 0;
-    ptr = ptr - 1; // compliant
+void good8(void) {
+  char Buffer[BufferSize];
+
+  char *P = &Buffer[0];
+  char *Q = P;
+  while (Q >= P) {
+    *Q = 0;
+    Q = Q - 1;
   }
 }
 
-void compliant_f7(void) {
-  int buffer[bufsize];
+void good9(void) {
+  int Buffer[BufferSize];
 
-  int *bptr = &buffer[0];
-  int *ptr  = bptr + bufsize; // compliant
-  int i = ptr - bptr; // compliant
-  while ( i >= 0 ) {
-    ptr[i] = 0;
-    i = i - 1; // compliant
+  int *P = &Buffer[0];
+  int *Q = P + BufferSize;
+  int N = Q - P;
+  while (N >= 0) {
+    Q[N] = 0;
+    N = N - 1;
   }
 }
 
-void compliant_f8(void) {
-  int buffer[bufsize];
+void good10(void) {
+  int Buffer[BufferSize];
+
+  int *P = &Buffer[0];
+  int *Q = Buffer + BufferSize;
+  int I = sizeof(*P) - sizeof(*Q);
 
-  int *bptr = &buffer[0];
-  int *ptr  = bptr + bufsize; // compliant
-  int i = sizeof(*ptr) - sizeof(*bptr); // compliant
+  sink(&I);
 }
-void compliant_f9(void) {
-  int buffer[bufsize];
 
-  int *bptr = &buffer[0];
-  int *ptr  = bptr + bufsize; // compliant
-  int i = sizeof(ptr) - sizeof(*bptr); // compliant
+void good11(void) {
+  int Buffer[BufferSize];
+
+  int *P = &Buffer[0];
+  int *Q = Buffer + BufferSize;
+  int I = sizeof(Q) - sizeof(*P);
+
+  sink(&I);
 }

>From 91288437f6f1543f351846a09e77c48175a2d74a Mon Sep 17 00:00:00 2001
From: Whisperity <whisperity at gmail.com>
Date: Tue, 27 Aug 2024 15:24:30 +0200
Subject: [PATCH 14/22] style: [NFC] `clang-format` the check's main file

---
 ...iousPointerArithmeticsUsingSizeofCheck.cpp | 107 ++++++++++--------
 1 file changed, 59 insertions(+), 48 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
index fc9c6eac38f91f..86314d4d88b373 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
@@ -17,46 +17,56 @@ using namespace clang::ast_matchers;
 
 namespace clang::tidy::bugprone {
 
-//static const char *bin_op_bind = "ptr-sizeof-expression";	
+// static const char *bin_op_bind = "ptr-sizeof-expression";
 static constexpr llvm::StringLiteral BinOp{"bin-op"};
 static constexpr llvm::StringLiteral PointedType{"pointed-type"};
-static const auto IgnoredType = qualType(anyOf(asString("char"),asString("unsigned char"),asString("signed char"),asString("int8_t"),asString("uint8_t"),asString("std::byte"),asString("const char"),asString("const unsigned char"),asString("const signed char"),asString("const int8_t"),asString("const uint8_t"),asString("const std::byte")));
-static const auto InterestingPointer = pointerType(unless(pointee(IgnoredType)));
+static const auto IgnoredType = qualType(
+    anyOf(asString("char"), asString("unsigned char"), asString("signed char"),
+          asString("int8_t"), asString("uint8_t"), asString("std::byte"),
+          asString("const char"), asString("const unsigned char"),
+          asString("const signed char"), asString("const int8_t"),
+          asString("const uint8_t"), asString("const std::byte")));
+static const auto InterestingPointer =
+    pointerType(unless(pointee(IgnoredType)));
 
-SuspiciousPointerArithmeticsUsingSizeofCheck::SuspiciousPointerArithmeticsUsingSizeofCheck(
-    StringRef Name, ClangTidyContext *Context)
-    : ClangTidyCheck(Name, Context) {
-}
+SuspiciousPointerArithmeticsUsingSizeofCheck::
+    SuspiciousPointerArithmeticsUsingSizeofCheck(StringRef Name,
+                                                 ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context) {}
 
-void SuspiciousPointerArithmeticsUsingSizeofCheck::registerMatchers(MatchFinder *Finder) {
-    Finder->addMatcher(
-	     expr(anyOf(
-/*                    binaryOperator(hasAnyOperatorName("+","-"),
-                      hasEitherOperand(hasType(pointerType())),
-		      hasEitherOperand(sizeOfExpr(expr())),
-		      unless(allOf(hasLHS(hasType(pointerType())),
-				   hasRHS(hasType(pointerType()))))
-		      ).bind(bin_op_bind),
-		    binaryOperator(hasAnyOperatorName("+=","-="),
-	              hasLHS(hasType(pointerType())),
-		      hasRHS(sizeOfExpr(expr()))
-		      ).bind(bin_op_bind)
+void SuspiciousPointerArithmeticsUsingSizeofCheck::registerMatchers(
+    MatchFinder *Finder) {
+  Finder->addMatcher(
+      expr(anyOf(
+          /*                    binaryOperator(hasAnyOperatorName("+","-"),
+                                hasEitherOperand(hasType(pointerType())),
+                                hasEitherOperand(sizeOfExpr(expr())),
+                                unless(allOf(hasLHS(hasType(pointerType())),
+                                             hasRHS(hasType(pointerType()))))
+                                ).bind(bin_op_bind),
+                              binaryOperator(hasAnyOperatorName("+=","-="),
+                                hasLHS(hasType(pointerType())),
+                                hasRHS(sizeOfExpr(expr()))
+                                ).bind(bin_op_bind)
 
-		    binaryOperator(hasAnyOperatorName("+=","-=","+","-" ),
-	              hasLHS(hasType(InterestingPointer)),
-		      hasRHS(sizeOfExpr(expr()))).bind(BinOp),
-		    binaryOperator(hasAnyOperatorName("+","-" ),
-	              hasRHS(hasType(InterestingPointer)),
-		      hasLHS(sizeOfExpr(expr()))).bind(BinOp)
-*/		    
-		    binaryOperator(hasAnyOperatorName("+=","-=","+","-" ),
-	              hasLHS(hasType(pointerType(pointee(qualType().bind(PointedType))))),
-		      hasRHS(sizeOfExpr(expr()))).bind(BinOp),
-		    binaryOperator(hasAnyOperatorName("+","-" ),
-	              hasRHS(hasType(pointerType(pointee(qualType().bind(PointedType))))),
-		      hasLHS(sizeOfExpr(expr()))).bind(BinOp)
-            )),
-        this);
+                              binaryOperator(hasAnyOperatorName("+=","-=","+","-"
+             ), hasLHS(hasType(InterestingPointer)),
+                                hasRHS(sizeOfExpr(expr()))).bind(BinOp),
+                              binaryOperator(hasAnyOperatorName("+","-" ),
+                                hasRHS(hasType(InterestingPointer)),
+                                hasLHS(sizeOfExpr(expr()))).bind(BinOp)
+          */
+          binaryOperator(hasAnyOperatorName("+=", "-=", "+", "-"),
+                         hasLHS(hasType(pointerType(
+                             pointee(qualType().bind(PointedType))))),
+                         hasRHS(sizeOfExpr(expr())))
+              .bind(BinOp),
+          binaryOperator(hasAnyOperatorName("+", "-"),
+                         hasRHS(hasType(pointerType(
+                             pointee(qualType().bind(PointedType))))),
+                         hasLHS(sizeOfExpr(expr())))
+              .bind(BinOp))),
+      this);
 }
 
 static CharUnits getSizeOfType(const ASTContext &Ctx, const Type *Ty) {
@@ -66,20 +76,21 @@ static CharUnits getSizeOfType(const ASTContext &Ctx, const Type *Ty) {
   return Ctx.getTypeSizeInChars(Ty);
 }
 
-void SuspiciousPointerArithmeticsUsingSizeofCheck::check(const MatchFinder::MatchResult &Result) {
-    const ASTContext &Ctx = *Result.Context;
-    const auto *Matched = Result.Nodes.getNodeAs<BinaryOperator>(BinOp);
-    const auto *SuspiciousQualTypePtr =
-        Result.Nodes.getNodeAs<QualType>(PointedType);
-    const auto *SuspiciousTypePtr = SuspiciousQualTypePtr->getTypePtr();
+void SuspiciousPointerArithmeticsUsingSizeofCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  const ASTContext &Ctx = *Result.Context;
+  const auto *Matched = Result.Nodes.getNodeAs<BinaryOperator>(BinOp);
+  const auto *SuspiciousQualTypePtr =
+      Result.Nodes.getNodeAs<QualType>(PointedType);
+  const auto *SuspiciousTypePtr = SuspiciousQualTypePtr->getTypePtr();
 
-    std::size_t sz = getSizeOfType(Ctx,SuspiciousTypePtr).getQuantity();
-    if ( sz > 1 )
-    {
-        diag(Matched->getExprLoc(),"Suspicious pointer arithmetics using sizeof() operator: sizeof(%0) is %1") << SuspiciousQualTypePtr->getAsString(Ctx.getPrintingPolicy())
-	                       << sz
-		               << Matched->getSourceRange();
-    }
+  std::size_t sz = getSizeOfType(Ctx, SuspiciousTypePtr).getQuantity();
+  if (sz > 1) {
+    diag(Matched->getExprLoc(), "Suspicious pointer arithmetics using sizeof() "
+                                "operator: sizeof(%0) is %1")
+        << SuspiciousQualTypePtr->getAsString(Ctx.getPrintingPolicy()) << sz
+        << Matched->getSourceRange();
+  }
 }
 
 } // namespace clang::tidy::bugprone

>From 7ece46236db82af80dc871f3824dac74d90f0f80 Mon Sep 17 00:00:00 2001
From: Whisperity <whisperity at gmail.com>
Date: Tue, 27 Aug 2024 15:42:18 +0200
Subject: [PATCH 15/22] wip: Refurbish the checker, improve code quality

---
 ...iousPointerArithmeticsUsingSizeofCheck.cpp | 96 ++++++++-----------
 ...ous-pointer-arithmetics-using-sizeof-c11.c | 22 +++++
 ...picious-pointer-arithmetics-using-sizeof.c | 12 +--
 3 files changed, 70 insertions(+), 60 deletions(-)
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof-c11.c

diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
index 86314d4d88b373..352d3e1ddb60c0 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
@@ -8,7 +8,6 @@
 
 #include "SuspiciousPointerArithmeticsUsingSizeofCheck.h"
 #include "../utils/Matchers.h"
-#include "../utils/OptionsUtils.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Lex/Lexer.h"
@@ -17,17 +16,30 @@ using namespace clang::ast_matchers;
 
 namespace clang::tidy::bugprone {
 
-// static const char *bin_op_bind = "ptr-sizeof-expression";
-static constexpr llvm::StringLiteral BinOp{"bin-op"};
-static constexpr llvm::StringLiteral PointedType{"pointed-type"};
-static const auto IgnoredType = qualType(
+namespace {
+
+constexpr llvm::StringLiteral BinOp{"bin-op"};
+constexpr llvm::StringLiteral PointedType{"pointed-type"};
+constexpr llvm::StringLiteral ScaleExpr{"scale-expr"};
+
+const auto IgnoredTypes = qualType(
     anyOf(asString("char"), asString("unsigned char"), asString("signed char"),
           asString("int8_t"), asString("uint8_t"), asString("std::byte"),
           asString("const char"), asString("const unsigned char"),
           asString("const signed char"), asString("const int8_t"),
           asString("const uint8_t"), asString("const std::byte")));
-static const auto InterestingPointer =
-    pointerType(unless(pointee(IgnoredType)));
+const auto InterestingPointer = pointerType(unless(pointee(IgnoredTypes)));
+
+const auto ScaledIntegerTraitExprs = /*stmt(anyOf(*/ sizeOfExpr(expr()) /*))*/;
+
+CharUnits getSizeOfType(const ASTContext &Ctx, const Type *Ty) {
+  if (!Ty || Ty->isIncompleteType() || Ty->isDependentType() ||
+      isa<DependentSizedArrayType>(Ty) || !Ty->isConstantSizeType())
+    return CharUnits::Zero();
+  return Ctx.getTypeSizeInChars(Ty);
+}
+
+} // namespace
 
 SuspiciousPointerArithmeticsUsingSizeofCheck::
     SuspiciousPointerArithmeticsUsingSizeofCheck(StringRef Name,
@@ -37,60 +49,36 @@ SuspiciousPointerArithmeticsUsingSizeofCheck::
 void SuspiciousPointerArithmeticsUsingSizeofCheck::registerMatchers(
     MatchFinder *Finder) {
   Finder->addMatcher(
-      expr(anyOf(
-          /*                    binaryOperator(hasAnyOperatorName("+","-"),
-                                hasEitherOperand(hasType(pointerType())),
-                                hasEitherOperand(sizeOfExpr(expr())),
-                                unless(allOf(hasLHS(hasType(pointerType())),
-                                             hasRHS(hasType(pointerType()))))
-                                ).bind(bin_op_bind),
-                              binaryOperator(hasAnyOperatorName("+=","-="),
-                                hasLHS(hasType(pointerType())),
-                                hasRHS(sizeOfExpr(expr()))
-                                ).bind(bin_op_bind)
-
-                              binaryOperator(hasAnyOperatorName("+=","-=","+","-"
-             ), hasLHS(hasType(InterestingPointer)),
-                                hasRHS(sizeOfExpr(expr()))).bind(BinOp),
-                              binaryOperator(hasAnyOperatorName("+","-" ),
-                                hasRHS(hasType(InterestingPointer)),
-                                hasLHS(sizeOfExpr(expr()))).bind(BinOp)
-          */
-          binaryOperator(hasAnyOperatorName("+=", "-=", "+", "-"),
-                         hasLHS(hasType(pointerType(
-                             pointee(qualType().bind(PointedType))))),
-                         hasRHS(sizeOfExpr(expr())))
-              .bind(BinOp),
-          binaryOperator(hasAnyOperatorName("+", "-"),
-                         hasRHS(hasType(pointerType(
-                             pointee(qualType().bind(PointedType))))),
-                         hasLHS(sizeOfExpr(expr())))
-              .bind(BinOp))),
+      expr(anyOf(binaryOperator(hasAnyOperatorName("+", "+=", "-", "-="),
+                                hasLHS(hasType(pointerType(
+                                    pointee(qualType().bind(PointedType))))),
+                                hasRHS(ScaledIntegerTraitExprs.bind(ScaleExpr)))
+                     .bind(BinOp),
+                 binaryOperator(hasAnyOperatorName("+", "-"),
+                                hasRHS(hasType(pointerType(
+                                    pointee(qualType().bind(PointedType))))),
+                                hasLHS(ScaledIntegerTraitExprs.bind(ScaleExpr)))
+                     .bind(BinOp))),
       this);
 }
 
-static CharUnits getSizeOfType(const ASTContext &Ctx, const Type *Ty) {
-  if (!Ty || Ty->isIncompleteType() || Ty->isDependentType() ||
-      isa<DependentSizedArrayType>(Ty) || !Ty->isConstantSizeType())
-    return CharUnits::Zero();
-  return Ctx.getTypeSizeInChars(Ty);
-}
-
 void SuspiciousPointerArithmeticsUsingSizeofCheck::check(
     const MatchFinder::MatchResult &Result) {
   const ASTContext &Ctx = *Result.Context;
-  const auto *Matched = Result.Nodes.getNodeAs<BinaryOperator>(BinOp);
-  const auto *SuspiciousQualTypePtr =
-      Result.Nodes.getNodeAs<QualType>(PointedType);
-  const auto *SuspiciousTypePtr = SuspiciousQualTypePtr->getTypePtr();
+  const auto *BO = Result.Nodes.getNodeAs<BinaryOperator>(BinOp);
+  const auto *QT = Result.Nodes.getNodeAs<QualType>(PointedType);
+  assert(BO && QT && "Broken matchers encountered.");
+
+  const auto Size = getSizeOfType(Ctx, QT->getTypePtr()).getQuantity();
+  if (Size == 1)
+    return;
 
-  std::size_t sz = getSizeOfType(Ctx, SuspiciousTypePtr).getQuantity();
-  if (sz > 1) {
-    diag(Matched->getExprLoc(), "Suspicious pointer arithmetics using sizeof() "
-                                "operator: sizeof(%0) is %1")
-        << SuspiciousQualTypePtr->getAsString(Ctx.getPrintingPolicy()) << sz
-        << Matched->getSourceRange();
-  }
+  diag(BO->getExprLoc(),
+       "pointer arithmetic using a number scaled by '%0'; this value will be "
+       "scaled again by the '%1' operator")
+      << "sizeof" << BO->getOpcodeStr();
+  diag(BO->getExprLoc(), "'%0' scales with '%1(%2)' == %3", DiagnosticIDs::Note)
+      << BO->getOpcodeStr() << "sizeof" << "?" << Size;
 }
 
 } // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof-c11.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof-c11.c
new file mode 100644
index 00000000000000..f00cb11b217caf
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof-c11.c
@@ -0,0 +1,22 @@
+// RUN: %check_clang_tidy --std=c11-or-later %s bugprone-suspicious-pointer-arithmetics-using-sizeof %t
+
+#define alignof(type_name) _Alignof(type_name)
+extern void sink(const void *P);
+
+enum { BufferSize = 1024 };
+
+struct S {
+  long A, B, C;
+};
+
+void bad4d(void) {
+  struct S Buffer[BufferSize];
+
+  struct S *P = &Buffer[0];
+  struct S *Q = P;
+  while (Q < P + alignof(Buffer)) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: pointer arithmetic using a number scaled by 'alignof()'; this value will be scaled again by the '+' operator
+    // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' scales with 'sizeof(struct S)' == {{[0-9]+}}
+    sink(Q++);
+  }
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c
index 8f2046ebdfa585..840eaf38b18f19 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c
@@ -117,8 +117,8 @@ void bad4(void) {
   while (Q < P + BufferSize) {
     *Q = 0;
     Q += sizeof(*Q);
-    // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic using a number scaled by 'sizeof()'; this value will be scaled again by the '+' operator
-    // CHECK-MESSAGES: :[[@LINE-2]]:7: note: '+' scales with 'sizeof(int)' == {{[0-9]+}}
+    // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic using a number scaled by 'sizeof()'; this value will be scaled again by the '+=' operator
+    // CHECK-MESSAGES: :[[@LINE-2]]:7: note: '+=' scales with 'sizeof(int)' == {{[0-9]+}}
   }
 }
 
@@ -151,7 +151,7 @@ void good5aa(void) {
   int *Q = P;
   while (Q < P + BufferSize) {
     *Q = 0;
-    Q += ( sizeof(Buffer)/ sizeof(Buffer[0]) );
+    Q += ( sizeof(Buffer) / sizeof(Buffer[0]) );
   }
 }
 
@@ -162,7 +162,7 @@ void good5ab(void) {
   int *Q = P;
   while (Q < P + BufferSize) {
     *Q = 0;
-    Q = Q + ( sizeof(Buffer)/ sizeof(Buffer[0]) );
+    Q = Q + ( sizeof(Buffer) / sizeof(Buffer[0]) );
   }
 }
 
@@ -173,7 +173,7 @@ void good5ba(void) {
   int *Q = P;
   while (Q < P + BufferSize) {
     *Q = 0;
-    Q -= ( sizeof(Buffer)/ sizeof(Buffer[0]) );
+    Q -= ( sizeof(Buffer) / sizeof(Buffer[0]) );
   }
 }
 
@@ -184,7 +184,7 @@ void good5bb(void) {
   int *Q = P;
   while (Q < P + BufferSize) {
     *Q = 0;
-    Q = Q - ( sizeof(Buffer)/ sizeof(Buffer[0]) );
+    Q = Q - ( sizeof(Buffer) / sizeof(Buffer[0]) );
   }
 }
 

>From cfe5be1229282e28f5de814557302f3b37e57267 Mon Sep 17 00:00:00 2001
From: Whisperity <whisperity at gmail.com>
Date: Tue, 27 Aug 2024 16:19:04 +0200
Subject: [PATCH 16/22] feat: Match `alignof()` and `offsetof()` as well

---
 ...iousPointerArithmeticsUsingSizeofCheck.cpp | 40 +++++++++++++++----
 ...iciousPointerArithmeticsUsingSizeofCheck.h |  2 +-
 clang-tools-extra/docs/ReleaseNotes.rst       |  2 +-
 ...cious-pointer-arithmetics-using-sizeof.rst |  4 +-
 ...ous-pointer-arithmetics-using-sizeof-c11.c |  4 +-
 ...picious-pointer-arithmetics-using-sizeof.c | 24 +++++------
 6 files changed, 50 insertions(+), 26 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
index 352d3e1ddb60c0..7a77bec319559b 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
@@ -30,7 +30,11 @@ const auto IgnoredTypes = qualType(
           asString("const uint8_t"), asString("const std::byte")));
 const auto InterestingPointer = pointerType(unless(pointee(IgnoredTypes)));
 
-const auto ScaledIntegerTraitExprs = /*stmt(anyOf(*/ sizeOfExpr(expr()) /*))*/;
+AST_MATCHER(Expr, offsetOfExpr) { return isa<OffsetOfExpr>(Node); }
+
+const auto ScaledIntegerTraitExprs =
+    expr(anyOf(unaryExprOrTypeTraitExpr(ofKind(UETT_SizeOf)),
+               unaryExprOrTypeTraitExpr(ofKind(UETT_AlignOf)), offsetOfExpr()));
 
 CharUnits getSizeOfType(const ASTContext &Ctx, const Type *Ty) {
   if (!Ty || Ty->isIncompleteType() || Ty->isDependentType() ||
@@ -67,18 +71,38 @@ void SuspiciousPointerArithmeticsUsingSizeofCheck::check(
   const ASTContext &Ctx = *Result.Context;
   const auto *BO = Result.Nodes.getNodeAs<BinaryOperator>(BinOp);
   const auto *QT = Result.Nodes.getNodeAs<QualType>(PointedType);
-  assert(BO && QT && "Broken matchers encountered.");
+  const auto *ScaleE = Result.Nodes.getNodeAs<Expr>(ScaleExpr);
+  assert(BO && QT && ScaleE && "Broken matchers encountered.");
 
   const auto Size = getSizeOfType(Ctx, QT->getTypePtr()).getQuantity();
   if (Size == 1)
     return;
 
-  diag(BO->getExprLoc(),
-       "pointer arithmetic using a number scaled by '%0'; this value will be "
-       "scaled again by the '%1' operator")
-      << "sizeof" << BO->getOpcodeStr();
-  diag(BO->getExprLoc(), "'%0' scales with '%1(%2)' == %3", DiagnosticIDs::Note)
-      << BO->getOpcodeStr() << "sizeof" << "?" << Size;
+  const int KindSelect = [ScaleE]() {
+    if (const auto *UTTE = dyn_cast<UnaryExprOrTypeTraitExpr>(ScaleE))
+      switch (UTTE->getKind()) {
+      case UETT_SizeOf:
+        return 0;
+      case UETT_AlignOf:
+        return 1;
+      default:
+        return -1;
+      }
+
+    if (isa<OffsetOfExpr>(ScaleE))
+      return 2;
+
+    return -1;
+  }();
+  assert(KindSelect != -1 && "Unhandled scale-expr kind!");
+
+  diag(BO->getExprLoc(), "pointer arithmetic using a number scaled by "
+                         "'%select{sizeof|alignof|offsetof}0'; this value will "
+                         "be scaled again by the '%1' operator")
+      << KindSelect << BO->getOpcodeStr() << ScaleE->getSourceRange();
+  diag(BO->getExprLoc(), "'%0' scales with 'sizeof(%1)' == %2",
+       DiagnosticIDs::Note)
+      << BO->getOpcodeStr() << QT->getAsString(Ctx.getPrintingPolicy()) << Size;
 }
 
 } // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.h b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.h
index 1dbc51dd3df84f..bfafd1a1296423 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.h
@@ -14,7 +14,7 @@
 namespace clang::tidy::bugprone {
 
 /// Finds suspicious pointer arithmetic calculations where the pointer is
-/// offset by a sizeof() expression.
+/// offset by an alignof(), offsetof(), or sizeof() expression.
 ///
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof.html
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index ba2ffb6f8970ff..c87781b1f2caa3 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -101,7 +101,7 @@ New checks
 - New :doc:`bugprone-suspicious-pointer-arithmetics-using-sizeof
   <clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof>`
   check that finds suspicious pointer arithmetic calculations where the pointer
-  is offset by a ``sizeof()`` expression.
+  is offset by an ``alignof()``, ``offsetof()``, or ``sizeof()`` expression.
 
 New check aliases
 ^^^^^^^^^^^^^^^^^
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof.rst
index 5188f947627ab0..a00eaf6ac84353 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof.rst
@@ -3,10 +3,10 @@
 bugprone-suspicious-pointer-arithmetics-using-sizeof
 ====================================================
 
-Finds suspicious pointer arithmetic calculations where the pointer is offset by a ``sizeof()`` expression.
+Finds suspicious pointer arithmetic calculations where the pointer is offset by an ``alignof()``, ``offsetof()``, or ``sizeof()`` expression.
 
 Pointer arithmetic expressions implicitly scale the offset added to or subtracted from the address by the size of the pointee type.
-Scaling the offset expression manually effectively results in a squared offset, which creates an invalid pointer that points beyond the end of the intended array.
+Using an offset expression that is already scaled by the size of the underlying type effectively results in a squared offset, which is likely an invalid pointer that points beyond the end of the intended array.
 
 .. code-block:: c++
 
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof-c11.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof-c11.c
index f00cb11b217caf..33bf69bdea1185 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof-c11.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof-c11.c
@@ -1,4 +1,4 @@
-// RUN: %check_clang_tidy --std=c11-or-later %s bugprone-suspicious-pointer-arithmetics-using-sizeof %t
+// RUN: %check_clang_tidy -std=c11-or-later %s bugprone-suspicious-pointer-arithmetics-using-sizeof %t
 
 #define alignof(type_name) _Alignof(type_name)
 extern void sink(const void *P);
@@ -15,7 +15,7 @@ void bad4d(void) {
   struct S *P = &Buffer[0];
   struct S *Q = P;
   while (Q < P + alignof(Buffer)) {
-    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: pointer arithmetic using a number scaled by 'alignof()'; this value will be scaled again by the '+' operator
+    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: pointer arithmetic using a number scaled by 'alignof'; this value will be scaled again by the '+' operator
     // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' scales with 'sizeof(struct S)' == {{[0-9]+}}
     sink(Q++);
   }
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c
index 840eaf38b18f19..5a834b85565d49 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c
@@ -13,8 +13,8 @@ void bad1a(void) {
   int *P = &Buffer[0];
   int *Q = P;
   while (Q < P + sizeof(Buffer)) {
-    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: pointer arithmetic using a number scaled by 'sizeof()'; this distance will be scaled again by the '+' operator [bugprone-suspicious-pointer-arithemetics-using-sizeof]
-    // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' scales with 'sizeof(Buffer)' == {{[0-9]+}}
+    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: pointer arithmetic using a number scaled by 'sizeof'; this value will be scaled again by the '+' operator [bugprone-suspicious-pointer-arithmetics-using-sizeof]
+    // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' scales with 'sizeof(int)' == {{[0-9]+}}
     *Q++ = 0;
   }
 }
@@ -26,8 +26,8 @@ void bad1b(void) {
   Integer *P = &Buffer[0];
   Integer *Q = P;
   while (Q < P + sizeof(Buffer)) {
-    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: pointer arithmetic using a number scaled by 'sizeof()'; this distance will be scaled again by the '+' operator
-    // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' scales with 'sizeof(Buffer)' == {{[0-9]+}}
+    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: pointer arithmetic using a number scaled by 'sizeof'; this value will be scaled again by the '+' operator
+    // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' scales with 'sizeof(Integer)' == {{[0-9]+}}
     *Q++ = 0;
   }
 }
@@ -47,8 +47,8 @@ void bad2(void) {
   int *P = Buffer;
 
   while (P < Buffer + sizeof(Buffer)) {
-    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: pointer arithmetic using a number scaled by 'sizeof()'; this value will be scaled again by the '+' operator
-    // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' scales with 'sizeof(int)' == {{[0-9]+}}
+    // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: pointer arithmetic using a number scaled by 'sizeof'; this value will be scaled again by the '+' operator
+    // CHECK-MESSAGES: :[[@LINE-2]]:21: note: '+' scales with 'sizeof(int)' == {{[0-9]+}}
     *P++ = 0;
   }
 }
@@ -87,8 +87,8 @@ void good3a(struct S *S) {
 void bad3b(struct S *S) {
   memset(S + offsetof(struct S, B), 0,
          sizeof(struct S) - offsetof(struct S, B));
-  // NCHECK-MESSAGES: :[[@LINE-1]]:12: warning: pointer arithmetic using a number scaled by 'offsetof()'; this value will be scaled again by the '+' operator
-  // NCHECK-MESSAGES: :[[@LINE-2]]:12: note: '+' scales with 'sizeof(int)' == {{[0-9]+}}
+  // CHECK-MESSAGES: :[[@LINE-2]]:12: warning: pointer arithmetic using a number scaled by 'offsetof'; this value will be scaled again by the '+' operator
+  // CHECK-MESSAGES: :[[@LINE-3]]:12: note: '+' scales with 'sizeof(struct S)' == {{[0-9]+}}
 }
 
 void good3b(struct S *S) {
@@ -103,7 +103,7 @@ void bad3c(void) {
   struct S *P = &Buffer[0];
   struct S *Q = P;
   while (Q < P + sizeof(Buffer)) {
-    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: pointer arithmetic using a number scaled by 'sizeof()'; this value will be scaled again by the '+' operator
+    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: pointer arithmetic using a number scaled by 'sizeof'; this value will be scaled again by the '+' operator
     // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' scales with 'sizeof(struct S)' == {{[0-9]+}}
     sink(Q++);
   }
@@ -117,7 +117,7 @@ void bad4(void) {
   while (Q < P + BufferSize) {
     *Q = 0;
     Q += sizeof(*Q);
-    // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic using a number scaled by 'sizeof()'; this value will be scaled again by the '+=' operator
+    // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic using a number scaled by 'sizeof'; this value will be scaled again by the '+=' operator
     // CHECK-MESSAGES: :[[@LINE-2]]:7: note: '+=' scales with 'sizeof(int)' == {{[0-9]+}}
   }
 }
@@ -196,7 +196,7 @@ void bad6(void) {
   while (Q < P + BufferSize) {
     *Q = 0;
     Q = Q + sizeof(*Q);
-    // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: pointer arithmetic using a number scaled by 'sizeof()'; this value will be scaled again by the '+' operator
+    // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: pointer arithmetic using a number scaled by 'sizeof'; this value will be scaled again by the '+' operator
     // CHECK-MESSAGES: :[[@LINE-2]]:11: note: '+' scales with 'sizeof(int)' == {{[0-9]+}}
   }
 }
@@ -253,7 +253,7 @@ void bad8(void) {
   while (Q >= P) {
     *Q = 0;
     Q = Q - sizeof(*Q);
-    // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: pointer arithmetic using a number scaled by 'sizeof()'; this value will be scaled again by the '-' operator
+    // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: pointer arithmetic using a number scaled by 'sizeof'; this value will be scaled again by the '-' operator
     // CHECK-MESSAGES: :[[@LINE-2]]:11: note: '-' scales with 'sizeof(int)' == {{[0-9]+}}
   }
 }

>From 0bad4f8f85ac3aac073f04c1bb66e8c305317c5e Mon Sep 17 00:00:00 2001
From: Whisperity <whisperity at gmail.com>
Date: Tue, 27 Aug 2024 16:26:10 +0200
Subject: [PATCH 17/22] style: `clang-format`

---
 clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
index 39ba55142da4bc..ce5c2a119f4528 100644
--- a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
@@ -284,8 +284,8 @@ class CERTModule : public ClangTidyModule {
     // C checkers
     // ARR
     CheckFactories
-      .registerCheck<bugprone::SuspiciousPointerArithmeticsUsingSizeofCheck>(
-        "cert-arr39-c");
+        .registerCheck<bugprone::SuspiciousPointerArithmeticsUsingSizeofCheck>(
+            "cert-arr39-c");
     // CON
     CheckFactories.registerCheck<bugprone::SpuriouslyWakeUpFunctionsCheck>(
         "cert-con36-c");

>From 69449326575b2725de54990744c80cc6ca49dfef Mon Sep 17 00:00:00 2001
From: Whisperity <whisperity at gmail.com>
Date: Tue, 27 Aug 2024 16:26:51 +0200
Subject: [PATCH 18/22] style: `clang-format`

---
 .../bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.h     | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.h b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.h
index bfafd1a1296423..fdce44a7a24394 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.h
@@ -1,4 +1,4 @@
-//===--- SuspiciousPointerArithmeticsUsingSizeofCheck.h - clang-tidy -*- C++ -*-===//
+//===--- SuspiciousPointerArithmeticsUsingSizeofCheck.h -------*- C++ -*---===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.

>From 067b855c10a6cfd1409c276f9fa1acc58a0ada01 Mon Sep 17 00:00:00 2001
From: Whisperity <whisperity at gmail.com>
Date: Tue, 27 Aug 2024 16:29:47 +0200
Subject: [PATCH 19/22] style: Reformat RST changes

---
 clang-tools-extra/docs/ReleaseNotes.rst        |  6 ++++--
 ...icious-pointer-arithmetics-using-sizeof.rst | 18 ++++++++++++------
 2 files changed, 16 insertions(+), 8 deletions(-)

diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index d25339f4a03165..039a7af8d0f03a 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -100,8 +100,10 @@ New checks
 
 - New :doc:`bugprone-suspicious-pointer-arithmetics-using-sizeof
   <clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof>`
-  check that finds suspicious pointer arithmetic calculations where the pointer
-  is offset by an ``alignof()``, ``offsetof()``, or ``sizeof()`` expression.
+  check.
+
+  Finds suspicious pointer arithmetic calculations where the pointer is offset
+  by an ``alignof()``, ``offsetof()``, or ``sizeof()`` expression.
 
 New check aliases
 ^^^^^^^^^^^^^^^^^
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof.rst
index a00eaf6ac84353..805e489d06e881 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof.rst
@@ -3,12 +3,16 @@
 bugprone-suspicious-pointer-arithmetics-using-sizeof
 ====================================================
 
-Finds suspicious pointer arithmetic calculations where the pointer is offset by an ``alignof()``, ``offsetof()``, or ``sizeof()`` expression.
+Finds suspicious pointer arithmetic calculations where the pointer is offset by
+an ``alignof()``, ``offsetof()``, or ``sizeof()`` expression.
 
-Pointer arithmetic expressions implicitly scale the offset added to or subtracted from the address by the size of the pointee type.
-Using an offset expression that is already scaled by the size of the underlying type effectively results in a squared offset, which is likely an invalid pointer that points beyond the end of the intended array.
+Pointer arithmetic expressions implicitly scale the offset added to or
+subtracted from the address by the size of the pointee type.
+Using an offset expression that is already scaled by the size of the underlying
+type effectively results in a squared offset, which is likely an invalid
+pointer that points beyond the end of the intended array.
 
-.. code-block:: c++
+.. code-block:: c
 
   void printEveryEvenIndexElement(int *Array, size_t N) {
     int *P = Array;
@@ -21,7 +25,7 @@ Using an offset expression that is already scaled by the size of the underlying
 
 The above example should be in the following, correct form:
 
-.. code-block:: c++
+.. code-block:: c
 
   void printEveryEvenIndexElement(int *Array, size_t N) {
     int *P = Array;
@@ -41,4 +45,6 @@ This check corresponds to the CERT C Coding Standard rule
 Limitations
 -----------
 
-While incorrect from a technically rigorous point of view, the check does not warn for pointer arithmetics where the pointee type is ``char`` (``sizeof(char) == 1``, by definition) on purpose.
+While incorrect from a technically rigorous point of view, the check does not
+warn for pointer arithmetics where the pointee type is ``char``
+(``sizeof(char) == 1``, by definition) on purpose.

>From dc50cad028fbfbda73328e8475afd5e9ef24d9f0 Mon Sep 17 00:00:00 2001
From: Whisperity <whisperity at gmail.com>
Date: Tue, 27 Aug 2024 17:02:31 +0200
Subject: [PATCH 20/22] test: Add a test for the "runtime offset number *
 sizeof()" case

---
 ...picious-pointer-arithmetics-using-sizeof.c | 28 ++++++++++++++++++-
 1 file changed, 27 insertions(+), 1 deletion(-)

diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c
index 5a834b85565d49..d7b647661ac78e 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c
@@ -2,8 +2,14 @@
 
 typedef __typeof__(sizeof(void*)) size_t;
 #define offsetof(type, member) __builtin_offsetof(type, member)
-extern void *memset(void *Dst, int Ch, size_t Count);
+extern void *memset(void *Dest, int Ch, size_t Count);
 extern void sink(const void *P);
+extern size_t strlen(const char *Str);
+extern size_t wcslen(const wchar_t *Str);
+extern char *strcpy(char *Dest, const char *Src);
+extern wchar_t *wcscpy(wchar_t *Dest, const wchar_t *Src);
+extern int scanf(const char *Format, ...);
+extern int wscanf(const wchar_t *Format, ...);
 
 enum { BufferSize = 1024 };
 
@@ -311,3 +317,23 @@ void good11(void) {
 
   sink(&I);
 }
+
+void bad12(void) {
+  wchar_t Message[BufferSize];
+  wcscpy(Message, L"Message: ");
+  wscanf(L"%s", Message + wcslen(Message) * sizeof(wchar_t));
+  // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: pointer arithmetic using a number scaled by 'sizeof'; this value will be scaled again by the '+' operator
+  // CHECK-MESSAGES: :[[@LINE-2]]:15: note: '+' scales with 'sizeof(wchar_t)' == {{[0-9]+}}
+}
+
+void silenced12(void) {
+  char Message[BufferSize];
+  strcpy(Message, "Message: ");
+  scanf("%s", Message + strlen(Message) * sizeof(char));
+}
+
+void good12(void) {
+  wchar_t Message[BufferSize];
+  wcscpy(Message, L"Message: ");
+  wscanf(L"%s", Message + wcslen(Message));
+}

>From a745f0d1b0cbc0ae19db1230c91854076aec19ed Mon Sep 17 00:00:00 2001
From: Whisperity <whisperity at gmail.com>
Date: Wed, 28 Aug 2024 11:37:26 +0200
Subject: [PATCH 21/22] feat: Match `P + N * sizeof()`, move implementation to
 `bugprone-sizeof-expression`

---
 .../bugprone/BugproneTidyModule.cpp           |   3 -
 .../clang-tidy/bugprone/CMakeLists.txt        |   1 -
 .../bugprone/SizeofExpressionCheck.cpp        |  88 +++++++++++++-
 .../bugprone/SizeofExpressionCheck.h          |   2 +-
 ...iousPointerArithmeticsUsingSizeofCheck.cpp | 108 ------------------
 ...iciousPointerArithmeticsUsingSizeofCheck.h |  31 -----
 .../clang-tidy/cert/CERTTidyModule.cpp        |  13 ++-
 ...izeof-expression-pointer-arithmetics-c11.c |  22 ++++
 ...> sizeof-expression-pointer-arithmetics.c} |  49 ++++----
 ...eof-expression-2.c => sizeof-expression.c} |   0
 ...ous-pointer-arithmetics-using-sizeof-c11.c |  22 ----
 11 files changed, 147 insertions(+), 192 deletions(-)
 delete mode 100644 clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
 delete mode 100644 clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.h
 create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression-pointer-arithmetics-c11.c
 rename clang-tools-extra/test/clang-tidy/checkers/bugprone/{suspicious-pointer-arithmetics-using-sizeof.c => sizeof-expression-pointer-arithmetics.c} (65%)
 rename clang-tools-extra/test/clang-tidy/checkers/bugprone/{sizeof-expression-2.c => sizeof-expression.c} (100%)
 delete mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof-c11.c

diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 39c43ce011881d..689eb92a3d8d17 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -72,7 +72,6 @@
 #include "SuspiciousMemoryComparisonCheck.h"
 #include "SuspiciousMemsetUsageCheck.h"
 #include "SuspiciousMissingCommaCheck.h"
-#include "SuspiciousPointerArithmeticsUsingSizeofCheck.h"
 #include "SuspiciousReallocUsageCheck.h"
 #include "SuspiciousSemicolonCheck.h"
 #include "SuspiciousStringCompareCheck.h"
@@ -220,8 +219,6 @@ class BugproneModule : public ClangTidyModule {
         "bugprone-suspicious-memset-usage");
     CheckFactories.registerCheck<SuspiciousMissingCommaCheck>(
         "bugprone-suspicious-missing-comma");
-    CheckFactories.registerCheck<SuspiciousPointerArithmeticsUsingSizeofCheck>(
-        "bugprone-suspicious-pointer-arithmetics-using-sizeof");
     CheckFactories.registerCheck<SuspiciousReallocUsageCheck>(
         "bugprone-suspicious-realloc-usage");
     CheckFactories.registerCheck<SuspiciousSemicolonCheck>(
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index 25574eb83863c4..cb0d8ae98bac58 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -69,7 +69,6 @@ add_clang_library(clangTidyBugproneModule
   SuspiciousMemoryComparisonCheck.cpp
   SuspiciousMemsetUsageCheck.cpp
   SuspiciousMissingCommaCheck.cpp
-  SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
   SuspiciousReallocUsageCheck.cpp
   SuspiciousSemicolonCheck.cpp
   SuspiciousStringCompareCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp
index d517e8473d94ae..143cf6b0ca72b7 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp
@@ -48,6 +48,8 @@ AST_MATCHER_P2(Expr, hasSizeOfDescendant, int, Depth,
   return false;
 }
 
+AST_MATCHER(Expr, offsetOfExpr) { return isa<OffsetOfExpr>(Node); }
+
 CharUnits getSizeOfType(const ASTContext &Ctx, const Type *Ty) {
   if (!Ty || Ty->isIncompleteType() || Ty->isDependentType() ||
       isa<DependentSizedArrayType>(Ty) || !Ty->isConstantSizeType())
@@ -257,8 +259,9 @@ void SizeofExpressionCheck::registerMatchers(MatchFinder *Finder) {
                          .bind("sizeof-sizeof-expr"),
                      this);
 
-  // Detect sizeof in pointer arithmetic like: N * sizeof(S) == P1 - P2 or
-  // (P1 - P2) / sizeof(S) where P1 and P2 are pointers to type S.
+  // Detect sizeof usage in comparisons involving pointer arithmetics, such as
+  // N * sizeof(S) == P1 - P2 or (P1 - P2) / sizeof(S), where P1 and P2 are
+  // pointers to a type S.
   const auto PtrDiffExpr = binaryOperator(
       hasOperatorName("-"),
       hasLHS(hasType(hasUnqualifiedDesugaredType(pointerType(pointee(
@@ -285,6 +288,50 @@ void SizeofExpressionCheck::registerMatchers(MatchFinder *Finder) {
           hasRHS(ignoringParenImpCasts(SizeOfExpr.bind("sizeof-ptr-div-expr"))))
           .bind("sizeof-in-ptr-arithmetic-div"),
       this);
+
+  // SEI CERT ARR39-C. Do not add or subtract a scaled integer to a pointer.
+  // Detect sizeof, alignof and offsetof usage in pointer arithmetics where
+  // they are used to scale the numeric distance, which is scaled again by
+  // the pointer arithmetic operator. This can result in forming invalid
+  // offsets.
+  //
+  // Examples, where P is a pointer, N is some integer (both compile-time and
+  // run-time): P + sizeof(T), P + sizeof(*P), P + N * sizeof(*P).
+  //
+  // This check does not warn on cases where the pointee type is "1 byte",
+  // as those cases can often come from generics and also do not constitute a
+  // problem because the size does not affect the scale used.
+  const auto PtrArithmeticIgnoredPointeeTypes = qualType(anyOf(
+      asString("char"), asString("unsigned char"), asString("signed char"),
+      asString("int8_t"), asString("uint8_t"), asString("std::byte"),
+      asString("const char"), asString("const unsigned char"),
+      asString("const signed char"), asString("const int8_t"),
+      asString("const uint8_t"), asString("const std::byte")));
+  const auto InterestingPtrTyForPtrArithmetic = pointerType(pointee(
+      qualType(unless(PtrArithmeticIgnoredPointeeTypes)).bind("pointee-type")));
+  const auto SizeofLikeScaleExpr =
+      expr(anyOf(unaryExprOrTypeTraitExpr(ofKind(UETT_SizeOf)),
+                 unaryExprOrTypeTraitExpr(ofKind(UETT_AlignOf)),
+                 offsetOfExpr()))
+          .bind("sizeof-in-ptr-arithmetic-scale-expr");
+  const auto PtrArithmeticIntegerScaleExpr = binaryOperator(
+      hasAnyOperatorName("*", "/"), hasEitherOperand(hasType(isInteger())),
+      hasEitherOperand(SizeofLikeScaleExpr));
+  const auto PtrArithmeticScaledIntegerExpr =
+      expr(anyOf(SizeofLikeScaleExpr, PtrArithmeticIntegerScaleExpr));
+
+  Finder->addMatcher(
+      expr(anyOf(
+          binaryOperator(
+              hasAnyOperatorName("+", "-"),
+              hasEitherOperand(hasType(InterestingPtrTyForPtrArithmetic)),
+              hasEitherOperand(PtrArithmeticScaledIntegerExpr))
+              .bind("sizeof-in-ptr-arithmetic-plusminus"),
+          binaryOperator(hasAnyOperatorName("+=", "-="),
+                         hasLHS(hasType(InterestingPtrTyForPtrArithmetic)),
+                         hasRHS(PtrArithmeticScaledIntegerExpr))
+              .bind("sizeof-in-ptr-arithmetic-plusminus"))),
+      this);
 }
 
 void SizeofExpressionCheck::check(const MatchFinder::MatchResult &Result) {
@@ -409,6 +456,43 @@ void SizeofExpressionCheck::check(const MatchFinder::MatchResult &Result) {
           << SizeOfExpr->getSourceRange() << E->getOperatorLoc()
           << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
     }
+  } else if (const auto *E = Result.Nodes.getNodeAs<BinaryOperator>(
+                 "sizeof-in-ptr-arithmetic-plusminus")) {
+    const auto *PointeeTy = Result.Nodes.getNodeAs<QualType>("pointee-type");
+    const auto *ScaleExpr =
+        Result.Nodes.getNodeAs<Expr>("sizeof-in-ptr-arithmetic-scale-expr");
+    const auto PointeeSize =
+        getSizeOfType(Ctx, PointeeTy->getTypePtr()).getQuantity();
+    const int ScaleKind = [ScaleExpr]() {
+      if (const auto *UTTE = dyn_cast<UnaryExprOrTypeTraitExpr>(ScaleExpr))
+        switch (UTTE->getKind()) {
+        case UETT_SizeOf:
+          return 0;
+        case UETT_AlignOf:
+          return 1;
+        default:
+          return -1;
+        }
+
+      if (isa<OffsetOfExpr>(ScaleExpr))
+        return 2;
+
+      return -1;
+    }();
+
+    if (ScaleKind != -1 && PointeeSize != 1) {
+      diag(E->getExprLoc(),
+           "suspicious usage of '%select{sizeof|alignof|offsetof}0(...)' in "
+           "pointer arithmetic; this scaled value will be scaled again by the "
+           "'%1' operator")
+          << ScaleKind << E->getOpcodeStr() << ScaleExpr->getSourceRange();
+      diag(E->getExprLoc(),
+           "'%0' in pointer arithmetic internally scales with 'sizeof(%1)' == "
+           "%2",
+           DiagnosticIDs::Note)
+          << E->getOpcodeStr()
+          << PointeeTy->getAsString(Ctx.getPrintingPolicy()) << PointeeSize;
+    }
   }
 }
 
diff --git a/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.h b/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.h
index 9ca17bc9e6f124..66d7c34cc9e940 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.h
@@ -13,7 +13,7 @@
 
 namespace clang::tidy::bugprone {
 
-/// Find suspicious usages of sizeof expression.
+/// Find suspicious usages of sizeof expressions.
 ///
 /// For the user-facing documentation see:
 /// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/sizeof-expression.html
diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
deleted file mode 100644
index 7a77bec319559b..00000000000000
--- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-//===--- SuspiciousPointerArithmeticsUsingSizeofCheck.cpp - clang-tidy ----===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#include "SuspiciousPointerArithmeticsUsingSizeofCheck.h"
-#include "../utils/Matchers.h"
-#include "clang/AST/ASTContext.h"
-#include "clang/ASTMatchers/ASTMatchFinder.h"
-#include "clang/Lex/Lexer.h"
-
-using namespace clang::ast_matchers;
-
-namespace clang::tidy::bugprone {
-
-namespace {
-
-constexpr llvm::StringLiteral BinOp{"bin-op"};
-constexpr llvm::StringLiteral PointedType{"pointed-type"};
-constexpr llvm::StringLiteral ScaleExpr{"scale-expr"};
-
-const auto IgnoredTypes = qualType(
-    anyOf(asString("char"), asString("unsigned char"), asString("signed char"),
-          asString("int8_t"), asString("uint8_t"), asString("std::byte"),
-          asString("const char"), asString("const unsigned char"),
-          asString("const signed char"), asString("const int8_t"),
-          asString("const uint8_t"), asString("const std::byte")));
-const auto InterestingPointer = pointerType(unless(pointee(IgnoredTypes)));
-
-AST_MATCHER(Expr, offsetOfExpr) { return isa<OffsetOfExpr>(Node); }
-
-const auto ScaledIntegerTraitExprs =
-    expr(anyOf(unaryExprOrTypeTraitExpr(ofKind(UETT_SizeOf)),
-               unaryExprOrTypeTraitExpr(ofKind(UETT_AlignOf)), offsetOfExpr()));
-
-CharUnits getSizeOfType(const ASTContext &Ctx, const Type *Ty) {
-  if (!Ty || Ty->isIncompleteType() || Ty->isDependentType() ||
-      isa<DependentSizedArrayType>(Ty) || !Ty->isConstantSizeType())
-    return CharUnits::Zero();
-  return Ctx.getTypeSizeInChars(Ty);
-}
-
-} // namespace
-
-SuspiciousPointerArithmeticsUsingSizeofCheck::
-    SuspiciousPointerArithmeticsUsingSizeofCheck(StringRef Name,
-                                                 ClangTidyContext *Context)
-    : ClangTidyCheck(Name, Context) {}
-
-void SuspiciousPointerArithmeticsUsingSizeofCheck::registerMatchers(
-    MatchFinder *Finder) {
-  Finder->addMatcher(
-      expr(anyOf(binaryOperator(hasAnyOperatorName("+", "+=", "-", "-="),
-                                hasLHS(hasType(pointerType(
-                                    pointee(qualType().bind(PointedType))))),
-                                hasRHS(ScaledIntegerTraitExprs.bind(ScaleExpr)))
-                     .bind(BinOp),
-                 binaryOperator(hasAnyOperatorName("+", "-"),
-                                hasRHS(hasType(pointerType(
-                                    pointee(qualType().bind(PointedType))))),
-                                hasLHS(ScaledIntegerTraitExprs.bind(ScaleExpr)))
-                     .bind(BinOp))),
-      this);
-}
-
-void SuspiciousPointerArithmeticsUsingSizeofCheck::check(
-    const MatchFinder::MatchResult &Result) {
-  const ASTContext &Ctx = *Result.Context;
-  const auto *BO = Result.Nodes.getNodeAs<BinaryOperator>(BinOp);
-  const auto *QT = Result.Nodes.getNodeAs<QualType>(PointedType);
-  const auto *ScaleE = Result.Nodes.getNodeAs<Expr>(ScaleExpr);
-  assert(BO && QT && ScaleE && "Broken matchers encountered.");
-
-  const auto Size = getSizeOfType(Ctx, QT->getTypePtr()).getQuantity();
-  if (Size == 1)
-    return;
-
-  const int KindSelect = [ScaleE]() {
-    if (const auto *UTTE = dyn_cast<UnaryExprOrTypeTraitExpr>(ScaleE))
-      switch (UTTE->getKind()) {
-      case UETT_SizeOf:
-        return 0;
-      case UETT_AlignOf:
-        return 1;
-      default:
-        return -1;
-      }
-
-    if (isa<OffsetOfExpr>(ScaleE))
-      return 2;
-
-    return -1;
-  }();
-  assert(KindSelect != -1 && "Unhandled scale-expr kind!");
-
-  diag(BO->getExprLoc(), "pointer arithmetic using a number scaled by "
-                         "'%select{sizeof|alignof|offsetof}0'; this value will "
-                         "be scaled again by the '%1' operator")
-      << KindSelect << BO->getOpcodeStr() << ScaleE->getSourceRange();
-  diag(BO->getExprLoc(), "'%0' scales with 'sizeof(%1)' == %2",
-       DiagnosticIDs::Note)
-      << BO->getOpcodeStr() << QT->getAsString(Ctx.getPrintingPolicy()) << Size;
-}
-
-} // namespace clang::tidy::bugprone
diff --git a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.h b/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.h
deleted file mode 100644
index fdce44a7a24394..00000000000000
--- a/clang-tools-extra/clang-tidy/bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.h
+++ /dev/null
@@ -1,31 +0,0 @@
-//===--- SuspiciousPointerArithmeticsUsingSizeofCheck.h -------*- C++ -*---===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSPOINTERARITHMETICSUSINGSIZEOFCHECK_H
-#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSPOINTERARITHMETICSUSINGSIZEOFCHECK_H
-
-#include "../ClangTidyCheck.h"
-
-namespace clang::tidy::bugprone {
-
-/// Finds suspicious pointer arithmetic calculations where the pointer is
-/// offset by an alignof(), offsetof(), or sizeof() expression.
-///
-/// For the user-facing documentation see:
-/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof.html
-class SuspiciousPointerArithmeticsUsingSizeofCheck : public ClangTidyCheck {
-public:
-  SuspiciousPointerArithmeticsUsingSizeofCheck(StringRef Name,
-                                               ClangTidyContext *Context);
-  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
-  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
-};
-
-} // namespace clang::tidy::bugprone
-
-#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SUSPICIOUSPOINTERARITHMETICSUSINGSIZEOFCHECK_H
diff --git a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
index ce5c2a119f4528..26befe0de59ae4 100644
--- a/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/cert/CERTTidyModule.cpp
@@ -14,9 +14,9 @@
 #include "../bugprone/ReservedIdentifierCheck.h"
 #include "../bugprone/SignalHandlerCheck.h"
 #include "../bugprone/SignedCharMisuseCheck.h"
+#include "../bugprone/SizeofExpressionCheck.h"
 #include "../bugprone/SpuriouslyWakeUpFunctionsCheck.h"
 #include "../bugprone/SuspiciousMemoryComparisonCheck.h"
-#include "../bugprone/SuspiciousPointerArithmeticsUsingSizeofCheck.h"
 #include "../bugprone/UnhandledSelfAssignmentCheck.h"
 #include "../bugprone/UnsafeFunctionsCheck.h"
 #include "../bugprone/UnusedReturnValueCheck.h"
@@ -283,9 +283,8 @@ class CERTModule : public ClangTidyModule {
 
     // C checkers
     // ARR
-    CheckFactories
-        .registerCheck<bugprone::SuspiciousPointerArithmeticsUsingSizeofCheck>(
-            "cert-arr39-c");
+    CheckFactories.registerCheck<bugprone::SizeofExpressionCheck>(
+        "cert-arr39-c");
     // CON
     CheckFactories.registerCheck<bugprone::SpuriouslyWakeUpFunctionsCheck>(
         "cert-con36-c");
@@ -337,6 +336,12 @@ class CERTModule : public ClangTidyModule {
   ClangTidyOptions getModuleOptions() override {
     ClangTidyOptions Options;
     ClangTidyOptions::OptionMap &Opts = Options.CheckOptions;
+    Opts["cert-arr39-c.WarnOnSizeOfConstant"] = "false";
+    Opts["cert-arr39-c.WarnOnSizeOfIntegerExpression"] = "false";
+    Opts["cert-arr39-c.WarnOnSizeOfThis"] = "false";
+    Opts["cert-arr39-c.WarnOnSizeOfCompareToConstant"] = "false";
+    Opts["cert-arr39-c.WarnOnSizeOfPointer"] = "false";
+    Opts["cert-arr39-c.WarnOnSizeOfPointerToAggregate"] = "false";
     Opts["cert-dcl16-c.NewSuffixes"] = "L;LL;LU;LLU";
     Opts["cert-err33-c.CheckedFunctions"] = CertErr33CCheckedFunctions;
     Opts["cert-err33-c.AllowCastToVoid"] = "true";
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression-pointer-arithmetics-c11.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression-pointer-arithmetics-c11.c
new file mode 100644
index 00000000000000..944328e61c3404
--- /dev/null
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression-pointer-arithmetics-c11.c
@@ -0,0 +1,22 @@
+// RUN: %check_clang_tidy -std=c11-or-later %s bugprone-sizeof-expression %t
+
+#define alignof(type_name) _Alignof(type_name)
+extern void sink(const void *P);
+
+enum { BufferSize = 1024 };
+
+struct S {
+  long A, B, C;
+};
+
+void bad4d(void) {
+  struct S Buffer[BufferSize];
+
+  struct S *P = &Buffer[0];
+  struct S *Q = P;
+  while (Q < P + alignof(Buffer)) {
+    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: suspicious usage of 'alignof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator [bugprone-sizeof-expression]
+    // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' in pointer arithmetic internally scales with 'sizeof(struct S)' == {{[0-9]+}}
+    sink(Q++);
+  }
+}
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression-pointer-arithmetics.c
similarity index 65%
rename from clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c
rename to clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression-pointer-arithmetics.c
index d7b647661ac78e..dd8aedb90c239a 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof.c
+++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression-pointer-arithmetics.c
@@ -1,7 +1,10 @@
-// RUN: %check_clang_tidy %s bugprone-suspicious-pointer-arithmetics-using-sizeof %t
+// RUN: %check_clang_tidy %s bugprone-sizeof-expression %t
 
-typedef __typeof__(sizeof(void*)) size_t;
 #define offsetof(type, member) __builtin_offsetof(type, member)
+
+typedef __SIZE_TYPE__ size_t;
+typedef __WCHAR_TYPE__ wchar_t;
+
 extern void *memset(void *Dest, int Ch, size_t Count);
 extern void sink(const void *P);
 extern size_t strlen(const char *Str);
@@ -19,8 +22,8 @@ void bad1a(void) {
   int *P = &Buffer[0];
   int *Q = P;
   while (Q < P + sizeof(Buffer)) {
-    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: pointer arithmetic using a number scaled by 'sizeof'; this value will be scaled again by the '+' operator [bugprone-suspicious-pointer-arithmetics-using-sizeof]
-    // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' scales with 'sizeof(int)' == {{[0-9]+}}
+    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator [bugprone-sizeof-expression]
+    // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' in pointer arithmetic internally scales with 'sizeof(int)' == {{[0-9]+}}
     *Q++ = 0;
   }
 }
@@ -32,8 +35,8 @@ void bad1b(void) {
   Integer *P = &Buffer[0];
   Integer *Q = P;
   while (Q < P + sizeof(Buffer)) {
-    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: pointer arithmetic using a number scaled by 'sizeof'; this value will be scaled again by the '+' operator
-    // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' scales with 'sizeof(Integer)' == {{[0-9]+}}
+    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator
+    // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' in pointer arithmetic internally scales with 'sizeof(Integer)' == {{[0-9]+}}
     *Q++ = 0;
   }
 }
@@ -53,8 +56,8 @@ void bad2(void) {
   int *P = Buffer;
 
   while (P < Buffer + sizeof(Buffer)) {
-    // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: pointer arithmetic using a number scaled by 'sizeof'; this value will be scaled again by the '+' operator
-    // CHECK-MESSAGES: :[[@LINE-2]]:21: note: '+' scales with 'sizeof(int)' == {{[0-9]+}}
+    // CHECK-MESSAGES: :[[@LINE-1]]:21: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator
+    // CHECK-MESSAGES: :[[@LINE-2]]:21: note: '+' in pointer arithmetic internally scales with 'sizeof(int)' == {{[0-9]+}}
     *P++ = 0;
   }
 }
@@ -93,8 +96,8 @@ void good3a(struct S *S) {
 void bad3b(struct S *S) {
   memset(S + offsetof(struct S, B), 0,
          sizeof(struct S) - offsetof(struct S, B));
-  // CHECK-MESSAGES: :[[@LINE-2]]:12: warning: pointer arithmetic using a number scaled by 'offsetof'; this value will be scaled again by the '+' operator
-  // CHECK-MESSAGES: :[[@LINE-3]]:12: note: '+' scales with 'sizeof(struct S)' == {{[0-9]+}}
+  // CHECK-MESSAGES: :[[@LINE-2]]:12: warning: suspicious usage of 'offsetof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator
+  // CHECK-MESSAGES: :[[@LINE-3]]:12: note: '+' in pointer arithmetic internally scales with 'sizeof(struct S)' == {{[0-9]+}}
 }
 
 void good3b(struct S *S) {
@@ -109,8 +112,8 @@ void bad3c(void) {
   struct S *P = &Buffer[0];
   struct S *Q = P;
   while (Q < P + sizeof(Buffer)) {
-    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: pointer arithmetic using a number scaled by 'sizeof'; this value will be scaled again by the '+' operator
-    // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' scales with 'sizeof(struct S)' == {{[0-9]+}}
+    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator
+    // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' in pointer arithmetic internally scales with 'sizeof(struct S)' == {{[0-9]+}}
     sink(Q++);
   }
 }
@@ -123,8 +126,8 @@ void bad4(void) {
   while (Q < P + BufferSize) {
     *Q = 0;
     Q += sizeof(*Q);
-    // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: pointer arithmetic using a number scaled by 'sizeof'; this value will be scaled again by the '+=' operator
-    // CHECK-MESSAGES: :[[@LINE-2]]:7: note: '+=' scales with 'sizeof(int)' == {{[0-9]+}}
+    // CHECK-MESSAGES: :[[@LINE-1]]:7: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+=' operator
+    // CHECK-MESSAGES: :[[@LINE-2]]:7: note: '+=' in pointer arithmetic internally scales with 'sizeof(int)' == {{[0-9]+}}
   }
 }
 
@@ -202,8 +205,8 @@ void bad6(void) {
   while (Q < P + BufferSize) {
     *Q = 0;
     Q = Q + sizeof(*Q);
-    // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: pointer arithmetic using a number scaled by 'sizeof'; this value will be scaled again by the '+' operator
-    // CHECK-MESSAGES: :[[@LINE-2]]:11: note: '+' scales with 'sizeof(int)' == {{[0-9]+}}
+    // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator
+    // CHECK-MESSAGES: :[[@LINE-2]]:11: note: '+' in pointer arithmetic internally scales with 'sizeof(int)' == {{[0-9]+}}
   }
 }
 
@@ -259,8 +262,8 @@ void bad8(void) {
   while (Q >= P) {
     *Q = 0;
     Q = Q - sizeof(*Q);
-    // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: pointer arithmetic using a number scaled by 'sizeof'; this value will be scaled again by the '-' operator
-    // CHECK-MESSAGES: :[[@LINE-2]]:11: note: '-' scales with 'sizeof(int)' == {{[0-9]+}}
+    // CHECK-MESSAGES: :[[@LINE-1]]:11: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '-' operator
+    // CHECK-MESSAGES: :[[@LINE-2]]:11: note: '-' in pointer arithmetic internally scales with 'sizeof(int)' == {{[0-9]+}}
   }
 }
 
@@ -322,8 +325,8 @@ void bad12(void) {
   wchar_t Message[BufferSize];
   wcscpy(Message, L"Message: ");
   wscanf(L"%s", Message + wcslen(Message) * sizeof(wchar_t));
-  // CHECK-MESSAGES: :[[@LINE-1]]:15: warning: pointer arithmetic using a number scaled by 'sizeof'; this value will be scaled again by the '+' operator
-  // CHECK-MESSAGES: :[[@LINE-2]]:15: note: '+' scales with 'sizeof(wchar_t)' == {{[0-9]+}}
+  // CHECK-MESSAGES: :[[@LINE-1]]:25: warning: suspicious usage of 'sizeof(...)' in pointer arithmetic; this scaled value will be scaled again by the '+' operator
+  // CHECK-MESSAGES: :[[@LINE-2]]:25: note: '+' in pointer arithmetic internally scales with 'sizeof(wchar_t)' == {{[0-9]+}}
 }
 
 void silenced12(void) {
@@ -332,6 +335,12 @@ void silenced12(void) {
   scanf("%s", Message + strlen(Message) * sizeof(char));
 }
 
+void nomatch12(void) {
+  char Message[BufferSize];
+  strcpy(Message, "Message: ");
+  scanf("%s", Message + strlen(Message));
+}
+
 void good12(void) {
   wchar_t Message[BufferSize];
   wcscpy(Message, L"Message: ");
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression-2.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression.c
similarity index 100%
rename from clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression-2.c
rename to clang-tools-extra/test/clang-tidy/checkers/bugprone/sizeof-expression.c
diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof-c11.c b/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof-c11.c
deleted file mode 100644
index 33bf69bdea1185..00000000000000
--- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/suspicious-pointer-arithmetics-using-sizeof-c11.c
+++ /dev/null
@@ -1,22 +0,0 @@
-// RUN: %check_clang_tidy -std=c11-or-later %s bugprone-suspicious-pointer-arithmetics-using-sizeof %t
-
-#define alignof(type_name) _Alignof(type_name)
-extern void sink(const void *P);
-
-enum { BufferSize = 1024 };
-
-struct S {
-  long A, B, C;
-};
-
-void bad4d(void) {
-  struct S Buffer[BufferSize];
-
-  struct S *P = &Buffer[0];
-  struct S *Q = P;
-  while (Q < P + alignof(Buffer)) {
-    // CHECK-MESSAGES: :[[@LINE-1]]:16: warning: pointer arithmetic using a number scaled by 'alignof'; this value will be scaled again by the '+' operator
-    // CHECK-MESSAGES: :[[@LINE-2]]:16: note: '+' scales with 'sizeof(struct S)' == {{[0-9]+}}
-    sink(Q++);
-  }
-}

>From 0cc4e0ac415e8e851280f0716132fbf73b5a9039 Mon Sep 17 00:00:00 2001
From: Whisperity <whisperity at gmail.com>
Date: Wed, 28 Aug 2024 12:34:11 +0200
Subject: [PATCH 22/22] doc: Document pointer arithmetic cases checked by
 `bugprone-sizeof-expression`

(Also document the other case which has been checked for a while but did not
have a documentation.)
---
 .../bugprone/SizeofExpressionCheck.cpp        |  4 +-
 clang-tools-extra/docs/ReleaseNotes.rst       | 17 ++--
 .../checks/bugprone/sizeof-expression.rst     | 98 +++++++++++++++++++
 ...cious-pointer-arithmetics-using-sizeof.rst | 50 ----------
 .../docs/clang-tidy/checks/cert/arr39-c.rst   |  4 +-
 .../docs/clang-tidy/checks/list.rst           |  1 +
 6 files changed, 110 insertions(+), 64 deletions(-)
 delete mode 100644 clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof.rst

diff --git a/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp
index 143cf6b0ca72b7..b4577618bda0f0 100644
--- a/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SizeofExpressionCheck.cpp
@@ -260,8 +260,8 @@ void SizeofExpressionCheck::registerMatchers(MatchFinder *Finder) {
                      this);
 
   // Detect sizeof usage in comparisons involving pointer arithmetics, such as
-  // N * sizeof(S) == P1 - P2 or (P1 - P2) / sizeof(S), where P1 and P2 are
-  // pointers to a type S.
+  // N * sizeof(T) == P1 - P2 or (P1 - P2) / sizeof(T), where P1 and P2 are
+  // pointers to a type T.
   const auto PtrDiffExpr = binaryOperator(
       hasOperatorName("-"),
       hasLHS(hasType(hasUnqualifiedDesugaredType(pointerType(pointee(
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index 039a7af8d0f03a..53fb3395146f10 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -98,24 +98,21 @@ Improvements to clang-tidy
 New checks
 ^^^^^^^^^^
 
-- New :doc:`bugprone-suspicious-pointer-arithmetics-using-sizeof
-  <clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof>`
-  check.
-
-  Finds suspicious pointer arithmetic calculations where the pointer is offset
-  by an ``alignof()``, ``offsetof()``, or ``sizeof()`` expression.
-
 New check aliases
 ^^^^^^^^^^^^^^^^^
 
 - New alias :doc:`cert-arr39-c <clang-tidy/checks/cert/arr39-c>` to
-  :doc:`bugprone-suspicious-pointer-arithmetics-using-sizeof
-  <clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof>`
-  was added.
+  :doc:`bugprone-sizeof-expression
+  <clang-tidy/checks/bugprone/sizeof-expression>` was added.
 
 Changes in existing checks
 ^^^^^^^^^^^^^^^^^^^^^^^^^^
 
+- Improved :doc:`bugprone-sizeof-expression
+  <clang-tidy/checks/bugprone/sizeof-expression>` check to find suspicious
+  usages of ``sizeof()``, ``alignof()``, and ``offsetof()`` when adding or
+  subtracting from a pointer.
+
 - Improved :doc:`modernize-use-std-format
   <clang-tidy/checks/modernize/use-std-format>` check to support replacing
   member function calls too.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/sizeof-expression.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/sizeof-expression.rst
index ed5bb4fbb89baf..905ad9821fb193 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/sizeof-expression.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/sizeof-expression.rst
@@ -164,6 +164,104 @@ hidden through macros.
     memcpy(dst, buf, sizeof(INT_SZ));  // sizeof(sizeof(int)) is suspicious.
   }
 
+Suspicious usages of 'sizeof(...)' in pointer arithmetic
+--------------------------------------------------------
+
+Arithmetic operators on pointers automatically scale the result with the size
+of the pointed typed.
+Further use of ``sizeof`` around pointer arithmetic will typically result in an
+unintended result.
+
+Scaling the result of pointer difference
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Subtracting two pointers results in an integer expression (of type
+``ptrdiff_t``) which expresses the distance between the two pointed objects in
+"number of objects between".
+A common mistake is to think that the result is "number of bytes between", and
+scale the difference with ``sizeof``, such as ``P1 - P2 == N * sizeof(T)``
+(instead of ``P1 - P2 == N``) or ``(P1 - P2) / sizeof(T)`` instead of
+``P1 - P2``.
+
+.. code-block:: c++
+
+  void splitFour(const Obj* Objs, size_t N, Obj Delimiter) {
+    const Obj *P = Objs;
+    while (P < Objs + N) {
+      if (*P == Delimiter) {
+        break;
+      }
+    }
+
+    if (P - Objs != 4 * sizeof(Obj)) { // Expecting a distance multiplied by sizeof is suspicious.
+      error();
+    }
+  }
+
+.. code-block:: c++
+
+  void iterateIfEvenLength(int *Begin, int *End) {
+    auto N = (Begin - End) / sizeof(int); // Dividing by sizeof() is suspicious.
+    if (N % 2)
+      return;
+
+    // ...
+  }
+
+Stepping a pointer with a scaled integer
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+Conversely, when performing pointer arithmetics to add or subtract from a
+pointer, the arithmetic operator implicitly scales the value actually added to
+the pointer with the size of the pointee, as ``Ptr + N`` expects ``N`` to be
+"number of objects to step", and not "number of bytes to step".
+
+Seeing the calculation of a pointer where ``sizeof`` appears is suspicious,
+and the result is typically unintended, often out of bounds.
+``Ptr + sizeof(T)`` will offset the pointer by ``sizeof(T)`` elements,
+effectively exponentiating the scaling factor to the power of 2.
+
+This case also checks suspicious ``alignof`` and ``offsetof`` usages in
+pointer arithmetic, as both return the "size" in bytes and not elements,
+potentially resulting in doubly-scaled offsets.
+
+
+.. code-block:: c++
+
+  void printEveryEvenIndexElement(int *Array, size_t N) {
+    int *P = Array;
+    while (P <= Array + N * sizeof(int)) { // Suspicious pointer arithmetic using sizeof()!
+      printf("%d ", *P);
+
+      P += 2 * sizeof(int); // Suspicious pointer arithmetic using sizeof()!
+    }
+  }
+
+.. code-block:: c++
+
+  struct Message { /* ... */; char Flags[8]; };
+  void clearFlags(Message *Array, size_t N) {
+    const Message *End = Array + N;
+    while (Array < End) {
+      memset(Array + offsetof(Message, Flags), // Suspicious pointer arithmetic using offsetof()!
+             0, sizeof(Message::Flags));
+      ++Array;
+    }
+  }
+
+For this checked bogus pattern, `cert-arr39-c` redirects here as an alias of
+this check.
+
+This check corresponds to the CERT C Coding Standard rule
+`ARR39-C. Do not add or subtract a scaled integer to a pointer
+<http://wiki.sei.cmu.edu/confluence/display/c/ARR39-C.+Do+not+add+or+subtract+a+scaled+integer+to+a+pointer>`_.
+
+Limitations
+"""""""""""
+
+Cases where the pointee type has a size of `1` byte (such as, and most
+importantly, ``char``) are excluded.
+
 Options
 -------
 
diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof.rst
deleted file mode 100644
index 805e489d06e881..00000000000000
--- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/suspicious-pointer-arithmetics-using-sizeof.rst
+++ /dev/null
@@ -1,50 +0,0 @@
-.. title:: clang-tidy - bugprone-suspicious-pointer-arithmetics-using-sizeof
-
-bugprone-suspicious-pointer-arithmetics-using-sizeof
-====================================================
-
-Finds suspicious pointer arithmetic calculations where the pointer is offset by
-an ``alignof()``, ``offsetof()``, or ``sizeof()`` expression.
-
-Pointer arithmetic expressions implicitly scale the offset added to or
-subtracted from the address by the size of the pointee type.
-Using an offset expression that is already scaled by the size of the underlying
-type effectively results in a squared offset, which is likely an invalid
-pointer that points beyond the end of the intended array.
-
-.. code-block:: c
-
-  void printEveryEvenIndexElement(int *Array, size_t N) {
-    int *P = Array;
-    while (P <= Array + N * sizeof(int)) { // Suspicious pointer arithmetics using sizeof()!
-      printf("%d ", *P);
-
-      P += 2 * sizeof(int); // Suspicious pointer arithmetics using sizeof()!
-    }
-  }
-
-The above example should be in the following, correct form:
-
-.. code-block:: c
-
-  void printEveryEvenIndexElement(int *Array, size_t N) {
-    int *P = Array;
-    while (P <= Array + N) {
-      printf("%d ", *P);
-
-      P += 2;
-    }
-  }
-
-`cert-arr39-c` redirects here as an alias of this check.
-
-This check corresponds to the CERT C Coding Standard rule
-`ARR39-C. Do not add or subtract a scaled integer to a pointer
-<http://wiki.sei.cmu.edu/confluence/display/c/ARR39-C.+Do+not+add+or+subtract+a+scaled+integer+to+a+pointer>`_.
-
-Limitations
------------
-
-While incorrect from a technically rigorous point of view, the check does not
-warn for pointer arithmetics where the pointee type is ``char``
-(``sizeof(char) == 1``, by definition) on purpose.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/cert/arr39-c.rst b/clang-tools-extra/docs/clang-tidy/checks/cert/arr39-c.rst
index 91e02e39952be9..21353c61eede86 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/cert/arr39-c.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/cert/arr39-c.rst
@@ -1,10 +1,10 @@
 .. title:: clang-tidy - cert-arr39-c
 .. meta::
-   :http-equiv=refresh: 5;URL=../bugprone/suspicious-pointer-arithmetics-using-sizeof.html
+   :http-equiv=refresh: 5;URL=../bugprone/sizeof-expression.html
 
 cert-arr39-c
 ============
 
 The `cert-arr39-c` check is an alias, please see
-:doc:`bugprone-suspicious-pointer-arithmetics-using-sizeof <../bugprone/suspicious-pointer-arithmetics-using-sizeof>`
+:doc:`bugprone-sizeof-expression <../bugprone/sizeof-expression>`
 for more information.
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index a931ebf025a10e..1909d7b8d8e246 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -407,6 +407,7 @@ Check aliases
    :header: "Name", "Redirect", "Offers fixes"
 
    :doc:`bugprone-narrowing-conversions <bugprone/narrowing-conversions>`, :doc:`cppcoreguidelines-narrowing-conversions <cppcoreguidelines/narrowing-conversions>`,
+   :doc:`cert-arr39-c <cert/arr39-c>`, :doc:`bugprone-sizeof-expression <bugprone/sizeof-expression>`,
    :doc:`cert-con36-c <cert/con36-c>`, :doc:`bugprone-spuriously-wake-up-functions <bugprone/spuriously-wake-up-functions>`,
    :doc:`cert-con54-cpp <cert/con54-cpp>`, :doc:`bugprone-spuriously-wake-up-functions <bugprone/spuriously-wake-up-functions>`,
    :doc:`cert-ctr56-cpp <cert/ctr56-cpp>`, :doc:`bugprone-pointer-arithmetic-on-polymorphic-object <bugprone/pointer-arithmetic-on-polymorphic-object>`,



More information about the cfe-commits mailing list