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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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/12] 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 186e7e386d799c12c035a878eb93c6daa122a8e8 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/12] 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 +- ...erlap.cpp => sprintf-argument-overlap.cpp} | 32 +++++++++---------- 8 files changed, 39 insertions(+), 39 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%) rename clang-tools-extra/test/clang-tidy/checkers/bugprone/{undefined-sprintf-overlap.cpp => sprintf-argument-overlap.cpp} (82%) 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/undefined-sprintf-overlap.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/sprintf-argument-overlap.cpp similarity index 82% rename from clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp rename to clang-tools-extra/test/clang-tidy/checkers/bugprone/sprintf-argument-overlap.cpp index 284adba70d4683..ec0d2c9e00ae75 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/undefined-sprintf-overlap.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/sprintf-argument-overlap.cpp @@ -1,4 +1,4 @@ -// RUN: %check_clang_tidy %s bugprone-undefined-sprintf-overlap %t +// RUN: %check_clang_tidy %s bugprone-sprintf-argument-overlap %t using size_t = decltype(sizeof(int)); @@ -25,55 +25,55 @@ struct st3_t { 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] + // 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-undefined-sprintf-overlap] + // 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-undefined-sprintf-overlap] + // 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-undefined-sprintf-overlap] + // 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-undefined-sprintf-overlap] + // 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-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] + // 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-undefined-sprintf-overlap] + // 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-undefined-sprintf-overlap] + // 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-undefined-sprintf-overlap] + // 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-undefined-sprintf-overlap] + // 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-undefined-sprintf-overlap] + // 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-undefined-sprintf-overlap] + // 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-undefined-sprintf-overlap] + // 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-undefined-sprintf-overlap] + // 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]); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits