https://github.com/ccotter updated 
https://github.com/llvm/llvm-project/pull/114244

>From fd914cc82688b122654d2d7ada72007541b197c0 Mon Sep 17 00:00:00 2001
From: Chris Cotter <ccotte...@bloomberg.net>
Date: Wed, 30 Oct 2024 10:54:49 -0400
Subject: [PATCH 01/15] Add bugprone-sprintf-overlap

---
 .../bugprone/BugproneTidyModule.cpp           |  3 +
 .../clang-tidy/bugprone/CMakeLists.txt        |  1 +
 .../bugprone/UndefinedSprintfOverlapCheck.cpp | 93 +++++++++++++++++++
 .../bugprone/UndefinedSprintfOverlapCheck.h   | 36 +++++++
 clang-tools-extra/docs/ReleaseNotes.rst       |  6 ++
 .../bugprone/undefined-sprintf-overlap.rst    | 23 +++++
 .../docs/clang-tidy/checks/list.rst           |  3 +-
 .../bugprone/undefined-sprintf-overlap.cpp    | 59 ++++++++++++
 8 files changed, 223 insertions(+), 1 deletion(-)
 create mode 100644 
clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp

diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp 
b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 33ac65e715ce81..ac3a08c80d7ae6 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -86,6 +86,7 @@
 #include "TooSmallLoopVariableCheck.h"
 #include "UncheckedOptionalAccessCheck.h"
 #include "UndefinedMemoryManipulationCheck.h"
+#include "UndefinedSprintfOverlapCheck.h"
 #include "UndelegatedConstructorCheck.h"
 #include "UnhandledExceptionAtNewCheck.h"
 #include "UnhandledSelfAssignmentCheck.h"
@@ -248,6 +249,8 @@ class BugproneModule : public ClangTidyModule {
         "bugprone-unchecked-optional-access");
     CheckFactories.registerCheck<UndefinedMemoryManipulationCheck>(
         "bugprone-undefined-memory-manipulation");
+    CheckFactories.registerCheck<UndefinedSprintfOverlapCheck>(
+        "bugprone-undefined-sprintf-overlap");
     CheckFactories.registerCheck<UndelegatedConstructorCheck>(
         "bugprone-undelegated-constructor");
     CheckFactories.registerCheck<UnhandledSelfAssignmentCheck>(
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index b0a2318acc0597..2403ed665fd5c7 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -81,6 +81,7 @@ add_clang_library(clangTidyBugproneModule STATIC
   TooSmallLoopVariableCheck.cpp
   UncheckedOptionalAccessCheck.cpp
   UndefinedMemoryManipulationCheck.cpp
+  UndefinedSprintfOverlapCheck.cpp
   UndelegatedConstructorCheck.cpp
   UnhandledExceptionAtNewCheck.cpp
   UnhandledSelfAssignmentCheck.cpp
diff --git 
a/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
new file mode 100644
index 00000000000000..301b6bce0dbbad
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
@@ -0,0 +1,93 @@
+//===--- UndefinedSprintfOverlapCheck.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 "UndefinedSprintfOverlapCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "clang/Lex/Lexer.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+AST_MATCHER_P(CallExpr, hasAnyOtherArgument,
+              ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
+  for (const auto *Arg : llvm::drop_begin(Node.arguments())) {
+    ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder);
+    if (InnerMatcher.matches(*Arg, Finder, &Result)) {
+      *Builder = std::move(Result);
+      return true;
+    }
+  }
+  return false;
+}
+
+AST_MATCHER_P(IntegerLiteral, hasSameValueAs, std::string, ID) {
+  return Builder->removeBindings(
+      [this, &Node](const ast_matchers::internal::BoundNodesMap &Nodes) {
+        const auto &BN = Nodes.getNode(ID);
+        if (const auto *Lit = BN.get<IntegerLiteral>()) {
+          return Lit->getValue() != Node.getValue();
+        }
+        return true;
+      });
+}
+
+UndefinedSprintfOverlapCheck::UndefinedSprintfOverlapCheck(
+    StringRef Name, ClangTidyContext *Context)
+    : ClangTidyCheck(Name, Context),
+      SprintfRegex(Options.get("SprintfFunction", "(::std)?::(sn?printf)")) {}
+
+void UndefinedSprintfOverlapCheck::registerMatchers(MatchFinder *Finder) {
+  auto FirstArg = declRefExpr(to(varDecl().bind("firstArg")));
+  auto OtherRefToArg = declRefExpr(to(varDecl(equalsBoundNode("firstArg"))))
+                           .bind("overlappingArg");
+  Finder->addMatcher(
+      callExpr(callee(functionDecl(matchesName(SprintfRegex)).bind("decl")),
+               allOf(hasArgument(
+                         0, anyOf(FirstArg.bind("firstArgExpr"),
+                                  arraySubscriptExpr(
+                                      hasBase(FirstArg),
+                                      hasIndex(integerLiteral().bind("index")))
+                                      .bind("firstArgExpr"),
+                                  memberExpr(member(decl().bind("member")),
+                                             hasObjectExpression(FirstArg))
+                                      .bind("firstArgExpr"))),
+                     hasAnyOtherArgument(anyOf(
+                         OtherRefToArg,
+                         arraySubscriptExpr(
+                             hasBase(OtherRefToArg),
+                             
hasIndex(integerLiteral(hasSameValueAs("index")))),
+                         memberExpr(member(decl(equalsBoundNode("member"))),
+                                    hasObjectExpression(OtherRefToArg)))))),
+      this);
+}
+
+void UndefinedSprintfOverlapCheck::check(
+    const MatchFinder::MatchResult &Result) {
+  const auto *OverlappingArg =
+      Result.Nodes.getNodeAs<DeclRefExpr>("overlappingArg");
+  const auto *FirstArg = Result.Nodes.getNodeAs<Expr>("firstArgExpr");
+  const auto *FnDecl = Result.Nodes.getNodeAs<FunctionDecl>("decl");
+
+  llvm::StringRef FirstArgText =
+      Lexer::getSourceText(CharSourceRange::getTokenRange(
+                               FirstArg->getBeginLoc(), FirstArg->getEndLoc()),
+                           *Result.SourceManager, getLangOpts());
+
+  diag(OverlappingArg->getLocation(),
+       "argument '%0' overlaps the first argument "
+       "in %1, which is undefined behavior")
+      << FirstArgText << FnDecl;
+}
+
+void UndefinedSprintfOverlapCheck::storeOptions(
+    ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, "SprintfRegex", SprintfRegex);
+}
+
+} // namespace clang::tidy::bugprone
diff --git 
a/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.h 
b/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.h
new file mode 100644
index 00000000000000..349b1156671ff0
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.h
@@ -0,0 +1,36 @@
+//===--- UndefinedSprintfOverlapCheck.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_UNDEFINEDSPRINTFOVERLAPCHECK_H
+#define 
LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNDEFINEDSPRINTFOVERLAPCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::bugprone {
+
+/// FIXME: Write a short description.
+///
+/// For the user-facing documentation see:
+/// 
http://clang.llvm.org/extra/clang-tidy/checks/bugprone/undefined-sprintf-overlap.html
+class UndefinedSprintfOverlapCheck : public ClangTidyCheck {
+public:
+  UndefinedSprintfOverlapCheck(StringRef Name, ClangTidyContext *Context);
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+  void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
+  std::optional<TraversalKind> getCheckTraversalKind() const override {
+    return TK_IgnoreUnlessSpelledInSource;
+  }
+
+private:
+  const std::string SprintfRegex;
+};
+
+} // namespace clang::tidy::bugprone
+
+#endif // 
LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNDEFINEDSPRINTFOVERLAPCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index ccebf74e8a67e7..7285343971189f 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -131,6 +131,12 @@ New checks
   Gives warnings for tagged unions, where the number of tags is
   different from the number of data members inside the union.
 
+- New :doc:`bugprone-undefined-sprintf-overlap
+  <clang-tidy/checks/bugprone/undefined-sprintf-overlap>` check.
+
+  Finds calls to sprintf family of functions whose first argument
+  overlaps with a subsequent argument.
+
 - New :doc:`portability-template-virtual-member-function
   <clang-tidy/checks/portability/template-virtual-member-function>` check.
 
diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
 
b/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
new file mode 100644
index 00000000000000..775d99c9f1e0bb
--- /dev/null
+++ 
b/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
@@ -0,0 +1,23 @@
+.. title:: clang-tidy - bugprone-undefined-sprintf-overlap
+
+bugprone-undefined-sprintf-overlap
+==================================
+
+Warns if any arguments to the sprintf family of functions overlap with the
+first argument.
+
+.. code-block:: c++
+
+    char buf[20] = {"hi"};
+    sprintf(buf, "%s%d", buf, 0);
+
+C99 and POSIX.1-2001 states that if copying were to take place between objects
+that overlap, the result is undefined.
+
+Options
+-------
+
+.. option:: SprintfRegex
+
+   A regex specifying the sprintf family of functions to match on. By default,
+   this is "(::std)?::sn?printf".
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst 
b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index d731b13fc0df44..41b7d92f94f90c 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -115,8 +115,8 @@ Clang-Tidy Checks
    :doc:`bugprone-multiple-new-in-one-expression 
<bugprone/multiple-new-in-one-expression>`,
    :doc:`bugprone-multiple-statement-macro 
<bugprone/multiple-statement-macro>`,
    :doc:`bugprone-no-escape <bugprone/no-escape>`,
-   :doc:`bugprone-nondeterministic-pointer-iteration-order 
<bugprone/nondeterministic-pointer-iteration-order>`,
    :doc:`bugprone-non-zero-enum-to-bool-conversion 
<bugprone/non-zero-enum-to-bool-conversion>`,
+   :doc:`bugprone-nondeterministic-pointer-iteration-order 
<bugprone/nondeterministic-pointer-iteration-order>`,
    :doc:`bugprone-not-null-terminated-result 
<bugprone/not-null-terminated-result>`, "Yes"
    :doc:`bugprone-optional-value-conversion 
<bugprone/optional-value-conversion>`, "Yes"
    :doc:`bugprone-parent-virtual-call <bugprone/parent-virtual-call>`, "Yes"
