https://github.com/ThanSin02426 updated https://github.com/llvm/llvm-project/pull/182823
>From 380554139e77ce83bb0c998273e7cae094d3c101 Mon Sep 17 00:00:00 2001 From: ThanSin02426 <[email protected]> Date: Mon, 23 Feb 2026 14:58:47 +0530 Subject: [PATCH 1/6] [clang-tidy] Add bugprone-sprintf-to-snprintf check This check finds calls to sprintf where the first argument is a fixed-size array and suggests replacing them with snprintf. Fixes #40511 --- .../bugprone/BugproneTidyModule.cpp | 3 ++ .../clang-tidy/bugprone/CMakeLists.txt | 1 + .../bugprone/SprintfToSnprintfCheck.cpp | 48 +++++++++++++++++++ .../bugprone/SprintfToSnprintfCheck.h | 33 +++++++++++++ clang-tools-extra/docs/ReleaseNotes.rst | 6 +++ .../checks/bugprone/sprintf-to-snprintf.rst | 27 +++++++++++ .../docs/clang-tidy/checks/list.rst | 1 + .../checkers/bugprone/sprintf-to-snprintf.cpp | 16 +++++++ 8 files changed, 135 insertions(+) create mode 100644 clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.cpp create mode 100644 clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.h create mode 100644 clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-to-snprintf.rst create mode 100644 clang-tools-extra/test/clang-tidy/checkers/bugprone/sprintf-to-snprintf.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp index 4150442c25d61..46d58b984f97d 100644 --- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp @@ -74,6 +74,7 @@ #include "SignedCharMisuseCheck.h" #include "SizeofContainerCheck.h" #include "SizeofExpressionCheck.h" +#include "SprintfToSnprintfCheck.h" #include "SpuriouslyWakeUpFunctionsCheck.h" #include "StandaloneEmptyCheck.h" #include "StdNamespaceModificationCheck.h" @@ -176,6 +177,8 @@ class BugproneModule : public ClangTidyModule { "bugprone-incorrect-enable-if"); CheckFactories.registerCheck<IncorrectEnableSharedFromThisCheck>( "bugprone-incorrect-enable-shared-from-this"); + CheckFactories.registerCheck<SprintfToSnprintfCheck>( + "bugprone-sprintf-to-snprintf"); CheckFactories.registerCheck<UnintendedCharOstreamOutputCheck>( "bugprone-unintended-char-ostream-output"); CheckFactories.registerCheck<ReturnConstRefFromParameterCheck>( diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt index db1256d91d311..21f3c5f00f12f 100644 --- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt +++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt @@ -37,6 +37,7 @@ add_clang_library(clangTidyBugproneModule STATIC IncorrectEnableIfCheck.cpp IncorrectEnableSharedFromThisCheck.cpp InvalidEnumDefaultInitializationCheck.cpp + SprintfToSnprintfCheck.cpp UnintendedCharOstreamOutputCheck.cpp ReturnConstRefFromParameterCheck.cpp SuspiciousStringviewDataUsageCheck.cpp diff --git a/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.cpp new file mode 100644 index 0000000000000..e357beb3e182e --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.cpp @@ -0,0 +1,48 @@ +//===----------------------------------------------------------------------===// +// +// 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 "SprintfToSnprintfCheck.h" +#include "clang/ASTMatchers/ASTMatchFinder.h" + +using namespace clang::ast_matchers; + +namespace clang::tidy::bugprone { + +void SprintfToSnprintfCheck::registerMatchers(MatchFinder *Finder) { + Finder->addMatcher( + callExpr( + callee(functionDecl(hasName("::sprintf"))), + hasArgument( + 0, ignoringParenImpCasts(declRefExpr(to( + varDecl(hasType(constantArrayType())).bind("buffer") + )).bind("arg0")) + ) + ).bind("call"), + this); +} + +void SprintfToSnprintfCheck::check(const MatchFinder::MatchResult &Result) { + const auto *Call = Result.Nodes.getNodeAs<CallExpr>("call"); + const auto *Buffer = Result.Nodes.getNodeAs<VarDecl>("buffer"); + + if (!Call || !Buffer) + return; + + StringRef BufferName = Buffer->getName(); + + auto Diag = diag(Call->getBeginLoc(), "use 'snprintf' instead of 'sprintf' for fixed-size character arrays"); + + SourceLocation FuncNameLoc = Call->getExprLoc(); + Diag << FixItHint::CreateReplacement(FuncNameLoc, "snprintf"); + + SourceLocation InsertLoc = Call->getArg(1)->getBeginLoc(); + std::string SizeArg = "sizeof(" + BufferName.str() + "), "; + Diag << FixItHint::CreateInsertion(InsertLoc, SizeArg); +} + +} // namespace clang::tidy::bugprone diff --git a/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.h b/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.h new file mode 100644 index 0000000000000..2a9b4dd3c3041 --- /dev/null +++ b/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.h @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// 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_SPRINTFTOSNPRINTFCHECK_H +#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SPRINTFTOSNPRINTFCHECK_H + +#include "../ClangTidyCheck.h" + +namespace clang::tidy::bugprone { + +/// FIXME: Write a short description. +/// +/// For the user-facing documentation see: +/// https://clang.llvm.org/extra/clang-tidy/checks/bugprone/sprintf-to-snprintf.html +class SprintfToSnprintfCheck : public ClangTidyCheck { +public: + SprintfToSnprintfCheck(StringRef Name, ClangTidyContext *Context) + : ClangTidyCheck(Name, Context) {} + void registerMatchers(ast_matchers::MatchFinder *Finder) override; + void check(const ast_matchers::MatchFinder::MatchResult &Result) override; + bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { + return LangOpts.CPlusPlus; + } +}; + +} // namespace clang::tidy::bugprone + +#endif // LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SPRINTFTOSNPRINTFCHECK_H diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst index e7437e62ee77d..23757aefb13e2 100644 --- a/clang-tools-extra/docs/ReleaseNotes.rst +++ b/clang-tools-extra/docs/ReleaseNotes.rst @@ -97,6 +97,12 @@ Improvements to clang-tidy New checks ^^^^^^^^^^ +- New :doc:`bugprone-sprintf-to-snprintf + <clang-tidy/checks/bugprone/sprintf-to-snprintf>` check. + + Finds calls to ``sprintf`` where the destination is a fixed-size character + array and suggests replacing them with the safer ``snprintf``. + - New :doc:`llvm-type-switch-case-types <clang-tidy/checks/llvm/type-switch-case-types>` check. diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-to-snprintf.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-to-snprintf.rst new file mode 100644 index 0000000000000..dc57e1736f3bd --- /dev/null +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-to-snprintf.rst @@ -0,0 +1,27 @@ +.. title:: clang-tidy - bugprone-sprintf-to-snprintf + +bugprone-sprintf-to-snprintf +============================ + +Finds calls to ``sprintf`` where the destination is a fixed-size character array and replaces them with the safer ``snprintf``. + +It's a common idiom to have a fixed-size buffer of characters allocated on the stack and then to ``printf`` into the buffer. This can easily lead to buffer overflows. This check recommends that the counted version of the function is used instead. + +Example +------- + +.. code-block:: c++ + + void f() { + char buff[80]; + sprintf(buff, "Hello, %s!\n", "world"); + } + +Becomes: + +.. code-block:: c++ + + void f() { + char buff[80]; + snprintf(buff, sizeof(buff), "Hello, %s!\n", "world"); + } \ No newline at end of file diff --git a/clang-tools-extra/docs/clang-tidy/checks/list.rst b/clang-tools-extra/docs/clang-tidy/checks/list.rst index 0eabd9929dc39..0136a4849a075 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/list.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/list.rst @@ -144,6 +144,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-to-snprintf <bugprone/sprintf-to-snprintf>`, "Yes" :doc:`bugprone-spuriously-wake-up-functions <bugprone/spuriously-wake-up-functions>`, :doc:`bugprone-standalone-empty <bugprone/standalone-empty>`, "Yes" :doc:`bugprone-std-namespace-modification <bugprone/std-namespace-modification>`, diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/sprintf-to-snprintf.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/sprintf-to-snprintf.cpp new file mode 100644 index 0000000000000..f5d6ff5c59ee4 --- /dev/null +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/sprintf-to-snprintf.cpp @@ -0,0 +1,16 @@ +// RUN: %check_clang_tidy %s bugprone-sprintf-to-snprintf %t + +extern "C" int sprintf(char *str, const char *format, ...); +extern "C" int snprintf(char *s, unsigned long n, const char *format, ...); + +void f() { + char buff[80]; + sprintf(buff, "Hello, %s!\n", "world"); + // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: use 'snprintf' instead of 'sprintf' for fixed-size character arrays [bugprone-sprintf-to-snprintf] + // CHECK-FIXES: snprintf(buff, sizeof(buff), "Hello, %s!\n", "world"); +} + +void ignore_pointers(char* ptr) { + sprintf(ptr, "Hello"); + // Should not trigger because it's not a fixed-size array. +} \ No newline at end of file >From 18843845fe3a34424626850f72d3fa74b070dd6c Mon Sep 17 00:00:00 2001 From: ThanSin02426 <[email protected]> Date: Mon, 23 Feb 2026 15:10:08 +0530 Subject: [PATCH 2/6] Added some changes --- .../docs/clang-tidy/checks/bugprone/sprintf-to-snprintf.rst | 3 ++- .../test/clang-tidy/checkers/bugprone/sprintf-to-snprintf.cpp | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-to-snprintf.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-to-snprintf.rst index dc57e1736f3bd..529aeeb09e959 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-to-snprintf.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-to-snprintf.rst @@ -24,4 +24,5 @@ Becomes: void f() { char buff[80]; snprintf(buff, sizeof(buff), "Hello, %s!\n", "world"); - } \ No newline at end of file + } + \ No newline at end of file diff --git a/clang-tools-extra/test/clang-tidy/checkers/bugprone/sprintf-to-snprintf.cpp b/clang-tools-extra/test/clang-tidy/checkers/bugprone/sprintf-to-snprintf.cpp index f5d6ff5c59ee4..64823596b76f7 100644 --- a/clang-tools-extra/test/clang-tidy/checkers/bugprone/sprintf-to-snprintf.cpp +++ b/clang-tools-extra/test/clang-tidy/checkers/bugprone/sprintf-to-snprintf.cpp @@ -13,4 +13,4 @@ void f() { void ignore_pointers(char* ptr) { sprintf(ptr, "Hello"); // Should not trigger because it's not a fixed-size array. -} \ No newline at end of file +} >From ea85167ae27757fdd5a2cd34e3657789ff14be2e Mon Sep 17 00:00:00 2001 From: ThanSin02426 <[email protected]> Date: Mon, 23 Feb 2026 15:36:36 +0530 Subject: [PATCH 3/6] Fixed the some changes --- .../bugprone/SprintfToSnprintfCheck.cpp | 23 +++++++++++-------- .../bugprone/SprintfToSnprintfCheck.h | 11 ++++----- .../checks/bugprone/sprintf-to-snprintf.rst | 11 +++++---- 3 files changed, 24 insertions(+), 21 deletions(-) diff --git a/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.cpp index e357beb3e182e..d685df46d846f 100644 --- a/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.cpp @@ -1,4 +1,4 @@ -//===----------------------------------------------------------------------===// +//===--- SprintfToSnprintfCheck.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. @@ -7,22 +7,23 @@ //===----------------------------------------------------------------------===// #include "SprintfToSnprintfCheck.h" +#include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" +#include "clang/Lex/Lexer.h" using namespace clang::ast_matchers; namespace clang::tidy::bugprone { void SprintfToSnprintfCheck::registerMatchers(MatchFinder *Finder) { + // Match either ::sprintf or ::std::sprintf where the first argument is a + // constant array. Finder->addMatcher( - callExpr( - callee(functionDecl(hasName("::sprintf"))), - hasArgument( - 0, ignoringParenImpCasts(declRefExpr(to( - varDecl(hasType(constantArrayType())).bind("buffer") - )).bind("arg0")) - ) - ).bind("call"), + callExpr(callee(functionDecl(hasAnyName("::sprintf", "::std::sprintf"))), + hasArgument(0, ignoringParenImpCasts(declRefExpr(to( + varDecl(hasType(constantArrayType())) + .bind("buffer"))).bind("arg0")))) + .bind("call"), this); } @@ -35,7 +36,9 @@ void SprintfToSnprintfCheck::check(const MatchFinder::MatchResult &Result) { StringRef BufferName = Buffer->getName(); - auto Diag = diag(Call->getBeginLoc(), "use 'snprintf' instead of 'sprintf' for fixed-size character arrays"); + auto Diag = diag(Call->getBeginLoc(), + "use 'snprintf' instead of 'sprintf' for fixed-size " + "character arrays"); SourceLocation FuncNameLoc = Call->getExprLoc(); Diag << FixItHint::CreateReplacement(FuncNameLoc, "snprintf"); diff --git a/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.h b/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.h index 2a9b4dd3c3041..3118f860e9ae8 100644 --- a/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.h +++ b/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.h @@ -1,4 +1,4 @@ -//===----------------------------------------------------------------------===// +//===--- SprintfToSnprintfCheck.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. @@ -13,19 +13,16 @@ namespace clang::tidy::bugprone { -/// FIXME: Write a short description. -/// +/// Finds calls to sprintf where the destination is a fixed-size character +/// array and replaces them with the safer snprintf. /// For the user-facing documentation see: -/// https://clang.llvm.org/extra/clang-tidy/checks/bugprone/sprintf-to-snprintf.html +/// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/sprintf-to-snprintf.html class SprintfToSnprintfCheck : public ClangTidyCheck { public: SprintfToSnprintfCheck(StringRef Name, ClangTidyContext *Context) : ClangTidyCheck(Name, Context) {} void registerMatchers(ast_matchers::MatchFinder *Finder) override; void check(const ast_matchers::MatchFinder::MatchResult &Result) override; - bool isLanguageVersionSupported(const LangOptions &LangOpts) const override { - return LangOpts.CPlusPlus; - } }; } // namespace clang::tidy::bugprone diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-to-snprintf.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-to-snprintf.rst index 529aeeb09e959..ad3fc46f9fea8 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-to-snprintf.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-to-snprintf.rst @@ -3,9 +3,13 @@ bugprone-sprintf-to-snprintf ============================ -Finds calls to ``sprintf`` where the destination is a fixed-size character array and replaces them with the safer ``snprintf``. +Finds calls to ``sprintf`` where the destination is a fixed-size character +array and replaces them with the safer ``snprintf``. -It's a common idiom to have a fixed-size buffer of characters allocated on the stack and then to ``printf`` into the buffer. This can easily lead to buffer overflows. This check recommends that the counted version of the function is used instead. +It's a common idiom to have a fixed-size buffer of characters allocated on +the stack and then to ``printf`` into the buffer. This can easily lead to +buffer overflows. This check recommends that the counted version of the +function is used instead. Example ------- @@ -24,5 +28,4 @@ Becomes: void f() { char buff[80]; snprintf(buff, sizeof(buff), "Hello, %s!\n", "world"); - } - \ No newline at end of file + } \ No newline at end of file >From 43e1e8833e35f8e4c328ecab183b02b56147ba3b Mon Sep 17 00:00:00 2001 From: ThanSin02426 <[email protected]> Date: Mon, 23 Feb 2026 15:48:44 +0530 Subject: [PATCH 4/6] Added some formatting --- .../clang-tidy/bugprone/SprintfToSnprintfCheck.cpp | 8 +++++--- .../clang-tidy/bugprone/SprintfToSnprintfCheck.h | 3 ++- .../clang-tidy/checks/bugprone/sprintf-to-snprintf.rst | 3 ++- 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.cpp index d685df46d846f..091d5657c9991 100644 --- a/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.cpp @@ -36,13 +36,15 @@ void SprintfToSnprintfCheck::check(const MatchFinder::MatchResult &Result) { StringRef BufferName = Buffer->getName(); - auto Diag = diag(Call->getBeginLoc(), - "use 'snprintf' instead of 'sprintf' for fixed-size " - "character arrays"); + auto Diag = diag( + Call->getBeginLoc(), + "use 'snprintf' instead of 'sprintf' for fixed-size character arrays"); + // 1. Fix-it: replace 'sprintf' with 'snprintf' SourceLocation FuncNameLoc = Call->getExprLoc(); Diag << FixItHint::CreateReplacement(FuncNameLoc, "snprintf"); + // 2. Fix-it: insert 'sizeof(buffer_name), ' as the new second argument SourceLocation InsertLoc = Call->getArg(1)->getBeginLoc(); std::string SizeArg = "sizeof(" + BufferName.str() + "), "; Diag << FixItHint::CreateInsertion(InsertLoc, SizeArg); diff --git a/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.h b/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.h index 3118f860e9ae8..5ac7181f0a896 100644 --- a/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.h +++ b/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.h @@ -13,8 +13,9 @@ namespace clang::tidy::bugprone { -/// Finds calls to sprintf where the destination is a fixed-size character +/// Finds calls to sprintf where the destination is a fixed-size character /// array and replaces them with the safer snprintf. +/// /// For the user-facing documentation see: /// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/sprintf-to-snprintf.html class SprintfToSnprintfCheck : public ClangTidyCheck { diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-to-snprintf.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-to-snprintf.rst index ad3fc46f9fea8..fe175b4d6b8a8 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-to-snprintf.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-to-snprintf.rst @@ -28,4 +28,5 @@ Becomes: void f() { char buff[80]; snprintf(buff, sizeof(buff), "Hello, %s!\n", "world"); - } \ No newline at end of file + } + \ No newline at end of file >From 00cfcc95e9a2af89a8cb07f8bd917ad5a4c7e6fe Mon Sep 17 00:00:00 2001 From: ThanSin02426 <[email protected]> Date: Tue, 24 Feb 2026 14:34:40 +0530 Subject: [PATCH 5/6] Add config option, fix formatting, and address reviews --- .../bugprone/SprintfToSnprintfCheck.cpp | 53 +++++++++++++------ .../bugprone/SprintfToSnprintfCheck.h | 8 ++- .../checks/bugprone/sprintf-to-snprintf.rst | 9 +++- 3 files changed, 50 insertions(+), 20 deletions(-) diff --git a/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.cpp index 091d5657c9991..ff8ec4f5d775c 100644 --- a/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "SprintfToSnprintfCheck.h" +#include "../utils/OptionsUtils.h" #include "clang/AST/ASTContext.h" #include "clang/ASTMatchers/ASTMatchFinder.h" #include "clang/Lex/Lexer.h" @@ -15,14 +16,25 @@ using namespace clang::ast_matchers; namespace clang::tidy::bugprone { +SprintfToSnprintfCheck::SprintfToSnprintfCheck(StringRef Name, + ClangTidyContext *Context) + : ClangTidyCheck(Name, Context), + SprintfLikeFunctions(utils::options::parseStringList( + Options.get("SprintfLikeFunctions", "::sprintf;::std::sprintf"))) {} + +void SprintfToSnprintfCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) { + Options.store(Opts, "SprintfLikeFunctions", + utils::options::serializeStringList(SprintfLikeFunctions)); +} + void SprintfToSnprintfCheck::registerMatchers(MatchFinder *Finder) { - // Match either ::sprintf or ::std::sprintf where the first argument is a - // constant array. Finder->addMatcher( - callExpr(callee(functionDecl(hasAnyName("::sprintf", "::std::sprintf"))), - hasArgument(0, ignoringParenImpCasts(declRefExpr(to( - varDecl(hasType(constantArrayType())) - .bind("buffer"))).bind("arg0")))) + callExpr(callee(functionDecl(hasAnyName(SprintfLikeFunctions))), + hasArgument( + 0, ignoringParenImpCasts( + declRefExpr(to(varDecl(hasType(constantArrayType())) + .bind("buffer"))) + .bind("arg0")))) .bind("call"), this); } @@ -34,20 +46,27 @@ void SprintfToSnprintfCheck::check(const MatchFinder::MatchResult &Result) { if (!Call || !Buffer) return; - StringRef BufferName = Buffer->getName(); + const FunctionDecl *Callee = Call->getDirectCallee(); + if (!Callee) + return; + + const StringRef FuncName = Callee->getName(); + const StringRef BufferName = Buffer->getName(); - auto Diag = diag( - Call->getBeginLoc(), - "use 'snprintf' instead of 'sprintf' for fixed-size character arrays"); + auto Diag = diag(Call->getBeginLoc(), + "use 'snprintf' instead of '%0' for fixed-size " + "character arrays") + << FuncName; - // 1. Fix-it: replace 'sprintf' with 'snprintf' - SourceLocation FuncNameLoc = Call->getExprLoc(); - Diag << FixItHint::CreateReplacement(FuncNameLoc, "snprintf"); + // Only provide an automated Fix-It if the function is exactly "sprintf" + if (FuncName == "sprintf") { + const SourceLocation FuncNameLoc = Call->getExprLoc(); + Diag << FixItHint::CreateReplacement(FuncNameLoc, "snprintf"); - // 2. Fix-it: insert 'sizeof(buffer_name), ' as the new second argument - SourceLocation InsertLoc = Call->getArg(1)->getBeginLoc(); - std::string SizeArg = "sizeof(" + BufferName.str() + "), "; - Diag << FixItHint::CreateInsertion(InsertLoc, SizeArg); + const SourceLocation InsertLoc = Call->getArg(1)->getBeginLoc(); + const std::string SizeArg = "sizeof(" + BufferName.str() + "), "; + Diag << FixItHint::CreateInsertion(InsertLoc, SizeArg); + } } } // namespace clang::tidy::bugprone diff --git a/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.h b/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.h index 5ac7181f0a896..f8350bf31ad82 100644 --- a/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.h +++ b/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.h @@ -10,6 +10,7 @@ #define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_SPRINTFTOSNPRINTFCHECK_H #include "../ClangTidyCheck.h" +#include <vector> namespace clang::tidy::bugprone { @@ -20,10 +21,13 @@ namespace clang::tidy::bugprone { /// http://clang.llvm.org/extra/clang-tidy/checks/bugprone/sprintf-to-snprintf.html class SprintfToSnprintfCheck : public ClangTidyCheck { public: - SprintfToSnprintfCheck(StringRef Name, ClangTidyContext *Context) - : ClangTidyCheck(Name, Context) {} + SprintfToSnprintfCheck(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; + +private: + const std::vector<StringRef> SprintfLikeFunctions; }; } // namespace clang::tidy::bugprone diff --git a/clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-to-snprintf.rst b/clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-to-snprintf.rst index fe175b4d6b8a8..7b9bd9a09deed 100644 --- a/clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-to-snprintf.rst +++ b/clang-tools-extra/docs/clang-tidy/checks/bugprone/sprintf-to-snprintf.rst @@ -11,6 +11,14 @@ the stack and then to ``printf`` into the buffer. This can easily lead to buffer overflows. This check recommends that the counted version of the function is used instead. +Options +------- + +.. option:: SprintfLikeFunctions + + A semicolon-separated list of functions to check. The default is + `::sprintf;::std::sprintf`. + Example ------- @@ -29,4 +37,3 @@ Becomes: char buff[80]; snprintf(buff, sizeof(buff), "Hello, %s!\n", "world"); } - \ No newline at end of file >From 5370844eb49a852dd5ef24143df1a5f9de7c1a39 Mon Sep 17 00:00:00 2001 From: ThanSin02426 <[email protected]> Date: Tue, 24 Feb 2026 14:42:03 +0530 Subject: [PATCH 6/6] Fix code formatting for clang-tidy bugprone SprintfToSnprintfCheck --- .../clang-tidy/bugprone/SprintfToSnprintfCheck.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.cpp b/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.cpp index ff8ec4f5d775c..ddd2218d0594b 100644 --- a/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.cpp +++ b/clang-tools-extra/clang-tidy/bugprone/SprintfToSnprintfCheck.cpp @@ -53,10 +53,10 @@ void SprintfToSnprintfCheck::check(const MatchFinder::MatchResult &Result) { const StringRef FuncName = Callee->getName(); const StringRef BufferName = Buffer->getName(); - auto Diag = diag(Call->getBeginLoc(), - "use 'snprintf' instead of '%0' for fixed-size " - "character arrays") - << FuncName; + auto Diag = + diag(Call->getBeginLoc(), "use 'snprintf' instead of '%0' for fixed-size " + "character arrays") + << FuncName; // Only provide an automated Fix-It if the function is exactly "sprintf" if (FuncName == "sprintf") { _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