@@ -153,6 +153,7 @@ Clang-Tidy Checks
    :doc:`bugprone-too-small-loop-variable <bugprone/too-small-loop-variable>`,
    :doc:`bugprone-unchecked-optional-access 
<bugprone/unchecked-optional-access>`,
    :doc:`bugprone-undefined-memory-manipulation 
<bugprone/undefined-memory-manipulation>`,
+   :doc:`bugprone-undefined-sprintf-overlap 
<bugprone/undefined-sprintf-overlap>`, "Yes"
    :doc:`bugprone-undelegated-constructor <bugprone/undelegated-constructor>`,
    :doc:`bugprone-unhandled-exception-at-new 
<bugprone/unhandled-exception-at-new>`,
    :doc:`bugprone-unhandled-self-assignment 
<bugprone/unhandled-self-assignment>`,
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
new file mode 100644
index 00000000000000..50095346da8a8d
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
@@ -0,0 +1,59 @@
+// RUN: %check_clang_tidy %s bugprone-undefined-sprintf-overlap %t
+
+using size_t = decltype(sizeof(int));
+
+extern "C" int sprintf(char *s, const char *format, ...);
+extern "C" int snprintf(char *s, size_t n, const char *format, ...);
+
+namespace std {
+  int snprintf(char *s, size_t n, const char *format, ...);
+}
+
+struct st_t {
+  char buf[10];
+  char buf2[10];
+};
+
+void first_arg_overlaps() {
+  char buf[10];
+  sprintf(buf, "%s", buf);
+  // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: argument 'buf' overlaps the 
first argument in 'sprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  snprintf(buf, sizeof(buf), "%s", buf);
+  // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: argument 'buf' overlaps the 
first argument in 'snprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  std::snprintf(buf, sizeof(buf), "%s", buf);
+  // CHECK-MESSAGES: :[[@LINE-1]]:41: warning: argument 'buf' overlaps the 
first argument in 'snprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+
+  char* c = &buf[0];
+  sprintf(c, "%s", c);
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: argument 'c' overlaps the first 
argument in 'sprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  snprintf(c, sizeof(buf), "%s", c);
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: argument 'c' overlaps the first 
argument in 'snprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+
+  snprintf(c, sizeof(buf), "%s%s", c, c);
+  // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: argument 'c' overlaps the first 
argument in 'snprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+
+  char buf2[10];
+  snprintf(buf, sizeof(buf), "%s", buf2);
+
+  st_t st1, st2;
+  sprintf(st1.buf, "%s", st1.buf);
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: argument 'st1.buf' overlaps the 
first argument in 'sprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  sprintf(st1.buf, "%s", st1.buf2);
+  sprintf(st1.buf, "%s", st2.buf);
+
+  st_t* stp;
+  sprintf(stp->buf, "%s", stp->buf);
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: argument 'stp->buf' overlaps 
the first argument in 'sprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  sprintf((stp->buf), "%s", stp->buf);
+  // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: argument 'stp->buf' overlaps 
the first argument in 'sprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  stp = &st1;
+  sprintf(stp->buf, "%s", st1.buf);
+
+  char bufs[10][10];
+  sprintf(bufs[1], "%s", bufs[1]);
+  // CHECK-MESSAGES: :[[@LINE-1]]:26:  warning: argument 'bufs[1]' overlaps 
the first argument in 'sprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  sprintf(bufs[0], "%s", bufs[1]);
+
+  char bufss[10][10][10];
+  sprintf(bufss[0][1], "%s", bufss[0][1]);
+}

>From 004719c3f6efbb5e36016ac49ce8983ff7d2b144 Mon Sep 17 00:00:00 2001
From: Chris Cotter <ccotte...@bloomberg.net>
Date: Thu, 31 Oct 2024 11:13:16 -0400
Subject: [PATCH 02/15] Apply suggestions from code review

Co-authored-by: EugeneZelenko <eugene.zele...@gmail.com>
---
 clang-tools-extra/docs/ReleaseNotes.rst                       | 2 +-
 .../clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst  | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 7285343971189f..e746c8fcf675f2 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -134,7 +134,7 @@ New checks
 - New :doc:`bugprone-undefined-sprintf-overlap
   <clang-tidy/checks/bugprone/undefined-sprintf-overlap>` check.
 
-  Finds calls to sprintf family of functions whose first argument
+  Finds calls to ``sprintf`` family of functions whose first argument
   overlaps with a subsequent argument.
 
 - New :doc:`portability-template-virtual-member-function
diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
 
b/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
index 775d99c9f1e0bb..3f6640cb7eec89 100644
--- 
a/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
+++ 
b/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
@@ -19,5 +19,5 @@ Options
 
 .. option:: SprintfRegex
 
-   A regex specifying the sprintf family of functions to match on. By default,
-   this is "(::std)?::sn?printf".
+   A regex specifying the ``sprintf`` family of functions to match on. By 
default,
+   this is `(::std)?::sn?printf`.

>From d69c69ad588af74fb1575169713ee726f09638f5 Mon Sep 17 00:00:00 2001
From: Chris Cotter <ccotte...@bloomberg.net>
Date: Thu, 31 Oct 2024 11:43:07 -0400
Subject: [PATCH 03/15] Review feedback

---
 .../clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp      | 2 +-
 clang-tools-extra/docs/ReleaseNotes.rst                       | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
index 301b6bce0dbbad..043e5d8fc2a29d 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
@@ -29,7 +29,7 @@ AST_MATCHER_P(CallExpr, hasAnyOtherArgument,
 AST_MATCHER_P(IntegerLiteral, hasSameValueAs, std::string, ID) {
   return Builder->removeBindings(
       [this, &Node](const ast_matchers::internal::BoundNodesMap &Nodes) {
-        const auto &BN = Nodes.getNode(ID);
+        const DynTypedNode &BN = Nodes.getNode(ID);
         if (const auto *Lit = BN.get<IntegerLiteral>()) {
           return Lit->getValue() != Node.getValue();
         }
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index e746c8fcf675f2..98c137a29c13ac 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -134,8 +134,8 @@ New checks
 - New :doc:`bugprone-undefined-sprintf-overlap
   <clang-tidy/checks/bugprone/undefined-sprintf-overlap>` check.
 
-  Finds calls to ``sprintf`` family of functions whose first argument
-  overlaps with a subsequent argument.
+  Warns if any arguments to the sprintf family of functions overlap with the
+  first argument.
 
 - New :doc:`portability-template-virtual-member-function
   <clang-tidy/checks/portability/template-virtual-member-function>` check.

>From 1984c94efc9094d26a4dc4103118d11c7bc56e2f Mon Sep 17 00:00:00 2001
From: Chris Cotter <ccotte...@bloomberg.net>
Date: Thu, 31 Oct 2024 16:59:29 -0400
Subject: [PATCH 04/15] Apply suggestions from code review

Co-authored-by: EugeneZelenko <eugene.zele...@gmail.com>
---
 clang-tools-extra/docs/ReleaseNotes.rst                         | 2 +-
 .../clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst    | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index 98c137a29c13ac..8caa9713fc9b37 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -134,7 +134,7 @@ New checks
 - New :doc:`bugprone-undefined-sprintf-overlap
   <clang-tidy/checks/bugprone/undefined-sprintf-overlap>` check.
 
-  Warns if any arguments to the sprintf family of functions overlap with the
+  Warns if any arguments to the ``sprintf`` family of functions overlap with 
the
   first argument.
 
 - New :doc:`portability-template-virtual-member-function
diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
 
b/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
index 3f6640cb7eec89..eaa10fd0ad6bd3 100644
--- 
a/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
+++ 
b/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
@@ -3,7 +3,7 @@
 bugprone-undefined-sprintf-overlap
 ==================================
 
-Warns if any arguments to the sprintf family of functions overlap with the
+Warns if any arguments to the ``sprintf`` family of functions overlap with the
 first argument.
 
 .. code-block:: c++

>From 75103a2c1b7d6be4284571df3584f201f9e1e431 Mon Sep 17 00:00:00 2001
From: Chris Cotter <ccotte...@bloomberg.net>
Date: Sat, 2 Nov 2024 13:22:58 -0400
Subject: [PATCH 05/15] Remove custom matcher

---
 .../bugprone/UndefinedSprintfOverlapCheck.cpp | 45 +++++++------------
 1 file changed, 17 insertions(+), 28 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
index 043e5d8fc2a29d..f0689fa4f3fee1 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
@@ -14,18 +14,6 @@ using namespace clang::ast_matchers;
 
 namespace clang::tidy::bugprone {
 
-AST_MATCHER_P(CallExpr, hasAnyOtherArgument,
-              ast_matchers::internal::Matcher<Expr>, InnerMatcher) {
-  for (const auto *Arg : llvm::drop_begin(Node.arguments())) {
-    ast_matchers::internal::BoundNodesTreeBuilder Result(*Builder);
-    if (InnerMatcher.matches(*Arg, Finder, &Result)) {
-      *Builder = std::move(Result);
-      return true;
-    }
-  }
-  return false;
-}
-
 AST_MATCHER_P(IntegerLiteral, hasSameValueAs, std::string, ID) {
   return Builder->removeBindings(
       [this, &Node](const ast_matchers::internal::BoundNodesMap &Nodes) {
@@ -43,27 +31,28 @@ UndefinedSprintfOverlapCheck::UndefinedSprintfOverlapCheck(
       SprintfRegex(Options.get("SprintfFunction", "(::std)?::(sn?printf)")) {}
 
 void UndefinedSprintfOverlapCheck::registerMatchers(MatchFinder *Finder) {
-  auto FirstArg = declRefExpr(to(varDecl().bind("firstArg")));
-  auto OtherRefToArg = declRefExpr(to(varDecl(equalsBoundNode("firstArg"))))
+  auto FirstArg = declRefExpr(to(varDecl().bind("firstArgDecl")));
+  auto OtherRefToArg = 
declRefExpr(to(varDecl(equalsBoundNode("firstArgDecl"))))
                            .bind("overlappingArg");
   Finder->addMatcher(
-      callExpr(callee(functionDecl(matchesName(SprintfRegex)).bind("decl")),
-               allOf(hasArgument(
-                         0, anyOf(FirstArg.bind("firstArgExpr"),
+      callExpr(
+          callee(functionDecl(matchesName(SprintfRegex)).bind("decl")),
+          allOf(hasArgument(
+                    0, expr(anyOf(FirstArg,
                                   arraySubscriptExpr(
                                       hasBase(FirstArg),
-                                      hasIndex(integerLiteral().bind("index")))
-                                      .bind("firstArgExpr"),
+                                      
hasIndex(integerLiteral().bind("index"))),
                                   memberExpr(member(decl().bind("member")),
-                                             hasObjectExpression(FirstArg))
-                                      .bind("firstArgExpr"))),
-                     hasAnyOtherArgument(anyOf(
-                         OtherRefToArg,
-                         arraySubscriptExpr(
-                             hasBase(OtherRefToArg),
-                             
hasIndex(integerLiteral(hasSameValueAs("index")))),
-                         memberExpr(member(decl(equalsBoundNode("member"))),
-                                    hasObjectExpression(OtherRefToArg)))))),
+                                             hasObjectExpression(FirstArg))))
+                           .bind("firstArgExpr")),
+                hasAnyArgument(expr(
+                    unless(equalsBoundNode("firstArgExpr")),
+                    anyOf(OtherRefToArg,
+                          arraySubscriptExpr(hasBase(OtherRefToArg),
+                                             hasIndex(integerLiteral(
+                                                 hasSameValueAs("index")))),
+                          memberExpr(member(decl(equalsBoundNode("member"))),
+                                     hasObjectExpression(OtherRefToArg))))))),
       this);
 }
 

>From 84ded5fc966979c55419b3bb32729259d98a6744 Mon Sep 17 00:00:00 2001
From: Chris Cotter <ccotte...@bloomberg.net>
Date: Sat, 4 Jan 2025 21:25:46 -0500
Subject: [PATCH 06/15] Review feedback

---
 .../bugprone/UndefinedSprintfOverlapCheck.cpp | 55 +++++++++----------
 .../bugprone/UndefinedSprintfOverlapCheck.h   |  6 +-
 .../bugprone/undefined-sprintf-overlap.rst    |  2 +-
 .../docs/clang-tidy/checks/list.rst           |  2 +-
 .../bugprone/undefined-sprintf-overlap.cpp    |  4 +-
 5 files changed, 35 insertions(+), 34 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
index f0689fa4f3fee1..82245ebdf4e666 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
@@ -18,9 +18,8 @@ AST_MATCHER_P(IntegerLiteral, hasSameValueAs, std::string, 
ID) {
   return Builder->removeBindings(
       [this, &Node](const ast_matchers::internal::BoundNodesMap &Nodes) {
         const DynTypedNode &BN = Nodes.getNode(ID);
-        if (const auto *Lit = BN.get<IntegerLiteral>()) {
+        if (const auto *Lit = BN.get<IntegerLiteral>())
           return Lit->getValue() != Node.getValue();
-        }
         return true;
       });
 }
@@ -28,50 +27,46 @@ AST_MATCHER_P(IntegerLiteral, hasSameValueAs, std::string, 
ID) {
 UndefinedSprintfOverlapCheck::UndefinedSprintfOverlapCheck(
     StringRef Name, ClangTidyContext *Context)
     : ClangTidyCheck(Name, Context),
-      SprintfRegex(Options.get("SprintfFunction", "(::std)?::(sn?printf)")) {}
+      SprintfRegex(Options.get("SprintfFunction", "(::std)?::sn?printf")) {}
 
 void UndefinedSprintfOverlapCheck::registerMatchers(MatchFinder *Finder) {
   auto FirstArg = declRefExpr(to(varDecl().bind("firstArgDecl")));
-  auto OtherRefToArg = 
declRefExpr(to(varDecl(equalsBoundNode("firstArgDecl"))))
-                           .bind("overlappingArg");
+  auto OtherRefToArg = 
declRefExpr(to(varDecl(equalsBoundNode("firstArgDecl"))));
   Finder->addMatcher(
       callExpr(
           callee(functionDecl(matchesName(SprintfRegex)).bind("decl")),
-          allOf(hasArgument(
-                    0, expr(anyOf(FirstArg,
-                                  arraySubscriptExpr(
-                                      hasBase(FirstArg),
-                                      
hasIndex(integerLiteral().bind("index"))),
-                                  memberExpr(member(decl().bind("member")),
-                                             hasObjectExpression(FirstArg))))
-                           .bind("firstArgExpr")),
-                hasAnyArgument(expr(
-                    unless(equalsBoundNode("firstArgExpr")),
-                    anyOf(OtherRefToArg,
-                          arraySubscriptExpr(hasBase(OtherRefToArg),
-                                             hasIndex(integerLiteral(
-                                                 hasSameValueAs("index")))),
-                          memberExpr(member(decl(equalsBoundNode("member"))),
-                                     hasObjectExpression(OtherRefToArg))))))),
+          hasArgument(
+                  0, expr(anyOf(FirstArg,
+                                arraySubscriptExpr(
+                                    hasBase(FirstArg),
+                                    hasIndex(integerLiteral().bind("index"))),
+                                memberExpr(member(decl().bind("member")),
+                                            hasObjectExpression(FirstArg))))
+                          .bind("firstArgExpr")),
+              hasAnyArgument(expr(
+                  unless(equalsBoundNode("firstArgExpr")),
+                  anyOf(OtherRefToArg,
+                        arraySubscriptExpr(hasBase(OtherRefToArg),
+                                            hasIndex(integerLiteral(
+                                                hasSameValueAs("index")))),
+                        memberExpr(member(decl(equalsBoundNode("member"))),
+                                    
hasObjectExpression(OtherRefToArg)))).bind("secondArgExpr"))),
       this);
 }
 
 void UndefinedSprintfOverlapCheck::check(
     const MatchFinder::MatchResult &Result) {
-  const auto *OverlappingArg =
-      Result.Nodes.getNodeAs<DeclRefExpr>("overlappingArg");
   const auto *FirstArg = Result.Nodes.getNodeAs<Expr>("firstArgExpr");
+  const auto *SecondArg = Result.Nodes.getNodeAs<Expr>("secondArgExpr");
   const auto *FnDecl = Result.Nodes.getNodeAs<FunctionDecl>("decl");
 
-  llvm::StringRef FirstArgText =
-      Lexer::getSourceText(CharSourceRange::getTokenRange(
-                               FirstArg->getBeginLoc(), FirstArg->getEndLoc()),
+  const llvm::StringRef FirstArgText =
+      
Lexer::getSourceText(CharSourceRange::getTokenRange(FirstArg->getSourceRange()),
                            *Result.SourceManager, getLangOpts());
 
-  diag(OverlappingArg->getLocation(),
-       "argument '%0' overlaps the first argument "
-       "in %1, which is undefined behavior")
-      << FirstArgText << FnDecl;
+  diag(SecondArg->getBeginLoc(),
+       "argument '%0' overlaps the first argument in %1, which is undefined 
behavior")
+      << FirstArgText << FnDecl << FirstArg->getSourceRange() << 
SecondArg->getSourceRange();
 }
 
 void UndefinedSprintfOverlapCheck::storeOptions(
diff --git 
a/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.h 
b/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.h
index 349b1156671ff0..e31f1752776df0 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.h
@@ -13,7 +13,8 @@
 
 namespace clang::tidy::bugprone {
 
-/// FIXME: Write a short description.
+/// Warns if any arguments to the ``sprintf`` family of functions overlap with
+/// the destination buffer (the first argument).
 ///
 /// For the user-facing documentation see:
 /// 
http://clang.llvm.org/extra/clang-tidy/checks/bugprone/undefined-sprintf-overlap.html
@@ -26,6 +27,9 @@ class UndefinedSprintfOverlapCheck : public ClangTidyCheck {
   std::optional<TraversalKind> getCheckTraversalKind() const override {
     return TK_IgnoreUnlessSpelledInSource;
   }
+  bool isLanguageVersionSupported(const LangOptions &LangOpts) const override {
+    return LangOpts.CPlusPlus || LangOpts.C99;
+  }
 
 private:
   const std::string SprintfRegex;
diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
 
b/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
index eaa10fd0ad6bd3..2a63e237833189 100644
--- 
a/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
+++ 
b/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
@@ -4,7 +4,7 @@ bugprone-undefined-sprintf-overlap
 ==================================
 
 Warns if any arguments to the ``sprintf`` family of functions overlap with the
-first argument.
+destination buffer (the first argument).
 
 .. code-block:: c++
 
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst 
b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index be26c82800af65..8c169dd59de74d 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -154,7 +154,7 @@ Clang-Tidy Checks
    :doc:`bugprone-too-small-loop-variable <bugprone/too-small-loop-variable>`,
    :doc:`bugprone-unchecked-optional-access 
<bugprone/unchecked-optional-access>`,
    :doc:`bugprone-undefined-memory-manipulation 
<bugprone/undefined-memory-manipulation>`,
-   :doc:`bugprone-undefined-sprintf-overlap 
<bugprone/undefined-sprintf-overlap>`, "Yes"
+   :doc:`bugprone-undefined-sprintf-overlap 
<bugprone/undefined-sprintf-overlap>`
    :doc:`bugprone-undelegated-constructor <bugprone/undelegated-constructor>`,
    :doc:`bugprone-unhandled-exception-at-new 
<bugprone/unhandled-exception-at-new>`,
    :doc:`bugprone-unhandled-self-assignment 
<bugprone/unhandled-self-assignment>`,
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
index 50095346da8a8d..cf844cc537d83d 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
@@ -33,7 +33,9 @@ void first_arg_overlaps() {
   // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: argument 'c' overlaps the first 
argument in 'snprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
 
   char buf2[10];
-  snprintf(buf, sizeof(buf), "%s", buf2);
+  sprintf(buf, "%s", buf2);
+  sprintf(buf, "%s", buf2, buf);
+  // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: argument 'buf' overlaps the 
first argument in 'sprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
 
   st_t st1, st2;
   sprintf(st1.buf, "%s", st1.buf);

>From cefd652381c6cf387bd7487bb46ff76f7b03bc34 Mon Sep 17 00:00:00 2001
From: Chris Cotter <ccotte...@bloomberg.net>
Date: Sat, 4 Jan 2025 21:29:43 -0500
Subject: [PATCH 07/15] Apply suggestions from code review

Co-authored-by: Nicolas van Kempen <nvank...@gmail.com>
---
 .../clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp   | 2 +-
 .../checks/bugprone/undefined-sprintf-overlap.rst          | 7 +++++--
 clang-tools-extra/docs/clang-tidy/checks/list.rst          | 2 +-
 3 files changed, 7 insertions(+), 4 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
index f0689fa4f3fee1..901f18dad53de4 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
@@ -63,7 +63,7 @@ void UndefinedSprintfOverlapCheck::check(
   const auto *FirstArg = Result.Nodes.getNodeAs<Expr>("firstArgExpr");
   const auto *FnDecl = Result.Nodes.getNodeAs<FunctionDecl>("decl");
 
-  llvm::StringRef FirstArgText =
+  const llvm::StringRef FirstArgText =
       Lexer::getSourceText(CharSourceRange::getTokenRange(
                                FirstArg->getBeginLoc(), FirstArg->getEndLoc()),
                            *Result.SourceManager, getLangOpts());
diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
 
b/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
index eaa10fd0ad6bd3..2a9b582db21275 100644
--- 
a/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
+++ 
b/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
@@ -11,8 +11,11 @@ first argument.
     char buf[20] = {"hi"};
     sprintf(buf, "%s%d", buf, 0);
 
-C99 and POSIX.1-2001 states that if copying were to take place between objects
-that overlap, the result is undefined.
+If copying takes place between objects that overlap, the behavior is undefined.
+This is stated in the `C23/N3220 standard
+<https://www.open-std.org/jtc1/sc22/wg14/www/docs/n3096.pdf>`_
+(sections 7.23.6.5 and 7.23.6.6), as well as the `POSIX.1-2024 standard
+<https://pubs.opengroup.org/onlinepubs/9799919799/>`_.
 
 Options
 -------
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst 
b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 41b7d92f94f90c..5b871644921127 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -153,7 +153,7 @@ Clang-Tidy Checks
    :doc:`bugprone-too-small-loop-variable <bugprone/too-small-loop-variable>`,
    :doc:`bugprone-unchecked-optional-access 
<bugprone/unchecked-optional-access>`,
    :doc:`bugprone-undefined-memory-manipulation 
<bugprone/undefined-memory-manipulation>`,
-   :doc:`bugprone-undefined-sprintf-overlap 
<bugprone/undefined-sprintf-overlap>`, "Yes"
+   :doc:`bugprone-undefined-sprintf-overlap 
<bugprone/undefined-sprintf-overlap>`,
    :doc:`bugprone-undelegated-constructor <bugprone/undelegated-constructor>`,
    :doc:`bugprone-unhandled-exception-at-new 
<bugprone/unhandled-exception-at-new>`,
    :doc:`bugprone-unhandled-self-assignment 
<bugprone/unhandled-self-assignment>`,

>From 680b94ed0871bd6e8dc54e5a14fedbfaaf07c557 Mon Sep 17 00:00:00 2001
From: Chris Cotter <ccotte...@bloomberg.net>
Date: Sat, 4 Jan 2025 21:32:29 -0500
Subject: [PATCH 08/15] format

---
 .../bugprone/UndefinedSprintfOverlapCheck.cpp | 45 ++++++++++---------
 1 file changed, 24 insertions(+), 21 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
index 82245ebdf4e666..f916321421c83f 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
@@ -31,26 +31,28 @@ UndefinedSprintfOverlapCheck::UndefinedSprintfOverlapCheck(
 
 void UndefinedSprintfOverlapCheck::registerMatchers(MatchFinder *Finder) {
   auto FirstArg = declRefExpr(to(varDecl().bind("firstArgDecl")));
-  auto OtherRefToArg = 
declRefExpr(to(varDecl(equalsBoundNode("firstArgDecl"))));
+  auto OtherRefToArg =
+      declRefExpr(to(varDecl(equalsBoundNode("firstArgDecl"))));
   Finder->addMatcher(
       callExpr(
           callee(functionDecl(matchesName(SprintfRegex)).bind("decl")),
-          hasArgument(
-                  0, expr(anyOf(FirstArg,
-                                arraySubscriptExpr(
-                                    hasBase(FirstArg),
-                                    hasIndex(integerLiteral().bind("index"))),
-                                memberExpr(member(decl().bind("member")),
+          hasArgument(0,
+                      expr(anyOf(FirstArg,
+                                 arraySubscriptExpr(
+                                     hasBase(FirstArg),
+                                     hasIndex(integerLiteral().bind("index"))),
+                                 memberExpr(member(decl().bind("member")),
                                             hasObjectExpression(FirstArg))))
                           .bind("firstArgExpr")),
-              hasAnyArgument(expr(
-                  unless(equalsBoundNode("firstArgExpr")),
-                  anyOf(OtherRefToArg,
-                        arraySubscriptExpr(hasBase(OtherRefToArg),
-                                            hasIndex(integerLiteral(
-                                                hasSameValueAs("index")))),
-                        memberExpr(member(decl(equalsBoundNode("member"))),
-                                    
hasObjectExpression(OtherRefToArg)))).bind("secondArgExpr"))),
+          hasAnyArgument(
+              expr(unless(equalsBoundNode("firstArgExpr")),
+                   anyOf(OtherRefToArg,
+                         arraySubscriptExpr(
+                             hasBase(OtherRefToArg),
+                             
hasIndex(integerLiteral(hasSameValueAs("index")))),
+                         memberExpr(member(decl(equalsBoundNode("member"))),
+                                    hasObjectExpression(OtherRefToArg))))
+                  .bind("secondArgExpr"))),
       this);
 }
 
@@ -60,13 +62,14 @@ void UndefinedSprintfOverlapCheck::check(
   const auto *SecondArg = Result.Nodes.getNodeAs<Expr>("secondArgExpr");
   const auto *FnDecl = Result.Nodes.getNodeAs<FunctionDecl>("decl");
 
-  const llvm::StringRef FirstArgText =
-      
Lexer::getSourceText(CharSourceRange::getTokenRange(FirstArg->getSourceRange()),
-                           *Result.SourceManager, getLangOpts());
+  const llvm::StringRef FirstArgText = Lexer::getSourceText(
+      CharSourceRange::getTokenRange(FirstArg->getSourceRange()),
+      *Result.SourceManager, getLangOpts());
 
-  diag(SecondArg->getBeginLoc(),
-       "argument '%0' overlaps the first argument in %1, which is undefined 
behavior")
-      << FirstArgText << FnDecl << FirstArg->getSourceRange() << 
SecondArg->getSourceRange();
+  diag(SecondArg->getBeginLoc(), "argument '%0' overlaps the first argument in 
"
+                                 "%1, which is undefined behavior")
+      << FirstArgText << FnDecl << FirstArg->getSourceRange()
+      << SecondArg->getSourceRange();
 }
 
 void UndefinedSprintfOverlapCheck::storeOptions(

>From bb6d7f7c6a43878f144b277bf2b85cf94b3bcf12 Mon Sep 17 00:00:00 2001
From: Chris Cotter <ccotte...@bloomberg.net>
Date: Sat, 4 Jan 2025 21:48:40 -0500
Subject: [PATCH 09/15] Add example of incorrect behavior

---
 .../checks/bugprone/undefined-sprintf-overlap.rst        | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
 
b/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
index 68a2d415d6d56b..ef35dded3335e7 100644
--- 
a/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
+++ 
b/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
@@ -17,6 +17,15 @@ This is stated in the `C23/N3220 standard
 (sections 7.23.6.5 and 7.23.6.6), as well as the `POSIX.1-2024 standard
 <https://pubs.opengroup.org/onlinepubs/9799919799/>`_.
 
+In practice, passing the output buffer to an input argument can result in
+incorrect output. For example, Linux with glibc may produce the following.
+
+.. clode-block:: c++
+   char buf[10];
+   sprintf(buf, "%s", "12");
+   sprintf(buf, "%s%s", "34", buf);
+   printf("%s\n", buf); // prints 3434
+
 Options
 -------
 

>From 32f9d3fce84be0b920418f0e66259f3e71e3dea4 Mon Sep 17 00:00:00 2001
From: Chris Cotter <ccotte...@bloomberg.net>
Date: Sun, 5 Jan 2025 20:42:38 -0500
Subject: [PATCH 10/15] Support more expressions with areStatementsIdentical

---
 .../bugprone/UndefinedSprintfOverlapCheck.cpp | 60 ++++++++++++-------
 .../bugprone/undefined-sprintf-overlap.cpp    | 21 +++++++
 2 files changed, 59 insertions(+), 22 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
index f916321421c83f..5d40b5a3a98a9e 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
@@ -7,6 +7,7 @@
 
//===----------------------------------------------------------------------===//
 
 #include "UndefinedSprintfOverlapCheck.h"
+#include "../utils/ASTUtils.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Lex/Lexer.h"
 
@@ -24,35 +25,40 @@ AST_MATCHER_P(IntegerLiteral, hasSameValueAs, std::string, 
ID) {
       });
 }
 
+// Similar to forEachArgumentWithParam. forEachArgumentWithParam does not work
+// with variadic functions like sprintf, since there is no `decl()` to match
+// against in the parameter list `...`.
+AST_MATCHER_P(CallExpr, forEachArgument, ast_matchers::internal::Matcher<Expr>,
+              ArgMatcher) {
+  using namespace clang::ast_matchers::internal;
+  BoundNodesTreeBuilder Result;
+  int ParamIndex = 0;
+  bool Matched = false;
+  for (unsigned ArgIndex = 0; ArgIndex < Node.getNumArgs(); ++ArgIndex) {
+    BoundNodesTreeBuilder ArgMatches(*Builder);
+    if (ArgMatcher.matches(*(Node.getArg(ArgIndex)->IgnoreParenCasts()), 
Finder,
+                           &ArgMatches)) {
+      BoundNodesTreeBuilder ParamMatches(ArgMatches);
+      Result.addMatch(ArgMatches);
+      Matched = true;
+    }
+    ++ParamIndex;
+  }
+  *Builder = std::move(Result);
+  return Matched;
+}
+
 UndefinedSprintfOverlapCheck::UndefinedSprintfOverlapCheck(
     StringRef Name, ClangTidyContext *Context)
     : ClangTidyCheck(Name, Context),
       SprintfRegex(Options.get("SprintfFunction", "(::std)?::sn?printf")) {}
 
 void UndefinedSprintfOverlapCheck::registerMatchers(MatchFinder *Finder) {
-  auto FirstArg = declRefExpr(to(varDecl().bind("firstArgDecl")));
-  auto OtherRefToArg =
-      declRefExpr(to(varDecl(equalsBoundNode("firstArgDecl"))));
   Finder->addMatcher(
-      callExpr(
-          callee(functionDecl(matchesName(SprintfRegex)).bind("decl")),
-          hasArgument(0,
-                      expr(anyOf(FirstArg,
-                                 arraySubscriptExpr(
-                                     hasBase(FirstArg),
-                                     hasIndex(integerLiteral().bind("index"))),
-                                 memberExpr(member(decl().bind("member")),
-                                            hasObjectExpression(FirstArg))))
-                          .bind("firstArgExpr")),
-          hasAnyArgument(
-              expr(unless(equalsBoundNode("firstArgExpr")),
-                   anyOf(OtherRefToArg,
-                         arraySubscriptExpr(
-                             hasBase(OtherRefToArg),
-                             
hasIndex(integerLiteral(hasSameValueAs("index")))),
-                         memberExpr(member(decl(equalsBoundNode("member"))),
-                                    hasObjectExpression(OtherRefToArg))))
-                  .bind("secondArgExpr"))),
+      callExpr(callee(functionDecl(matchesName(SprintfRegex)).bind("decl")),
+               hasArgument(0, expr().bind("firstArgExpr")),
+               forEachArgument(expr(unless(equalsBoundNode("firstArgExpr")))
+                                   .bind("secondArgExpr"))),
       this);
 }
 
@@ -62,6 +68,16 @@ void UndefinedSprintfOverlapCheck::check(
   const auto *SecondArg = Result.Nodes.getNodeAs<Expr>("secondArgExpr");
   const auto *FnDecl = Result.Nodes.getNodeAs<FunctionDecl>("decl");
 
+  clang::ASTContext &Context = *Result.Context;
+
+  if (!FirstArg || !SecondArg)
+    return;
+
+  if (!utils::areStatementsIdentical(FirstArg, SecondArg, Context))
+    return;
+  if (FirstArg->HasSideEffects(Context) || SecondArg->HasSideEffects(Context))
+    return;
+
   const llvm::StringRef FirstArgText = Lexer::getSourceText(
       CharSourceRange::getTokenRange(FirstArg->getSourceRange()),
       *Result.SourceManager, getLangOpts());
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
index cf844cc537d83d..ae504346a26497 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
@@ -14,6 +14,14 @@ struct st_t {
   char buf2[10];
 };
 
+struct st2_t {
+  st_t inner;
+};
+
+struct st3_t {
+  st2_t inner;
+};
+
 void first_arg_overlaps() {
   char buf[10];
   sprintf(buf, "%s", buf);
@@ -31,6 +39,7 @@ void first_arg_overlaps() {
 
   snprintf(c, sizeof(buf), "%s%s", c, c);
   // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: argument 'c' overlaps the first 
argument in 'snprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  // CHECK-MESSAGES: :[[@LINE-2]]:39: warning: argument 'c' overlaps the first 
argument in 'snprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
 
   char buf2[10];
   sprintf(buf, "%s", buf2);
@@ -43,6 +52,12 @@ void first_arg_overlaps() {
   sprintf(st1.buf, "%s", st1.buf2);
   sprintf(st1.buf, "%s", st2.buf);
 
+  st3_t st3;
+  sprintf(st3.inner.inner.buf, "%s", st3.inner.inner.buf);
+  // CHECK-MESSAGES: :[[@LINE-1]]:38: warning: argument 'st3.inner.inner.buf' 
overlaps the first argument in 'sprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  sprintf((st3.inner.inner.buf), "%s", st3.inner.inner.buf);
+  // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: argument 'st3.inner.inner.buf' 
overlaps the first argument in 'sprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+
   st_t* stp;
   sprintf(stp->buf, "%s", stp->buf);
   // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: argument 'stp->buf' overlaps 
the first argument in 'sprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
@@ -58,4 +73,10 @@ void first_arg_overlaps() {
 
   char bufss[10][10][10];
   sprintf(bufss[0][1], "%s", bufss[0][1]);
+  // CHECK-MESSAGES: :[[@LINE-1]]:30:  warning: argument 'bufss[0][1]' 
overlaps the first argument in 'sprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+
+  sprintf(bufss[0][0], "%s", bufss[0][1]);
+
+  int i = 0;
+  sprintf(bufss[0][++i], "%s", bufss[0][++i]);
 }

>From 357350efcc43ba77131c8b30aae42dc0d32fd499 Mon Sep 17 00:00:00 2001
From: Chris Cotter <ccotte...@bloomberg.net>
Date: Sun, 5 Jan 2025 21:45:34 -0500
Subject: [PATCH 11/15] Use argument number instead of argument text

---
 .../bugprone/UndefinedSprintfOverlapCheck.cpp | 33 ++++++++++++-------
 .../bugprone/undefined-sprintf-overlap.cpp    | 30 ++++++++---------
 2 files changed, 36 insertions(+), 27 deletions(-)

diff --git 
a/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
index 5d40b5a3a98a9e..f7b6cd21c3396e 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
@@ -58,34 +58,43 @@ void 
UndefinedSprintfOverlapCheck::registerMatchers(MatchFinder *Finder) {
       callExpr(callee(functionDecl(matchesName(SprintfRegex)).bind("decl")),
                hasArgument(0, expr().bind("firstArgExpr")),
                forEachArgument(expr(unless(equalsBoundNode("firstArgExpr")))
-                                   .bind("secondArgExpr"))),
+                                   .bind("otherArgExpr")))
+          .bind("call"),
       this);
 }
 
 void UndefinedSprintfOverlapCheck::check(
     const MatchFinder::MatchResult &Result) {
   const auto *FirstArg = Result.Nodes.getNodeAs<Expr>("firstArgExpr");
-  const auto *SecondArg = Result.Nodes.getNodeAs<Expr>("secondArgExpr");
+  const auto *OtherArg = Result.Nodes.getNodeAs<Expr>("otherArgExpr");
+  const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call");
   const auto *FnDecl = Result.Nodes.getNodeAs<FunctionDecl>("decl");
 
   clang::ASTContext &Context = *Result.Context;
 
-  if (!FirstArg || !SecondArg)
+  if (!FirstArg || !OtherArg || !Call || !FnDecl)
     return;
 
-  if (!utils::areStatementsIdentical(FirstArg, SecondArg, Context))
+  if (!utils::areStatementsIdentical(FirstArg, OtherArg, Context))
     return;
-  if (FirstArg->HasSideEffects(Context) || SecondArg->HasSideEffects(Context))
+  if (FirstArg->HasSideEffects(Context) || OtherArg->HasSideEffects(Context))
     return;
 
-  const llvm::StringRef FirstArgText = Lexer::getSourceText(
-      CharSourceRange::getTokenRange(FirstArg->getSourceRange()),
-      *Result.SourceManager, getLangOpts());
+  std::optional<unsigned> ArgNumber;
+  for (unsigned I = 0; I != Call->getNumArgs(); ++I) {
+    if (Call->getArg(I)->IgnoreUnlessSpelledInSource() == OtherArg) {
+      ArgNumber = I;
+      break;
+    }
+  }
+  if (!ArgNumber)
+    return;
 
-  diag(SecondArg->getBeginLoc(), "argument '%0' overlaps the first argument in 
"
-                                 "%1, which is undefined behavior")
-      << FirstArgText << FnDecl << FirstArg->getSourceRange()
-      << SecondArg->getSourceRange();
+  diag(OtherArg->getBeginLoc(),
+       "the %ordinal0 argument in %1 overlaps the 1st argument, "
+       "which is undefined behavior")
+      << *ArgNumber << FnDecl << FirstArg->getSourceRange()
+      << OtherArg->getSourceRange();
 }
 
 void UndefinedSprintfOverlapCheck::storeOptions(
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
index ae504346a26497..284adba70d4683 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
@@ -25,55 +25,55 @@ struct st3_t {
 void first_arg_overlaps() {
   char buf[10];
   sprintf(buf, "%s", buf);
-  // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: argument 'buf' overlaps the 
first argument in 'sprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
   snprintf(buf, sizeof(buf), "%s", buf);
-  // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: argument 'buf' overlaps the 
first argument in 'snprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: the 3rd argument in 'snprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
   std::snprintf(buf, sizeof(buf), "%s", buf);
-  // CHECK-MESSAGES: :[[@LINE-1]]:41: warning: argument 'buf' overlaps the 
first argument in 'snprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  // CHECK-MESSAGES: :[[@LINE-1]]:41: warning: the 3rd argument in 'snprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
 
   char* c = &buf[0];
   sprintf(c, "%s", c);
-  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: argument 'c' overlaps the first 
argument in 'sprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
   snprintf(c, sizeof(buf), "%s", c);
-  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: argument 'c' overlaps the first 
argument in 'snprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: the 3rd argument in 'snprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
 
   snprintf(c, sizeof(buf), "%s%s", c, c);
-  // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: argument 'c' overlaps the first 
argument in 'snprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
-  // CHECK-MESSAGES: :[[@LINE-2]]:39: warning: argument 'c' overlaps the first 
argument in 'snprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: the 3rd argument in 'snprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  // CHECK-MESSAGES: :[[@LINE-2]]:39: warning: the 4th argument in 'snprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
 
   char buf2[10];
   sprintf(buf, "%s", buf2);
   sprintf(buf, "%s", buf2, buf);
-  // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: argument 'buf' overlaps the 
first argument in 'sprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: the 3rd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
 
   st_t st1, st2;
   sprintf(st1.buf, "%s", st1.buf);
-  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: argument 'st1.buf' overlaps the 
first argument in 'sprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
   sprintf(st1.buf, "%s", st1.buf2);
   sprintf(st1.buf, "%s", st2.buf);
 
   st3_t st3;
   sprintf(st3.inner.inner.buf, "%s", st3.inner.inner.buf);
-  // CHECK-MESSAGES: :[[@LINE-1]]:38: warning: argument 'st3.inner.inner.buf' 
overlaps the first argument in 'sprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  // CHECK-MESSAGES: :[[@LINE-1]]:38: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
   sprintf((st3.inner.inner.buf), "%s", st3.inner.inner.buf);
-  // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: argument 'st3.inner.inner.buf' 
overlaps the first argument in 'sprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
 
   st_t* stp;
   sprintf(stp->buf, "%s", stp->buf);
-  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: argument 'stp->buf' overlaps 
the first argument in 'sprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
   sprintf((stp->buf), "%s", stp->buf);
-  // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: argument 'stp->buf' overlaps 
the first argument in 'sprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
   stp = &st1;
   sprintf(stp->buf, "%s", st1.buf);
 
   char bufs[10][10];
   sprintf(bufs[1], "%s", bufs[1]);
-  // CHECK-MESSAGES: :[[@LINE-1]]:26:  warning: argument 'bufs[1]' overlaps 
the first argument in 'sprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  // CHECK-MESSAGES: :[[@LINE-1]]:26:  warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
   sprintf(bufs[0], "%s", bufs[1]);
 
   char bufss[10][10][10];
   sprintf(bufss[0][1], "%s", bufss[0][1]);
-  // CHECK-MESSAGES: :[[@LINE-1]]:30:  warning: argument 'bufss[0][1]' 
overlaps the first argument in 'sprintf', which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  // CHECK-MESSAGES: :[[@LINE-1]]:30:  warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
 
   sprintf(bufss[0][0], "%s", bufss[0][1]);
 

>From 292752be949bdde798b08e62fb3e55424cca1d89 Mon Sep 17 00:00:00 2001
From: Chris Cotter <ccotte...@bloomberg.net>
Date: Sun, 5 Jan 2025 22:11:52 -0500
Subject: [PATCH 12/15] Rename tool

---
 .../bugprone/BugproneTidyModule.cpp           |  6 +-
 .../clang-tidy/bugprone/CMakeLists.txt        |  2 +-
 ...ck.cpp => SprintfArgumentOverlapCheck.cpp} | 12 +--
 ...pCheck.h => SprintfArgumentOverlapCheck.h} | 14 ++--
 clang-tools-extra/docs/ReleaseNotes.rst       |  4 +-
 ...erlap.rst => sprintf-argument-overlap.rst} |  6 +-
 .../docs/clang-tidy/checks/list.rst           |  2 +-
 .../bugprone/sprintf-argument-overlap.cpp     | 82 +++++++++++++++++++
 .../bugprone/undefined-sprintf-overlap.cpp    |  3 +
 9 files changed, 108 insertions(+), 23 deletions(-)
 rename clang-tools-extra/clang-tidy/bugprone/{UndefinedSprintfOverlapCheck.cpp 
=> SprintfArgumentOverlapCheck.cpp} (90%)
 rename clang-tools-extra/clang-tidy/bugprone/{UndefinedSprintfOverlapCheck.h 
=> SprintfArgumentOverlapCheck.h} (67%)
 rename 
clang-tools-extra/docs/clang-tidy/checks/bugprone/{undefined-sprintf-overlap.rst
 => sprintf-argument-overlap.rst} (88%)
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/sprintf-argument-overlap.cpp

diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp 
b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index a85458bf49255c..b229753e0b86a3 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -86,7 +86,7 @@
 #include "TooSmallLoopVariableCheck.h"
 #include "UncheckedOptionalAccessCheck.h"
 #include "UndefinedMemoryManipulationCheck.h"
-#include "UndefinedSprintfOverlapCheck.h"
+#include "SprintfArgumentOverlapCheck.h"
 #include "UndelegatedConstructorCheck.h"
 #include "UnhandledExceptionAtNewCheck.h"
 #include "UnhandledSelfAssignmentCheck.h"
@@ -249,8 +249,8 @@ class BugproneModule : public ClangTidyModule {
         "bugprone-unchecked-optional-access");
     CheckFactories.registerCheck<UndefinedMemoryManipulationCheck>(
         "bugprone-undefined-memory-manipulation");
-    CheckFactories.registerCheck<UndefinedSprintfOverlapCheck>(
-        "bugprone-undefined-sprintf-overlap");
+    CheckFactories.registerCheck<SprintfArgumentOverlapCheck>(
+        "bugprone-sprintf-argument-overlap");
     CheckFactories.registerCheck<UndelegatedConstructorCheck>(
         "bugprone-undelegated-constructor");
     CheckFactories.registerCheck<UnhandledSelfAssignmentCheck>(
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index 9efadc0c08751c..dd818866f56b3d 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -83,7 +83,7 @@ add_clang_library(clangTidyBugproneModule STATIC
   TooSmallLoopVariableCheck.cpp
   UncheckedOptionalAccessCheck.cpp
   UndefinedMemoryManipulationCheck.cpp
-  UndefinedSprintfOverlapCheck.cpp
+  SprintfArgumentOverlapCheck.cpp
   UndelegatedConstructorCheck.cpp
   UnhandledExceptionAtNewCheck.cpp
   UnhandledSelfAssignmentCheck.cpp
diff --git 
a/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/SprintfArgumentOverlapCheck.cpp
similarity index 90%
rename from 
clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
rename to clang-tools-extra/clang-tidy/bugprone/SprintfArgumentOverlapCheck.cpp
index f7b6cd21c3396e..6d86279191492a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/SprintfArgumentOverlapCheck.cpp
@@ -1,4 +1,4 @@
-//===--- UndefinedSprintfOverlapCheck.cpp - clang-tidy 
--------------------===//
+//===--- SprintfArgumentOverlapCheck.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.
@@ -6,7 +6,7 @@
 //
 
//===----------------------------------------------------------------------===//
 
-#include "UndefinedSprintfOverlapCheck.h"
+#include "SprintfArgumentOverlapCheck.h"
 #include "../utils/ASTUtils.h"
 #include "clang/ASTMatchers/ASTMatchFinder.h"
 #include "clang/Lex/Lexer.h"
@@ -48,12 +48,12 @@ AST_MATCHER_P(CallExpr, forEachArgument, 
ast_matchers::internal::Matcher<Expr>,
   return Matched;
 }
 
-UndefinedSprintfOverlapCheck::UndefinedSprintfOverlapCheck(
+SprintfArgumentOverlapCheck::SprintfArgumentOverlapCheck(
     StringRef Name, ClangTidyContext *Context)
     : ClangTidyCheck(Name, Context),
       SprintfRegex(Options.get("SprintfFunction", "(::std)?::sn?printf")) {}
 
-void UndefinedSprintfOverlapCheck::registerMatchers(MatchFinder *Finder) {
+void SprintfArgumentOverlapCheck::registerMatchers(MatchFinder *Finder) {
   Finder->addMatcher(
       callExpr(callee(functionDecl(matchesName(SprintfRegex)).bind("decl")),
                hasArgument(0, expr().bind("firstArgExpr")),
@@ -63,7 +63,7 @@ void 
UndefinedSprintfOverlapCheck::registerMatchers(MatchFinder *Finder) {
       this);
 }
 
-void UndefinedSprintfOverlapCheck::check(
+void SprintfArgumentOverlapCheck::check(
     const MatchFinder::MatchResult &Result) {
   const auto *FirstArg = Result.Nodes.getNodeAs<Expr>("firstArgExpr");
   const auto *OtherArg = Result.Nodes.getNodeAs<Expr>("otherArgExpr");
@@ -97,7 +97,7 @@ void UndefinedSprintfOverlapCheck::check(
       << OtherArg->getSourceRange();
 }
 
-void UndefinedSprintfOverlapCheck::storeOptions(
+void SprintfArgumentOverlapCheck::storeOptions(
     ClangTidyOptions::OptionMap &Opts) {
   Options.store(Opts, "SprintfRegex", SprintfRegex);
 }
diff --git 
a/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.h 
b/clang-tools-extra/clang-tidy/bugprone/SprintfArgumentOverlapCheck.h
similarity index 67%
rename from clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.h
rename to clang-tools-extra/clang-tidy/bugprone/SprintfArgumentOverlapCheck.h
index e31f1752776df0..58d8e9cfb022ba 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UndefinedSprintfOverlapCheck.h
+++ b/clang-tools-extra/clang-tidy/bugprone/SprintfArgumentOverlapCheck.h
@@ -1,4 +1,4 @@
-//===--- UndefinedSprintfOverlapCheck.h - clang-tidy ------------*- C++ 
-*-===//
+//===--- SprintfArgumentOverlapCheck.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.
@@ -6,8 +6,8 @@
 //
 
//===----------------------------------------------------------------------===//
 
-#ifndef 
LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNDEFINEDSPRINTFOVERLAPCHECK_H
-#define 
LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNDEFINEDSPRINTFOVERLAPCHECK_H
+#ifndef 
LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SPRINTFARGUMENTOVERLAPCHECK_H
+#define 
LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SPRINTFARGUMENTOVERLAPCHECK_H
 
 #include "../ClangTidyCheck.h"
 
@@ -17,10 +17,10 @@ namespace clang::tidy::bugprone {
 /// the destination buffer (the first argument).
 ///
 /// For the user-facing documentation see:
-/// 
http://clang.llvm.org/extra/clang-tidy/checks/bugprone/undefined-sprintf-overlap.html
-class UndefinedSprintfOverlapCheck : public ClangTidyCheck {
+/// 
http://clang.llvm.org/extra/clang-tidy/checks/bugprone/sprintf-argument-overlap.html
+class SprintfArgumentOverlapCheck : public ClangTidyCheck {
 public:
-  UndefinedSprintfOverlapCheck(StringRef Name, ClangTidyContext *Context);
+  SprintfArgumentOverlapCheck(StringRef Name, ClangTidyContext *Context);
   void registerMatchers(ast_matchers::MatchFinder *Finder) override;
   void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
   void storeOptions(ClangTidyOptions::OptionMap &Opts) override;
@@ -37,4 +37,4 @@ class UndefinedSprintfOverlapCheck : public ClangTidyCheck {
 
 } // namespace clang::tidy::bugprone
 
-#endif // 
LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNDEFINEDSPRINTFOVERLAPCHECK_H
+#endif // 
LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SPRINTFARGUMENTOVERLAPCHECK_H
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst 
b/clang-tools-extra/docs/ReleaseNotes.rst
index ad60ce3d6ae9d1..a366896ebb23a8 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -157,8 +157,8 @@ New checks
   Gives warnings for tagged unions, where the number of tags is
   different from the number of data members inside the union.
 
-- New :doc:`bugprone-undefined-sprintf-overlap
-  <clang-tidy/checks/bugprone/undefined-sprintf-overlap>` check.
+- New :doc:`bugprone-sprintf-argument-overlap
+  <clang-tidy/checks/bugprone/sprintf-argument-overlap>` check.
 
   Warns if any arguments to the ``sprintf`` family of functions overlap with 
the
   first argument.
diff --git 
a/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
 
b/clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-argument-overlap.rst
similarity index 88%
rename from 
clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
rename to 
clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-argument-overlap.rst
index ef35dded3335e7..315683f1f99588 100644
--- 
a/clang-tools-extra/docs/clang-tidy/checks/bugprone/undefined-sprintf-overlap.rst
+++ 
b/clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-argument-overlap.rst
@@ -1,7 +1,7 @@
-.. title:: clang-tidy - bugprone-undefined-sprintf-overlap
+.. title:: clang-tidy - bugprone-sprintf-argument-overlap
 
-bugprone-undefined-sprintf-overlap
-==================================
+bugprone-sprintf-argument-overlap
+=================================
 
 Warns if any arguments to the ``sprintf`` family of functions overlap with the
 destination buffer (the first argument).
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst 
b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 765b152ff10b8b..6c8f3b1d7469c6 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -154,7 +154,7 @@ Clang-Tidy Checks
    :doc:`bugprone-too-small-loop-variable <bugprone/too-small-loop-variable>`,
    :doc:`bugprone-unchecked-optional-access 
<bugprone/unchecked-optional-access>`,
    :doc:`bugprone-undefined-memory-manipulation 
<bugprone/undefined-memory-manipulation>`,
-   :doc:`bugprone-undefined-sprintf-overlap 
<bugprone/undefined-sprintf-overlap>`,
+   :doc:`bugprone-sprintf-argument-overlap 
<bugprone/sprintf-argument-overlap>`,
    :doc:`bugprone-undelegated-constructor <bugprone/undelegated-constructor>`,
    :doc:`bugprone-unhandled-exception-at-new 
<bugprone/unhandled-exception-at-new>`,
    :doc:`bugprone-unhandled-self-assignment 
<bugprone/unhandled-self-assignment>`,
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/sprintf-argument-overlap.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/sprintf-argument-overlap.cpp
new file mode 100644
index 00000000000000..ec0d2c9e00ae75
--- /dev/null
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/sprintf-argument-overlap.cpp
@@ -0,0 +1,82 @@
+// RUN: %check_clang_tidy %s bugprone-sprintf-argument-overlap %t
+
+using size_t = decltype(sizeof(int));
+
+extern "C" int sprintf(char *s, const char *format, ...);
+extern "C" int snprintf(char *s, size_t n, const char *format, ...);
+
+namespace std {
+  int snprintf(char *s, size_t n, const char *format, ...);
+}
+
+struct st_t {
+  char buf[10];
+  char buf2[10];
+};
+
+struct st2_t {
+  st_t inner;
+};
+
+struct st3_t {
+  st2_t inner;
+};
+
+void first_arg_overlaps() {
+  char buf[10];
+  sprintf(buf, "%s", buf);
+  // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-sprintf-argument-overlap]
+  snprintf(buf, sizeof(buf), "%s", buf);
+  // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: the 3rd argument in 'snprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-sprintf-argument-overlap]
+  std::snprintf(buf, sizeof(buf), "%s", buf);
+  // CHECK-MESSAGES: :[[@LINE-1]]:41: warning: the 3rd argument in 'snprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-sprintf-argument-overlap]
+
+  char* c = &buf[0];
+  sprintf(c, "%s", c);
+  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-sprintf-argument-overlap]
+  snprintf(c, sizeof(buf), "%s", c);
+  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: the 3rd argument in 'snprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-sprintf-argument-overlap]
+
+  snprintf(c, sizeof(buf), "%s%s", c, c);
+  // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: the 3rd argument in 'snprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-sprintf-argument-overlap]
+  // CHECK-MESSAGES: :[[@LINE-2]]:39: warning: the 4th argument in 'snprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-sprintf-argument-overlap]
+
+  char buf2[10];
+  sprintf(buf, "%s", buf2);
+  sprintf(buf, "%s", buf2, buf);
+  // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: the 3rd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-sprintf-argument-overlap]
+
+  st_t st1, st2;
+  sprintf(st1.buf, "%s", st1.buf);
+  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-sprintf-argument-overlap]
+  sprintf(st1.buf, "%s", st1.buf2);
+  sprintf(st1.buf, "%s", st2.buf);
+
+  st3_t st3;
+  sprintf(st3.inner.inner.buf, "%s", st3.inner.inner.buf);
+  // CHECK-MESSAGES: :[[@LINE-1]]:38: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-sprintf-argument-overlap]
+  sprintf((st3.inner.inner.buf), "%s", st3.inner.inner.buf);
+  // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-sprintf-argument-overlap]
+
+  st_t* stp;
+  sprintf(stp->buf, "%s", stp->buf);
+  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-sprintf-argument-overlap]
+  sprintf((stp->buf), "%s", stp->buf);
+  // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-sprintf-argument-overlap]
+  stp = &st1;
+  sprintf(stp->buf, "%s", st1.buf);
+
+  char bufs[10][10];
+  sprintf(bufs[1], "%s", bufs[1]);
+  // CHECK-MESSAGES: :[[@LINE-1]]:26:  warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-sprintf-argument-overlap]
+  sprintf(bufs[0], "%s", bufs[1]);
+
+  char bufss[10][10][10];
+  sprintf(bufss[0][1], "%s", bufss[0][1]);
+  // CHECK-MESSAGES: :[[@LINE-1]]:30:  warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-sprintf-argument-overlap]
+
+  sprintf(bufss[0][0], "%s", bufss[0][1]);
+
+  int i = 0;
+  sprintf(bufss[0][++i], "%s", bufss[0][++i]);
+}
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
index 284adba70d4683..5686a1b9278d46 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
@@ -30,6 +30,9 @@ void first_arg_overlaps() {
   // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: the 3rd argument in 'snprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
   std::snprintf(buf, sizeof(buf), "%s", buf);
   // CHECK-MESSAGES: :[[@LINE-1]]:41: warning: the 3rd argument in 'snprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  sprintf(buf+1, "%s", (buf+1));
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
+  sprintf(buf+1, "%s", buf+2);
 
   char* c = &buf[0];
   sprintf(c, "%s", c);

>From 3e1abf85468419615108f3e3173ebd61e3b28cee Mon Sep 17 00:00:00 2001
From: Chris Cotter <ccotte...@bloomberg.net>
Date: Sun, 5 Jan 2025 22:16:10 -0500
Subject: [PATCH 13/15] tidy up

---
 clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp    | 2 +-
 .../clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp  | 1 +
 2 files changed, 2 insertions(+), 1 deletion(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp 
b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index b229753e0b86a3..fc69390766415a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -63,6 +63,7 @@
 #include "SignedCharMisuseCheck.h"
 #include "SizeofContainerCheck.h"
 #include "SizeofExpressionCheck.h"
+#include "SprintfArgumentOverlapCheck.h"
 #include "SpuriouslyWakeUpFunctionsCheck.h"
 #include "StandaloneEmptyCheck.h"
 #include "StringConstructorCheck.h"
@@ -86,7 +87,6 @@
 #include "TooSmallLoopVariableCheck.h"
 #include "UncheckedOptionalAccessCheck.h"
 #include "UndefinedMemoryManipulationCheck.h"
-#include "SprintfArgumentOverlapCheck.h"
 #include "UndelegatedConstructorCheck.h"
 #include "UnhandledExceptionAtNewCheck.h"
 #include "UnhandledSelfAssignmentCheck.h"
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
index 5686a1b9278d46..b613497a472311 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
@@ -33,6 +33,7 @@ void first_arg_overlaps() {
   sprintf(buf+1, "%s", (buf+1));
   // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
   sprintf(buf+1, "%s", buf+2);
+  sprintf(buf+1, "%s", buf[1]);
 
   char* c = &buf[0];
   sprintf(c, "%s", c);

>From c8f57642d5ba4f70ee9c05f85575c22c8c7e74fa Mon Sep 17 00:00:00 2001
From: Chris Cotter <ccotte...@bloomberg.net>
Date: Sun, 5 Jan 2025 23:04:43 -0500
Subject: [PATCH 14/15] Fix rename operation

---
 .../bugprone/sprintf-argument-overlap.cpp     |  4 +
 .../bugprone/undefined-sprintf-overlap.cpp    | 86 -------------------
 2 files changed, 4 insertions(+), 86 deletions(-)
 delete mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp

diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/sprintf-argument-overlap.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/sprintf-argument-overlap.cpp
index ec0d2c9e00ae75..0726efed7b0a03 100644
--- 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/sprintf-argument-overlap.cpp
+++ 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/sprintf-argument-overlap.cpp
@@ -30,6 +30,10 @@ void first_arg_overlaps() {
   // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: the 3rd argument in 'snprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-sprintf-argument-overlap]
   std::snprintf(buf, sizeof(buf), "%s", buf);
   // CHECK-MESSAGES: :[[@LINE-1]]:41: warning: the 3rd argument in 'snprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-sprintf-argument-overlap]
+  sprintf(buf+1, "%s", (buf+1));
+  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-sprintf-argument-overlap]
+  sprintf(buf+1, "%s", buf+2);
+  sprintf(buf+1, "%s", buf[1]);
 
   char* c = &buf[0];
   sprintf(c, "%s", c);
diff --git 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
 
b/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
deleted file mode 100644
index b613497a472311..00000000000000
--- 
a/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-// RUN: %check_clang_tidy %s bugprone-undefined-sprintf-overlap %t
-
-using size_t = decltype(sizeof(int));
-
-extern "C" int sprintf(char *s, const char *format, ...);
-extern "C" int snprintf(char *s, size_t n, const char *format, ...);
-
-namespace std {
-  int snprintf(char *s, size_t n, const char *format, ...);
-}
-
-struct st_t {
-  char buf[10];
-  char buf2[10];
-};
-
-struct st2_t {
-  st_t inner;
-};
-
-struct st3_t {
-  st2_t inner;
-};
-
-void first_arg_overlaps() {
-  char buf[10];
-  sprintf(buf, "%s", buf);
-  // CHECK-MESSAGES: :[[@LINE-1]]:22: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
-  snprintf(buf, sizeof(buf), "%s", buf);
-  // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: the 3rd argument in 'snprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
-  std::snprintf(buf, sizeof(buf), "%s", buf);
-  // CHECK-MESSAGES: :[[@LINE-1]]:41: warning: the 3rd argument in 'snprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
-  sprintf(buf+1, "%s", (buf+1));
-  // CHECK-MESSAGES: :[[@LINE-1]]:24: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
-  sprintf(buf+1, "%s", buf+2);
-  sprintf(buf+1, "%s", buf[1]);
-
-  char* c = &buf[0];
-  sprintf(c, "%s", c);
-  // CHECK-MESSAGES: :[[@LINE-1]]:20: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
-  snprintf(c, sizeof(buf), "%s", c);
-  // CHECK-MESSAGES: :[[@LINE-1]]:34: warning: the 3rd argument in 'snprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
-
-  snprintf(c, sizeof(buf), "%s%s", c, c);
-  // CHECK-MESSAGES: :[[@LINE-1]]:36: warning: the 3rd argument in 'snprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
-  // CHECK-MESSAGES: :[[@LINE-2]]:39: warning: the 4th argument in 'snprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
-
-  char buf2[10];
-  sprintf(buf, "%s", buf2);
-  sprintf(buf, "%s", buf2, buf);
-  // CHECK-MESSAGES: :[[@LINE-1]]:28: warning: the 3rd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
-
-  st_t st1, st2;
-  sprintf(st1.buf, "%s", st1.buf);
-  // CHECK-MESSAGES: :[[@LINE-1]]:26: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
-  sprintf(st1.buf, "%s", st1.buf2);
-  sprintf(st1.buf, "%s", st2.buf);
-
-  st3_t st3;
-  sprintf(st3.inner.inner.buf, "%s", st3.inner.inner.buf);
-  // CHECK-MESSAGES: :[[@LINE-1]]:38: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
-  sprintf((st3.inner.inner.buf), "%s", st3.inner.inner.buf);
-  // CHECK-MESSAGES: :[[@LINE-1]]:40: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
-
-  st_t* stp;
-  sprintf(stp->buf, "%s", stp->buf);
-  // CHECK-MESSAGES: :[[@LINE-1]]:27: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
-  sprintf((stp->buf), "%s", stp->buf);
-  // CHECK-MESSAGES: :[[@LINE-1]]:29: warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
-  stp = &st1;
-  sprintf(stp->buf, "%s", st1.buf);
-
-  char bufs[10][10];
-  sprintf(bufs[1], "%s", bufs[1]);
-  // CHECK-MESSAGES: :[[@LINE-1]]:26:  warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
-  sprintf(bufs[0], "%s", bufs[1]);
-
-  char bufss[10][10][10];
-  sprintf(bufss[0][1], "%s", bufss[0][1]);
-  // CHECK-MESSAGES: :[[@LINE-1]]:30:  warning: the 2nd argument in 'sprintf' 
overlaps the 1st argument, which is undefined behavior 
[bugprone-undefined-sprintf-overlap]
-
-  sprintf(bufss[0][0], "%s", bufss[0][1]);
-
-  int i = 0;
-  sprintf(bufss[0][++i], "%s", bufss[0][++i]);
-}

>From a699e1d7d2e90ba6c5ee16a9d4a42bd496577b70 Mon Sep 17 00:00:00 2001
From: Chris Cotter <ccotte...@bloomberg.net>
Date: Sun, 5 Jan 2025 23:08:01 -0500
Subject: [PATCH 15/15] Fix sort

---
 clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp | 4 ++--
 clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt         | 2 +-
 clang-tools-extra/docs/clang-tidy/checks/list.rst            | 2 +-
 3 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp 
b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index fc69390766415a..fe6cc78d32f4eb 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -205,6 +205,8 @@ class BugproneModule : public ClangTidyModule {
         "bugprone-sizeof-container");
     CheckFactories.registerCheck<SizeofExpressionCheck>(
         "bugprone-sizeof-expression");
+    CheckFactories.registerCheck<SprintfArgumentOverlapCheck>(
+        "bugprone-sprintf-argument-overlap");
     CheckFactories.registerCheck<SpuriouslyWakeUpFunctionsCheck>(
         "bugprone-spuriously-wake-up-functions");
     CheckFactories.registerCheck<StandaloneEmptyCheck>(
@@ -249,8 +251,6 @@ class BugproneModule : public ClangTidyModule {
         "bugprone-unchecked-optional-access");
     CheckFactories.registerCheck<UndefinedMemoryManipulationCheck>(
         "bugprone-undefined-memory-manipulation");
-    CheckFactories.registerCheck<SprintfArgumentOverlapCheck>(
-        "bugprone-sprintf-argument-overlap");
     CheckFactories.registerCheck<UndelegatedConstructorCheck>(
         "bugprone-undelegated-constructor");
     CheckFactories.registerCheck<UnhandledSelfAssignmentCheck>(
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index dd818866f56b3d..3ae2afb6de6e44 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -60,6 +60,7 @@ add_clang_library(clangTidyBugproneModule STATIC
   SizeofContainerCheck.cpp
   SizeofExpressionCheck.cpp
   SmartPtrArrayMismatchCheck.cpp
+  SprintfArgumentOverlapCheck.cpp
   SpuriouslyWakeUpFunctionsCheck.cpp
   StandaloneEmptyCheck.cpp
   StringConstructorCheck.cpp
@@ -83,7 +84,6 @@ add_clang_library(clangTidyBugproneModule STATIC
   TooSmallLoopVariableCheck.cpp
   UncheckedOptionalAccessCheck.cpp
   UndefinedMemoryManipulationCheck.cpp
-  SprintfArgumentOverlapCheck.cpp
   UndelegatedConstructorCheck.cpp
   UnhandledExceptionAtNewCheck.cpp
   UnhandledSelfAssignmentCheck.cpp
diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst 
b/clang-tools-extra/docs/clang-tidy/checks/list.rst
index 6c8f3b1d7469c6..f8626305716f92 100644
--- a/clang-tools-extra/docs/clang-tidy/checks/list.rst
+++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst
@@ -131,6 +131,7 @@ Clang-Tidy Checks
    :doc:`bugprone-signed-char-misuse <bugprone/signed-char-misuse>`,
    :doc:`bugprone-sizeof-container <bugprone/sizeof-container>`,
    :doc:`bugprone-sizeof-expression <bugprone/sizeof-expression>`,
+   :doc:`bugprone-sprintf-argument-overlap 
<bugprone/sprintf-argument-overlap>`,
    :doc:`bugprone-spuriously-wake-up-functions 
<bugprone/spuriously-wake-up-functions>`,
    :doc:`bugprone-standalone-empty <bugprone/standalone-empty>`, "Yes"
    :doc:`bugprone-string-constructor <bugprone/string-constructor>`, "Yes"
@@ -154,7 +155,6 @@ Clang-Tidy Checks
    :doc:`bugprone-too-small-loop-variable <bugprone/too-small-loop-variable>`,
    :doc:`bugprone-unchecked-optional-access 
<bugprone/unchecked-optional-access>`,
    :doc:`bugprone-undefined-memory-manipulation 
<bugprone/undefined-memory-manipulation>`,
-   :doc:`bugprone-sprintf-argument-overlap 
<bugprone/sprintf-argument-overlap>`,
    :doc:`bugprone-undelegated-constructor <bugprone/undelegated-constructor>`,
    :doc:`bugprone-unhandled-exception-at-new 
<bugprone/unhandled-exception-at-new>`,
    :doc:`bugprone-unhandled-self-assignment 
<bugprone/unhandled-self-assignment>`,

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to