[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2026-01-17 Thread Baranov Victor via cfe-commits


@@ -0,0 +1,264 @@
+//===--===//
+//
+// 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 "UnsafeFormatStringCheck.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+static constexpr llvm::StringLiteral OptionNameCustomPrintfFunctions =
+"CustomPrintfFunctions";
+static constexpr llvm::StringLiteral OptionNameCustomScanfFunctions =
+"CustomScanfFunctions";
+
+static constexpr llvm::StringLiteral BuiltInFormatBind = "format";
+static constexpr llvm::StringLiteral BuiltInCallBind = "call";
+static constexpr llvm::StringLiteral PrintfCallBind = "printfcall";
+static constexpr llvm::StringLiteral ScanfCallBind = "scanfcall";
+
+static std::vector
+parseCheckedFunctions(StringRef Option, ClangTidyContext *Context) {
+  const std::vector Functions =
+  utils::options::parseStringList(Option);
+  std::vector Result;
+  Result.reserve(Functions.size());
+
+  for (const StringRef Function : Functions) {
+if (Function.empty())
+  continue;
+const auto [Name, ParamCount] = Function.split(',');
+unsigned long Count = 0;
+if (Name.trim().empty() || ParamCount.trim().empty() ||
+ParamCount.trim().getAsInteger(10, Count)) {
+  Context->configurationDiag(
+  "invalid configuration value for option '%0'; "
+  "expected , ; pairs.")
+  << OptionNameCustomPrintfFunctions;
+  continue;
+}
+Result.push_back(
+{Name.trim().str(),
+ matchers::MatchesAnyListedNameMatcher::NameMatcher(Name.trim()),
+ Count});
+  }
+
+  return Result;
+}
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context),
+  CustomPrintfFunctions(parseCheckedFunctions(
+  Options.get(OptionNameCustomPrintfFunctions, ""), Context)),
+  CustomScanfFunctions(parseCheckedFunctions(
+  Options.get(OptionNameCustomScanfFunctions, ""), Context)) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");
+  Finder->addMatcher(
+  callExpr(
+  callee(functionDecl(VulnerableFunctions,
+  anyOf(isInStdNamespace(),
+hasDeclContext(translationUnitDecl(),
+  anyOf(hasArgument(0, stringLiteral().bind(BuiltInFormatBind)),
+hasArgument(1, stringLiteral().bind(BuiltInFormatBind
+  .bind(BuiltInCallBind),
+  this);
+
+  if (!CustomPrintfFunctions.empty()) {
+std::vector FunctionNames;
+FunctionNames.reserve(CustomPrintfFunctions.size());
+
+for (const auto &Entry : CustomPrintfFunctions)
+  FunctionNames.emplace_back(Entry.Name);
+
+auto CustomFunctionsMatcher = 
matchers::matchesAnyListedName(FunctionNames);
+
+Finder->addMatcher(callExpr(callee((functionDecl(CustomFunctionsMatcher
+   .bind(PrintfCallBind),
+   this);
+  }
+
+  if (!CustomScanfFunctions.empty()) {
+std::vector FunctionNames;
+FunctionNames.reserve(CustomScanfFunctions.size());
+
+for (const auto &Entry : CustomScanfFunctions)
+  FunctionNames.emplace_back(Entry.Name);
+
+auto CustomFunctionsMatcher = 
matchers::matchesAnyListedName(FunctionNames);
+
+Finder->addMatcher(callExpr(callee((functionDecl(CustomFunctionsMatcher
+   .bind(ScanfCallBind),
+   this);
+  }
+}
+
+void UnsafeFormatStringCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, OptionNameCustomPrintfFunctions, "");
+  Options.store(Opts, OptionNameCustomScanfFunctions, "");
+}
+
+const StringLiteral *UnsafeFormatStringCheck::getFormatLiteral(
+const CallExpr *Call, const std::vector &CustomFunctions) 
{
+  const auto *FD = cast(Call->getDirectCallee());
+  if (!FD)
+return nullptr;
+  for (const auto &Entry : CustomFunctions) {
+if (Entry.Pattern.match(*FD)) {
+  if (Entry.FormatStringLocation >= Call->getNumArgs())
+return nullptr;
+  const Expr *Arg =
+  Call->getArg(Entry.FormatStringLocation)->IgnoreImpCasts();
+  return dyn_cast(Arg)

[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2026-01-17 Thread Baranov Victor via cfe-commits

https://github.com/vbvictor edited 
https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2026-01-17 Thread Baranov Victor via cfe-commits

vbvictor wrote:

> maybe bugprone-unbounded-format-string ?

Sounds good to me

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2026-01-14 Thread via cfe-commits


@@ -0,0 +1,114 @@
+.. title:: clang-tidy - bugprone-unsafe-format-string
+
+bugprone-unsafe-format-string
+=
+
+Detects usage of vulnerable ``printf`` and ``scanf``-like format string 
+functions with unbounded ``%s`` specifiers that can cause buffer overflows.
+
+The check identifies calls to format string functions like ``sprintf``, 
``scanf``,
+and their variants that use ``%s`` format specifiers without proper limits.
+This can lead to buffer overflow vulnerabilities when the input string is 
longer
+than the destination buffer.
+
+Format Specifier Behavior
+-
+
+The check distinguishes between different function families:
+
+**scanf family functions**: Field width limits input length
+  - ``%s`` - unsafe (no limit)
+  - ``%99s`` - safe (reads at most 99 characters)
+
+**sprintf family functions**: Precision limits output length
+  - ``%s`` - unsafe (no limit)
+  - ``%99s`` - unsafe (minimum width, no maximum)
+  - ``%.99s`` - safe (outputs at most 99 characters)
+  - ``%10.99s`` - safe (minimum 10 chars, maximum 99 chars)
+
+Examples
+
+
+.. code-block:: c
+
+  char buffer[100];
+  const char* input = "user input";
+  
+  // Unsafe sprintf usage
+  sprintf(buffer, "%s", input);  // No limit
+  sprintf(buffer, "%99s", input);// Field width is minimum, not maximum
+  
+  // Safe sprintf usage
+  sprintf(buffer, "%.99s", input);   // Precision limits to 99 chars
+  sprintf(buffer, "%10.99s", input); // Min 10, max 99 chars
+  
+  // Unsafe scanf usage
+  scanf("%s", buffer);   // No limit
+  
+  // Safe scanf usage
+  scanf("%99s", buffer); // Field width limits to 99 chars
+  
+  // Safe alternative: use safer functions
+  snprintf(buffer, sizeof(buffer), "%s", input);
+
+
+Checked Functions
+-
+
+The check detects unsafe format strings in these functions:
+
+**sprintf family** (precision ``.N`` provides safety):
+* ``sprintf``, ``vsprintf``
+
+**scanf family** (field width ``N`` provides safety):
+* ``scanf``, ``fscanf``, ``sscanf``
+* ``vscanf``, ``vfscanf``, ``vsscanf``
+* ``wscanf``, ``fwscanf``, ``swscanf``
+* ``vwscanf``, ``vfwscanf``, ``vswscanf``
+
+Configuration
+-
+
+The checker offers 2 configuration options.
+
+* `CustomPrintfFunctions` The user can specify own printf-like functions

EugeneZelenko wrote:

```suggestion
.. option:: CustomPrintfFunctions

The user can specify own ``printf``-like functions
```

Same for other option.

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2026-01-14 Thread Yanzuo Liu via cfe-commits

https://github.com/zwuis edited https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2026-01-14 Thread Yanzuo Liu via cfe-commits


@@ -0,0 +1,264 @@
+//===--===//
+//
+// 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 "UnsafeFormatStringCheck.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+static constexpr llvm::StringLiteral OptionNameCustomPrintfFunctions =
+"CustomPrintfFunctions";
+static constexpr llvm::StringLiteral OptionNameCustomScanfFunctions =
+"CustomScanfFunctions";
+
+static constexpr llvm::StringLiteral BuiltInFormatBind = "format";
+static constexpr llvm::StringLiteral BuiltInCallBind = "call";
+static constexpr llvm::StringLiteral PrintfCallBind = "printfcall";
+static constexpr llvm::StringLiteral ScanfCallBind = "scanfcall";
+
+static std::vector
+parseCheckedFunctions(StringRef Option, ClangTidyContext *Context) {
+  const std::vector Functions =
+  utils::options::parseStringList(Option);
+  std::vector Result;
+  Result.reserve(Functions.size());
+
+  for (const StringRef Function : Functions) {
+if (Function.empty())
+  continue;
+const auto [Name, ParamCount] = Function.split(',');
+unsigned long Count = 0;
+if (Name.trim().empty() || ParamCount.trim().empty() ||
+ParamCount.trim().getAsInteger(10, Count)) {
+  Context->configurationDiag(
+  "invalid configuration value for option '%0'; "
+  "expected , ; pairs.")
+  << OptionNameCustomPrintfFunctions;
+  continue;
+}
+Result.push_back(
+{Name.trim().str(),
+ matchers::MatchesAnyListedNameMatcher::NameMatcher(Name.trim()),
+ Count});
+  }
+
+  return Result;
+}
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context),
+  CustomPrintfFunctions(parseCheckedFunctions(
+  Options.get(OptionNameCustomPrintfFunctions, ""), Context)),
+  CustomScanfFunctions(parseCheckedFunctions(
+  Options.get(OptionNameCustomScanfFunctions, ""), Context)) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");
+  Finder->addMatcher(
+  callExpr(
+  callee(functionDecl(VulnerableFunctions,
+  anyOf(isInStdNamespace(),
+hasDeclContext(translationUnitDecl(),
+  anyOf(hasArgument(0, stringLiteral().bind(BuiltInFormatBind)),
+hasArgument(1, stringLiteral().bind(BuiltInFormatBind
+  .bind(BuiltInCallBind),
+  this);
+
+  if (!CustomPrintfFunctions.empty()) {
+std::vector FunctionNames;
+FunctionNames.reserve(CustomPrintfFunctions.size());
+
+for (const auto &Entry : CustomPrintfFunctions)
+  FunctionNames.emplace_back(Entry.Name);
+
+auto CustomFunctionsMatcher = 
matchers::matchesAnyListedName(FunctionNames);
+
+Finder->addMatcher(callExpr(callee((functionDecl(CustomFunctionsMatcher
+   .bind(PrintfCallBind),
+   this);
+  }
+
+  if (!CustomScanfFunctions.empty()) {
+std::vector FunctionNames;
+FunctionNames.reserve(CustomScanfFunctions.size());
+
+for (const auto &Entry : CustomScanfFunctions)
+  FunctionNames.emplace_back(Entry.Name);
+
+auto CustomFunctionsMatcher = 
matchers::matchesAnyListedName(FunctionNames);
+
+Finder->addMatcher(callExpr(callee((functionDecl(CustomFunctionsMatcher
+   .bind(ScanfCallBind),
+   this);
+  }
+}
+
+void UnsafeFormatStringCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, OptionNameCustomPrintfFunctions, "");
+  Options.store(Opts, OptionNameCustomScanfFunctions, "");
+}
+
+const StringLiteral *UnsafeFormatStringCheck::getFormatLiteral(
+const CallExpr *Call, const std::vector &CustomFunctions) 
{
+  const auto *FD = cast(Call->getDirectCallee());
+  if (!FD)
+return nullptr;
+  for (const auto &Entry : CustomFunctions) {
+if (Entry.Pattern.match(*FD)) {
+  if (Entry.FormatStringLocation >= Call->getNumArgs())
+return nullptr;
+  const Expr *Arg =
+  Call->getArg(Entry.FormatStringLocation)->IgnoreImpCasts();
+  return dyn_cast(Arg)

[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2026-01-14 Thread via cfe-commits


@@ -0,0 +1,114 @@
+.. title:: clang-tidy - bugprone-unsafe-format-string
+
+bugprone-unsafe-format-string
+=
+
+Detects usage of vulnerable ``printf`` and ``scanf``-like format string 
+functions with unbounded ``%s`` specifiers that can cause buffer overflows.
+
+The check identifies calls to format string functions like ``sprintf``, 
``scanf``,
+and their variants that use ``%s`` format specifiers without proper limits.
+This can lead to buffer overflow vulnerabilities when the input string is 
longer
+than the destination buffer.
+
+Format Specifier Behavior
+-
+
+The check distinguishes between different function families:
+
+**scanf family functions**: Field width limits input length
+  - ``%s`` - unsafe (no limit)
+  - ``%99s`` - safe (reads at most 99 characters)
+
+**sprintf family functions**: Precision limits output length
+  - ``%s`` - unsafe (no limit)
+  - ``%99s`` - unsafe (minimum width, no maximum)
+  - ``%.99s`` - safe (outputs at most 99 characters)
+  - ``%10.99s`` - safe (minimum 10 chars, maximum 99 chars)
+
+Examples
+
+
+.. code-block:: c
+
+  char buffer[100];
+  const char* input = "user input";
+  
+  // Unsafe sprintf usage
+  sprintf(buffer, "%s", input);  // No limit
+  sprintf(buffer, "%99s", input);// Field width is minimum, not maximum
+  
+  // Safe sprintf usage
+  sprintf(buffer, "%.99s", input);   // Precision limits to 99 chars
+  sprintf(buffer, "%10.99s", input); // Min 10, max 99 chars
+  
+  // Unsafe scanf usage
+  scanf("%s", buffer);   // No limit
+  
+  // Safe scanf usage
+  scanf("%99s", buffer); // Field width limits to 99 chars
+  
+  // Safe alternative: use safer functions
+  snprintf(buffer, sizeof(buffer), "%s", input);
+
+
+Checked Functions
+-
+
+The check detects unsafe format strings in these functions:
+
+**sprintf family** (precision ``.N`` provides safety):
+* ``sprintf``, ``vsprintf``
+
+**scanf family** (field width ``N`` provides safety):
+* ``scanf``, ``fscanf``, ``sscanf``
+* ``vscanf``, ``vfscanf``, ``vsscanf``
+* ``wscanf``, ``fwscanf``, ``swscanf``
+* ``vwscanf``, ``vfwscanf``, ``vswscanf``
+
+Configuration
+-
+
+The checker offers 2 configuration options.
+

EugeneZelenko wrote:

```suggestion
```

Not needed.

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2026-01-14 Thread Yanzuo Liu via cfe-commits


@@ -0,0 +1,264 @@
+//===--===//
+//
+// 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 "UnsafeFormatStringCheck.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+static constexpr llvm::StringLiteral OptionNameCustomPrintfFunctions =

zwuis wrote:

Use `StringRef`. See #172765.

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2026-01-14 Thread Yanzuo Liu via cfe-commits


@@ -0,0 +1,264 @@
+//===--===//
+//
+// 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 "UnsafeFormatStringCheck.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+static constexpr llvm::StringLiteral OptionNameCustomPrintfFunctions =
+"CustomPrintfFunctions";
+static constexpr llvm::StringLiteral OptionNameCustomScanfFunctions =
+"CustomScanfFunctions";
+
+static constexpr llvm::StringLiteral BuiltInFormatBind = "format";
+static constexpr llvm::StringLiteral BuiltInCallBind = "call";
+static constexpr llvm::StringLiteral PrintfCallBind = "printfcall";
+static constexpr llvm::StringLiteral ScanfCallBind = "scanfcall";
+
+static std::vector
+parseCheckedFunctions(StringRef Option, ClangTidyContext *Context) {
+  const std::vector Functions =
+  utils::options::parseStringList(Option);
+  std::vector Result;
+  Result.reserve(Functions.size());
+
+  for (const StringRef Function : Functions) {
+if (Function.empty())
+  continue;
+const auto [Name, ParamCount] = Function.split(',');
+unsigned long Count = 0;
+if (Name.trim().empty() || ParamCount.trim().empty() ||
+ParamCount.trim().getAsInteger(10, Count)) {
+  Context->configurationDiag(
+  "invalid configuration value for option '%0'; "
+  "expected , ; pairs.")
+  << OptionNameCustomPrintfFunctions;
+  continue;
+}
+Result.push_back(
+{Name.trim().str(),
+ matchers::MatchesAnyListedNameMatcher::NameMatcher(Name.trim()),
+ Count});
+  }
+
+  return Result;
+}
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context),
+  CustomPrintfFunctions(parseCheckedFunctions(
+  Options.get(OptionNameCustomPrintfFunctions, ""), Context)),
+  CustomScanfFunctions(parseCheckedFunctions(
+  Options.get(OptionNameCustomScanfFunctions, ""), Context)) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");
+  Finder->addMatcher(
+  callExpr(
+  callee(functionDecl(VulnerableFunctions,
+  anyOf(isInStdNamespace(),
+hasDeclContext(translationUnitDecl(),
+  anyOf(hasArgument(0, stringLiteral().bind(BuiltInFormatBind)),
+hasArgument(1, stringLiteral().bind(BuiltInFormatBind
+  .bind(BuiltInCallBind),
+  this);
+
+  if (!CustomPrintfFunctions.empty()) {
+std::vector FunctionNames;
+FunctionNames.reserve(CustomPrintfFunctions.size());
+
+for (const auto &Entry : CustomPrintfFunctions)
+  FunctionNames.emplace_back(Entry.Name);
+
+auto CustomFunctionsMatcher = 
matchers::matchesAnyListedName(FunctionNames);
+
+Finder->addMatcher(callExpr(callee((functionDecl(CustomFunctionsMatcher
+   .bind(PrintfCallBind),
+   this);
+  }
+
+  if (!CustomScanfFunctions.empty()) {
+std::vector FunctionNames;
+FunctionNames.reserve(CustomScanfFunctions.size());
+
+for (const auto &Entry : CustomScanfFunctions)
+  FunctionNames.emplace_back(Entry.Name);
+
+auto CustomFunctionsMatcher = 
matchers::matchesAnyListedName(FunctionNames);
+
+Finder->addMatcher(callExpr(callee((functionDecl(CustomFunctionsMatcher
+   .bind(ScanfCallBind),
+   this);
+  }
+}
+
+void UnsafeFormatStringCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, OptionNameCustomPrintfFunctions, "");
+  Options.store(Opts, OptionNameCustomScanfFunctions, "");
+}
+
+const StringLiteral *UnsafeFormatStringCheck::getFormatLiteral(
+const CallExpr *Call, const std::vector &CustomFunctions) 
{
+  const auto *FD = cast(Call->getDirectCallee());

zwuis wrote:

`getDirectCallee()` already returns `FunctionDecl *`.

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2026-01-14 Thread Yanzuo Liu via cfe-commits

https://github.com/zwuis commented:

> coauthors: [email protected], [email protected]

FYI 
https://docs.github.com/en/pull-requests/committing-changes-to-your-project/creating-and-editing-commits/creating-a-commit-with-multiple-authors

> > Can we give this check a more specific name rather than using "unsafe"?
> 
> Any suggestions?
> 
> maybe bugprone-unbounded-format-string ?

+1 if other reviewers don't have a plan to extend this check in future.

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2026-01-14 Thread Baranov Victor via cfe-commits

https://github.com/vbvictor edited 
https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2026-01-14 Thread Yanzuo Liu via cfe-commits

https://github.com/zwuis edited https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2026-01-14 Thread Yanzuo Liu via cfe-commits


@@ -0,0 +1,34 @@
+//===*- 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_UNSAFEFORMATSTRINGCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNSAFEFORMATSTRINGCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::bugprone {
+
+/// Detects usage of vulnerable format string functions with unbounded %s
+/// specifiers that can cause buffer overflows.
+///
+/// For the user-facing documentation see:
+/// 
https://clang.llvm.org/extra/clang-tidy/checks/bugprone/unsafe-format-string.html
+class UnsafeFormatStringCheck : public ClangTidyCheck {
+public:
+  UnsafeFormatStringCheck(StringRef Name, ClangTidyContext *Context);
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  bool hasUnboundedStringSpecifier(StringRef Fmt, bool IsScanfFamily);

zwuis wrote:

> ... in .cpp file ...

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-04 Thread Daniel Krupp via cfe-commits

dkrupp wrote:

I have executed the checker on several open source projects.

There are a few findings.
1) In twin, the destination buffer size is calculated properly (I think), but 
using snprintf or width specifier would not hurt.
2) Openssl the write length to `sfx` is protected with the if condition. 
3) The sprintf usage in sqlite could be problematic. The source string size is 
not trivially visible and the write length of the destination buffer is not 
protected. Using snprintf or width specifier would make the write much safer.

| Project | Reports |
|-|-|
| codechecker | [0 
reports](https://codechecker-demo.eastus.cloudapp.azure.com/Default/reports?run=codechecker_v6.25.1_ednikru_dkrupp-bugprone-unsafe-format-string-pr_a8d28b5)
 |
| memcached | [0 
reports](https://codechecker-demo.eastus.cloudapp.azure.com/Default/reports?run=memcached_1.6.38_ednikru_dkrupp-bugprone-unsafe-format-string-pr_a8d28b5)
 |
| tmux | [0 
reports](https://codechecker-demo.eastus.cloudapp.azure.com/Default/reports?run=tmux_3.5a_ednikru_dkrupp-bugprone-unsafe-format-string-pr_a8d28b5)
 |
| curl | [0 
reports](https://codechecker-demo.eastus.cloudapp.azure.com/Default/reports?run=curl_curl-8_12_1_ednikru_dkrupp-bugprone-unsafe-format-string-pr_a8d28b5)
 |
| twin | [3 
reports](https://codechecker-demo.eastus.cloudapp.azure.com/Default/reports?run=twin_v0.9.0_ednikru_dkrupp-bugprone-unsafe-format-string-pr_a8d28b5)
 |
| vim | [0 
reports](https://codechecker-demo.eastus.cloudapp.azure.com/Default/reports?run=vim_v9.1.1232_ednikru_dkrupp-bugprone-unsafe-format-string-pr_a8d28b5)
 |
| openssl | [2 
reports](https://codechecker-demo.eastus.cloudapp.azure.com/Default/reports?run=openssl_openssl-3.4.1_ednikru_dkrupp-bugprone-unsafe-format-string-pr_a8d28b5)
 |
| sqlite | [1 
reports](https://codechecker-demo.eastus.cloudapp.azure.com/Default/reports?run=sqlite_version-3.49.1_ednikru_dkrupp-bugprone-unsafe-format-string-pr_a8d28b5)
 |
| postgres | [0 
reports](https://codechecker-demo.eastus.cloudapp.azure.com/Default/reports?run=postgres_REL_17_4_ednikru_dkrupp-bugprone-unsafe-format-string-pr_a8d28b5)
 |
| tinyxml2 | [0 
reports](https://codechecker-demo.eastus.cloudapp.azure.com/Default/reports?run=tinyxml2_11.0.0_ednikru_dkrupp-bugprone-unsafe-format-string-pr_a8d28b5)
 |
| libwebm | [0 
reports](https://codechecker-demo.eastus.cloudapp.azure.com/Default/reports?run=libwebm_libwebm-1.0.0.31_ednikru_dkrupp-bugprone-unsafe-format-string-pr_a8d28b5)
 |
| xerces | [0 
reports](https://codechecker-demo.eastus.cloudapp.azure.com/Default/reports?run=xerces_v3.3.0_ednikru_dkrupp-bugprone-unsafe-format-string-pr_a8d28b5)
 |



https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-03 Thread Daniel Krupp via cfe-commits

dkrupp wrote:

> Can we give this check a more specific name rather than using "unsafe"?

Any suggestions?

maybe bugprone-unbounded-format-string ?

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-02 Thread Yanzuo Liu via cfe-commits


@@ -0,0 +1,111 @@
+.. title:: clang-tidy - bugprone-unsafe-format-string
+
+bugprone-unsafe-format-string
+=
+
+Detects usage of vulnerable format string functions with unbounded ``%s``
+specifiers that can cause buffer overflows.
+
+The check identifies calls to format string functions like ``sprintf``, 
``scanf``,
+and their variants that use ``%s`` format specifiers without proper limits.
+This can lead to buffer overflow vulnerabilities when the input string is 
longer
+than the destination buffer.
+
+Format Specifier Behavior
+-
+
+The check distinguishes between different function families:
+
+**scanf family functions**: Field width limits input length
+  - ``%s`` - unsafe (no limit)
+  - ``%99s`` - safe (reads at most 99 characters)
+
+**sprintf family functions**: Precision limits output length
+  - ``%s`` - unsafe (no limit)
+  - ``%99s`` - unsafe (minimum width, no maximum)
+  - ``%.99s`` - safe (outputs at most 99 characters)
+  - ``%10.99s`` - safe (minimum 10 chars, maximum 99 chars)
+
+Examples
+
+
+.. code-block:: c
+
+  char buffer[100];
+  const char* input = "user input";
+  
+  // Unsafe sprintf usage
+  sprintf(buffer, "%s", input);  // No limit
+  sprintf(buffer, "%99s", input);// Field width is minimum, not maximum
+  
+  // Safe sprintf usage
+  sprintf(buffer, "%.99s", input);   // Precision limits to 99 chars
+  sprintf(buffer, "%10.99s", input); // Min 10, max 99 chars
+  
+  // Unsafe scanf usage
+  scanf("%s", buffer);   // No limit
+  
+  // Safe scanf usage
+  scanf("%99s", buffer); // Field width limits to 99 chars
+  
+  // Safe alternative: use safer functions
+  snprintf(buffer, sizeof(buffer), "%s", input);
+
+
+Checked Functions
+-
+
+The check detects unsafe format strings in these functions:
+
+**sprintf family** (precision ``.N`` provides safety):
+* ``sprintf``, ``vsprintf``
+
+**scanf family** (field width ``N`` provides safety):
+* ``scanf``, ``fscanf``, ``sscanf``
+* ``vscanf``, ``vfscanf``, ``vsscanf``
+* ``wscanf``, ``fwscanf``, ``swscanf``
+* ``vwscanf``, ``vfwscanf``, ``vswscanf``
+
+Configuration
+-
+
+The checker offers 2 configuration options.
+
+* `CustomPrintfFunctions` The user can specify own printf-like functions with 
dangerous format string parameter.
+* `CustomScanfFunctions` The user can specify own scanf-like functions with 
dangerous format string parameter.
+
+Format:
+Both options have the following format.
+.. code::
+  
+   bugprone-unsafe-functions.CustomPrintfFunctions="
+ functionRegex1, format-string-position;
+ functionRegex2, format-string-position;
+ ...
+   "
+
+The first parameter in the pairs is a function regular expression matching the 
function name, 
+the second parameter is the count of the format string literal argument.
+
+The following configuration will give warning:
+
+.. code::
+  
+  bugprone-unsafe-format-string.CustomPrintfFunctions: 'mysprintf, 0;'
+  bugprone-unsafe-format-string.CustomScanfFunctions: 'myscanf, 1;'
+
+  extern int myscanf( const char* format, ... );
+  extern int mysprintf( char* buffer, const char* format, ... );
+  void test() {
+char buffer[100];
+const char* input = "user input";
+mysprintf(buffer, "%s", input); // warning 
+myscanf("%s", buffer); //warning
+  }

zwuis wrote:

Please document the default value of options.

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-02 Thread Yanzuo Liu via cfe-commits

https://github.com/zwuis commented:

Can we give this check a more specific name rather than using "unsafe"?

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-02 Thread Yanzuo Liu via cfe-commits

https://github.com/zwuis edited https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-02 Thread via cfe-commits


@@ -0,0 +1,111 @@
+.. title:: clang-tidy - bugprone-unsafe-format-string
+
+bugprone-unsafe-format-string
+=
+
+Detects usage of vulnerable format string functions with unbounded ``%s``

EugeneZelenko wrote:

Please synchronize with statement in Release Notes.

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-02 Thread via cfe-commits


@@ -0,0 +1,33 @@
+// RUN: %check_clang_tidy %s bugprone-unsafe-format-string %t --\
+// RUN:  -config="{CheckOptions: 
{bugprone-unsafe-format-string.CustomPrintfFunctions: 'mysprintf, 1;', 
bugprone-unsafe-format-string.CustomScanfFunctions: 'myscanf, 0;'  }}"\
+// RUN: -- -isystem %S/Inputs/unsafe-format-string
+
+#include 
+
+extern int myscanf( const char* format, ... );
+extern int mysprintf( char* buffer, const char* format, ... );
+
+void test_sprintf() {
+  char buffer[100];
+  const char* input = "user input";
+
+  /* Positive: unsafe %s without field width */
+  mysprintf(buffer, "%s", input);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: format specifier '%s' without 
precision may cause buffer overflow; consider using '%.Ns' where N limits 
output length [bugprone-unsafe-format-string]
+  
+  mysprintf(buffer, "%.99s", input);
+  /*no warning*/
+}
+
+
+void test_scanf() {
+  char buffer[100];
+
+  /* Positive: unsafe %s without field width */
+  myscanf("%s", buffer);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: format specifier '%s' without 
field width may cause buffer overflow; consider using '%Ns' where N limits 
input length [bugprone-unsafe-format-string]
+
+  /*Negative: safe %s with field width */
+  myscanf("%99s", buffer);
+  /* no-warning */
+}

EugeneZelenko wrote:

Please add newline.

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-02 Thread via cfe-commits


@@ -0,0 +1,111 @@
+.. title:: clang-tidy - bugprone-unsafe-format-string
+
+bugprone-unsafe-format-string
+=
+
+Detects usage of vulnerable format string functions with unbounded ``%s``
+specifiers that can cause buffer overflows.
+
+The check identifies calls to format string functions like ``sprintf``, 
``scanf``,
+and their variants that use ``%s`` format specifiers without proper limits.
+This can lead to buffer overflow vulnerabilities when the input string is 
longer
+than the destination buffer.
+
+Format Specifier Behavior
+-
+
+The check distinguishes between different function families:
+
+**scanf family functions**: Field width limits input length
+  - ``%s`` - unsafe (no limit)
+  - ``%99s`` - safe (reads at most 99 characters)
+
+**sprintf family functions**: Precision limits output length
+  - ``%s`` - unsafe (no limit)
+  - ``%99s`` - unsafe (minimum width, no maximum)
+  - ``%.99s`` - safe (outputs at most 99 characters)
+  - ``%10.99s`` - safe (minimum 10 chars, maximum 99 chars)
+
+Examples
+
+
+.. code-block:: c
+
+  char buffer[100];
+  const char* input = "user input";
+  
+  // Unsafe sprintf usage
+  sprintf(buffer, "%s", input);  // No limit
+  sprintf(buffer, "%99s", input);// Field width is minimum, not maximum
+  
+  // Safe sprintf usage
+  sprintf(buffer, "%.99s", input);   // Precision limits to 99 chars
+  sprintf(buffer, "%10.99s", input); // Min 10, max 99 chars
+  
+  // Unsafe scanf usage
+  scanf("%s", buffer);   // No limit
+  
+  // Safe scanf usage
+  scanf("%99s", buffer); // Field width limits to 99 chars
+  
+  // Safe alternative: use safer functions
+  snprintf(buffer, sizeof(buffer), "%s", input);
+
+
+Checked Functions
+-
+
+The check detects unsafe format strings in these functions:
+
+**sprintf family** (precision ``.N`` provides safety):
+* ``sprintf``, ``vsprintf``
+
+**scanf family** (field width ``N`` provides safety):
+* ``scanf``, ``fscanf``, ``sscanf``
+* ``vscanf``, ``vfscanf``, ``vsscanf``
+* ``wscanf``, ``fwscanf``, ``swscanf``
+* ``vwscanf``, ``vfwscanf``, ``vswscanf``
+
+Configuration
+-
+
+The checker offers 2 configuration options.
+
+* `CustomPrintfFunctions` The user can specify own printf-like functions with 
dangerous format string parameter.
+* `CustomScanfFunctions` The user can specify own scanf-like functions with 
dangerous format string parameter.

EugeneZelenko wrote:

```suggestion
* `CustomPrintfFunctions` The user can specify own ``printf``-like functions 
with dangerous format string parameter.
* `CustomScanfFunctions` The user can specify own ``scanf``-like functions with 
dangerous format string parameter.
```

80-characters limit, please.

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-02 Thread via cfe-commits


@@ -0,0 +1,264 @@
+//===--===//
+//
+// 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 "UnsafeFormatStringCheck.h"
+#include "../utils/OptionsUtils.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+#include 
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+static constexpr llvm::StringLiteral OptionNameCustomPrintfFunctions =
+"CustomPrintfFunctions";
+static constexpr llvm::StringLiteral OptionNameCustomScanfFunctions =
+"CustomScanfFunctions";
+
+static constexpr llvm::StringLiteral BuiltInFormatBind = "format";
+static constexpr llvm::StringLiteral BuiltInCallBind = "call";
+static constexpr llvm::StringLiteral PrintfCallBind = "printfcall";
+static constexpr llvm::StringLiteral ScanfCallBind = "scanfcall";
+
+static std::vector
+parseCheckedFunctions(StringRef Option, ClangTidyContext *Context) {
+  const std::vector Functions =
+  utils::options::parseStringList(Option);
+  std::vector Result;
+  Result.reserve(Functions.size());
+
+  for (const StringRef Function : Functions) {
+if (Function.empty())
+  continue;
+const auto [Name, ParamCount] = Function.split(',');
+unsigned long Count = 0;
+if (Name.trim().empty() || ParamCount.trim().empty() ||
+ParamCount.trim().getAsInteger(10, Count)) {
+  Context->configurationDiag(
+  "invalid configuration value for option '%0'; "
+  "expected , ; pairs.")
+  << OptionNameCustomPrintfFunctions;
+  continue;
+}
+Result.push_back(
+{Name.trim().str(),
+ matchers::MatchesAnyListedNameMatcher::NameMatcher(Name.trim()),
+ Count});
+  }
+
+  return Result;
+}
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context),
+  CustomPrintfFunctions(parseCheckedFunctions(
+  Options.get(OptionNameCustomPrintfFunctions, ""), Context)),
+  CustomScanfFunctions(parseCheckedFunctions(
+  Options.get(OptionNameCustomScanfFunctions, ""), Context)) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");
+  Finder->addMatcher(
+  callExpr(
+  callee(functionDecl(VulnerableFunctions,
+  anyOf(isInStdNamespace(),
+hasDeclContext(translationUnitDecl(),
+  anyOf(hasArgument(0, stringLiteral().bind(BuiltInFormatBind)),
+hasArgument(1, stringLiteral().bind(BuiltInFormatBind
+  .bind(BuiltInCallBind),
+  this);
+
+  if (!CustomPrintfFunctions.empty()) {
+std::vector FunctionNames;
+FunctionNames.reserve(CustomPrintfFunctions.size());
+
+for (const auto &Entry : CustomPrintfFunctions)
+  FunctionNames.emplace_back(Entry.Name);
+
+auto CustomFunctionsMatcher = 
matchers::matchesAnyListedName(FunctionNames);
+
+Finder->addMatcher(callExpr(callee((functionDecl(CustomFunctionsMatcher
+   .bind(PrintfCallBind),
+   this);
+  }
+
+  if (!CustomScanfFunctions.empty()) {
+std::vector FunctionNames;
+FunctionNames.reserve(CustomScanfFunctions.size());
+
+for (const auto &Entry : CustomScanfFunctions)
+  FunctionNames.emplace_back(Entry.Name);
+
+auto CustomFunctionsMatcher = 
matchers::matchesAnyListedName(FunctionNames);
+
+Finder->addMatcher(callExpr(callee((functionDecl(CustomFunctionsMatcher
+   .bind(ScanfCallBind),
+   this);
+  }
+}
+
+void UnsafeFormatStringCheck::storeOptions(ClangTidyOptions::OptionMap &Opts) {
+  Options.store(Opts, OptionNameCustomPrintfFunctions, "");
+  Options.store(Opts, OptionNameCustomScanfFunctions, "");
+}
+
+const StringLiteral *UnsafeFormatStringCheck::getFormatLiteral(
+const CallExpr *Call, const std::vector &CustomFunctions) 
{
+  auto *FD = cast(Call->getDirectCallee());

EugeneZelenko wrote:

`const`?

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-02 Thread via cfe-commits


@@ -0,0 +1,111 @@
+.. title:: clang-tidy - bugprone-unsafe-format-string
+
+bugprone-unsafe-format-string
+=
+
+Detects usage of vulnerable format string functions with unbounded ``%s``
+specifiers that can cause buffer overflows.
+
+The check identifies calls to format string functions like ``sprintf``, 
``scanf``,
+and their variants that use ``%s`` format specifiers without proper limits.
+This can lead to buffer overflow vulnerabilities when the input string is 
longer
+than the destination buffer.
+
+Format Specifier Behavior
+-
+
+The check distinguishes between different function families:
+
+**scanf family functions**: Field width limits input length
+  - ``%s`` - unsafe (no limit)
+  - ``%99s`` - safe (reads at most 99 characters)
+
+**sprintf family functions**: Precision limits output length
+  - ``%s`` - unsafe (no limit)
+  - ``%99s`` - unsafe (minimum width, no maximum)
+  - ``%.99s`` - safe (outputs at most 99 characters)
+  - ``%10.99s`` - safe (minimum 10 chars, maximum 99 chars)
+
+Examples
+
+
+.. code-block:: c
+
+  char buffer[100];
+  const char* input = "user input";
+  
+  // Unsafe sprintf usage
+  sprintf(buffer, "%s", input);  // No limit
+  sprintf(buffer, "%99s", input);// Field width is minimum, not maximum
+  
+  // Safe sprintf usage
+  sprintf(buffer, "%.99s", input);   // Precision limits to 99 chars
+  sprintf(buffer, "%10.99s", input); // Min 10, max 99 chars
+  
+  // Unsafe scanf usage
+  scanf("%s", buffer);   // No limit
+  
+  // Safe scanf usage
+  scanf("%99s", buffer); // Field width limits to 99 chars
+  
+  // Safe alternative: use safer functions
+  snprintf(buffer, sizeof(buffer), "%s", input);
+
+
+Checked Functions
+-
+
+The check detects unsafe format strings in these functions:
+
+**sprintf family** (precision ``.N`` provides safety):
+* ``sprintf``, ``vsprintf``
+
+**scanf family** (field width ``N`` provides safety):
+* ``scanf``, ``fscanf``, ``sscanf``
+* ``vscanf``, ``vfscanf``, ``vsscanf``
+* ``wscanf``, ``fwscanf``, ``swscanf``
+* ``vwscanf``, ``vfwscanf``, ``vswscanf``
+
+Configuration
+-
+
+The checker offers 2 configuration options.
+
+* `CustomPrintfFunctions` The user can specify own printf-like functions with 
dangerous format string parameter.
+* `CustomScanfFunctions` The user can specify own scanf-like functions with 
dangerous format string parameter.
+
+Format:
+Both options have the following format.
+.. code::

EugeneZelenko wrote:

```suggestion
Both options have the following format:

.. code::
```

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-02 Thread via cfe-commits


@@ -202,6 +202,12 @@ New checks
   Detects default initialization (to 0) of variables with ``enum`` type where
   the enum has no enumerator with value of 0.
 
+- New :doc:`bugprone-unsafe-format-string
+  ` check.
+
+  Detects usage of vulnerable printf and scanf-like format 
+  string functions  with unbounded ``%s`` specifiers that can cause buffer 
overflows.

EugeneZelenko wrote:

```suggestion
  Detects usage of vulnerable ``printf`` and ``scanf``-like format string 
  functions with unbounded ``%s`` specifiers that can cause buffer overflows.
```

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-02 Thread Daniel Krupp via cfe-commits

https://github.com/dkrupp updated 
https://github.com/llvm/llvm-project/pull/168691

>From 03433eec012de3ad51e44d0d96721d004ef1c7d7 Mon Sep 17 00:00:00 2001
From: Daniel Krupp 
Date: Thu, 30 Oct 2025 13:39:23 +0100
Subject: [PATCH 1/9] [clang-tidy] New bugprone-unsafe-format-string check

Adds a new check which warns for the usage of unbounded %s format string 
specifiers
in the sprintf and scanf family functions, which may cause buffer overlfow.
---
 .../bugprone/BugproneTidyModule.cpp   |   3 +
 .../clang-tidy/bugprone/CMakeLists.txt|   1 +
 .../bugprone/UnsafeFormatStringCheck.cpp  | 149 +++
 .../bugprone/UnsafeFormatStringCheck.h|  34 +++
 .../checks/bugprone/unsafe-format-string.rst  |  73 ++
 .../system-header-simulator.h |  57 
 .../checkers/bugprone/unsafe-format-string.c  | 243 ++
 .../bugprone/unsafe-format-string.cpp |  58 +
 8 files changed, 618 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-format-string.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unsafe-format-string/system-header-simulator.h
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-format-string.c
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-format-string.cpp

diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp 
b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 6859dc97c112a..15e8a6c3afb6a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -107,6 +107,7 @@
 #include "UnintendedCharOstreamOutputCheck.h"
 #include "UniquePtrArrayMismatchCheck.h"
 #include "UnsafeFunctionsCheck.h"
+#include "UnsafeFormatStringCheck.h"
 #include "UnusedLocalNonTrivialVariableCheck.h"
 #include "UnusedRaiiCheck.h"
 #include "UnusedReturnValueCheck.h"
@@ -308,6 +309,8 @@ class BugproneModule : public ClangTidyModule {
 "bugprone-crtp-constructor-accessibility");
 CheckFactories.registerCheck(
 "bugprone-unsafe-functions");
+CheckFactories.registerCheck(
+"bugprone-unsafe-format-string");
 CheckFactories.registerCheck(
 "bugprone-unused-local-non-trivial-variable");
 CheckFactories.registerCheck("bugprone-unused-raii");
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index db1256d91d311..0e9439423ce5a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -108,6 +108,7 @@ add_clang_library(clangTidyBugproneModule STATIC
   UnhandledSelfAssignmentCheck.cpp
   UniquePtrArrayMismatchCheck.cpp
   UnsafeFunctionsCheck.cpp
+  UnsafeFormatStringCheck.cpp
   UnusedLocalNonTrivialVariableCheck.cpp
   UnusedRaiiCheck.cpp
   UnusedReturnValueCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
new file mode 100644
index 0..cd8f6b85ee1e2
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
@@ -0,0 +1,149 @@
+//===--- UnsafeFormatStringCheck.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 "UnsafeFormatStringCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");
+  Finder->addMatcher(
+  callExpr(callee(functionDecl(VulnerableFunctions,
+   anyOf(isInStdNamespace(),
+ hasParent(translationUnitDecl(),
+   anyOf(hasArgument(0, stringLiteral().bind("format")),
+ hasArgument(1, stringLiteral().bind

[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-02 Thread Daniel Krupp via cfe-commits

dkrupp wrote:

> Missing Release Notes entry.
> 
> How about custom `printf/scanf` functions?
> 
> Are similar functionality covered by `-Wformat` or Clang Static Analyzer?

Release notes extended.

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-02 Thread Daniel Krupp via cfe-commits

dkrupp wrote:

> Missing Release Notes entry.
> 
> How about custom `printf/scanf` functions?
> 
> Are similar functionality covered by `-Wformat` or Clang Static Analyzer?
There are related checkers, but they warn for different cases

-Wformat detects different cases. -Wformat-overflow is the closest, but it 
detects cases where the width specifier is present, but proven to be larger 
than the destination buffer. This check however always requieres  the width 
specifier to be present.

Clang Static Analyzer has a checker bans certain unsafe functions altogether, 
like scanf : 
https://clang.llvm.org/docs/analyzer/checkers.html#security-insecureapi-deprecatedorunsafebufferhandling-c

this check is less strict.



https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-02 Thread Daniel Krupp via cfe-commits

https://github.com/dkrupp updated 
https://github.com/llvm/llvm-project/pull/168691

>From 03433eec012de3ad51e44d0d96721d004ef1c7d7 Mon Sep 17 00:00:00 2001
From: Daniel Krupp 
Date: Thu, 30 Oct 2025 13:39:23 +0100
Subject: [PATCH 1/8] [clang-tidy] New bugprone-unsafe-format-string check

Adds a new check which warns for the usage of unbounded %s format string 
specifiers
in the sprintf and scanf family functions, which may cause buffer overlfow.
---
 .../bugprone/BugproneTidyModule.cpp   |   3 +
 .../clang-tidy/bugprone/CMakeLists.txt|   1 +
 .../bugprone/UnsafeFormatStringCheck.cpp  | 149 +++
 .../bugprone/UnsafeFormatStringCheck.h|  34 +++
 .../checks/bugprone/unsafe-format-string.rst  |  73 ++
 .../system-header-simulator.h |  57 
 .../checkers/bugprone/unsafe-format-string.c  | 243 ++
 .../bugprone/unsafe-format-string.cpp |  58 +
 8 files changed, 618 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-format-string.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unsafe-format-string/system-header-simulator.h
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-format-string.c
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-format-string.cpp

diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp 
b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 6859dc97c112a..15e8a6c3afb6a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -107,6 +107,7 @@
 #include "UnintendedCharOstreamOutputCheck.h"
 #include "UniquePtrArrayMismatchCheck.h"
 #include "UnsafeFunctionsCheck.h"
+#include "UnsafeFormatStringCheck.h"
 #include "UnusedLocalNonTrivialVariableCheck.h"
 #include "UnusedRaiiCheck.h"
 #include "UnusedReturnValueCheck.h"
@@ -308,6 +309,8 @@ class BugproneModule : public ClangTidyModule {
 "bugprone-crtp-constructor-accessibility");
 CheckFactories.registerCheck(
 "bugprone-unsafe-functions");
+CheckFactories.registerCheck(
+"bugprone-unsafe-format-string");
 CheckFactories.registerCheck(
 "bugprone-unused-local-non-trivial-variable");
 CheckFactories.registerCheck("bugprone-unused-raii");
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index db1256d91d311..0e9439423ce5a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -108,6 +108,7 @@ add_clang_library(clangTidyBugproneModule STATIC
   UnhandledSelfAssignmentCheck.cpp
   UniquePtrArrayMismatchCheck.cpp
   UnsafeFunctionsCheck.cpp
+  UnsafeFormatStringCheck.cpp
   UnusedLocalNonTrivialVariableCheck.cpp
   UnusedRaiiCheck.cpp
   UnusedReturnValueCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
new file mode 100644
index 0..cd8f6b85ee1e2
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
@@ -0,0 +1,149 @@
+//===--- UnsafeFormatStringCheck.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 "UnsafeFormatStringCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");
+  Finder->addMatcher(
+  callExpr(callee(functionDecl(VulnerableFunctions,
+   anyOf(isInStdNamespace(),
+ hasParent(translationUnitDecl(),
+   anyOf(hasArgument(0, stringLiteral().bind("format")),
+ hasArgument(1, stringLiteral().bind

[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-02 Thread Daniel Krupp via cfe-commits


@@ -0,0 +1,34 @@
+//===*- 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_UNSAFEFORMATSTRINGCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNSAFEFORMATSTRINGCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::bugprone {
+
+/// Detects usage of vulnerable format string functions with unbounded %s
+/// specifiers that can cause buffer overflows.
+///
+/// For the user-facing documentation see:
+/// 
https://clang.llvm.org/extra/clang-tidy/checks/bugprone/unsafe-format-string.html
+class UnsafeFormatStringCheck : public ClangTidyCheck {
+public:
+  UnsafeFormatStringCheck(StringRef Name, ClangTidyContext *Context);
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  bool hasUnboundedStringSpecifier(StringRef Fmt, bool IsScanfFamily);

dkrupp wrote:

done

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-02 Thread Daniel Krupp via cfe-commits

https://github.com/dkrupp updated 
https://github.com/llvm/llvm-project/pull/168691

>From 03433eec012de3ad51e44d0d96721d004ef1c7d7 Mon Sep 17 00:00:00 2001
From: Daniel Krupp 
Date: Thu, 30 Oct 2025 13:39:23 +0100
Subject: [PATCH 1/7] [clang-tidy] New bugprone-unsafe-format-string check

Adds a new check which warns for the usage of unbounded %s format string 
specifiers
in the sprintf and scanf family functions, which may cause buffer overlfow.
---
 .../bugprone/BugproneTidyModule.cpp   |   3 +
 .../clang-tidy/bugprone/CMakeLists.txt|   1 +
 .../bugprone/UnsafeFormatStringCheck.cpp  | 149 +++
 .../bugprone/UnsafeFormatStringCheck.h|  34 +++
 .../checks/bugprone/unsafe-format-string.rst  |  73 ++
 .../system-header-simulator.h |  57 
 .../checkers/bugprone/unsafe-format-string.c  | 243 ++
 .../bugprone/unsafe-format-string.cpp |  58 +
 8 files changed, 618 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-format-string.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unsafe-format-string/system-header-simulator.h
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-format-string.c
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-format-string.cpp

diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp 
b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 6859dc97c112a..15e8a6c3afb6a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -107,6 +107,7 @@
 #include "UnintendedCharOstreamOutputCheck.h"
 #include "UniquePtrArrayMismatchCheck.h"
 #include "UnsafeFunctionsCheck.h"
+#include "UnsafeFormatStringCheck.h"
 #include "UnusedLocalNonTrivialVariableCheck.h"
 #include "UnusedRaiiCheck.h"
 #include "UnusedReturnValueCheck.h"
@@ -308,6 +309,8 @@ class BugproneModule : public ClangTidyModule {
 "bugprone-crtp-constructor-accessibility");
 CheckFactories.registerCheck(
 "bugprone-unsafe-functions");
+CheckFactories.registerCheck(
+"bugprone-unsafe-format-string");
 CheckFactories.registerCheck(
 "bugprone-unused-local-non-trivial-variable");
 CheckFactories.registerCheck("bugprone-unused-raii");
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index db1256d91d311..0e9439423ce5a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -108,6 +108,7 @@ add_clang_library(clangTidyBugproneModule STATIC
   UnhandledSelfAssignmentCheck.cpp
   UniquePtrArrayMismatchCheck.cpp
   UnsafeFunctionsCheck.cpp
+  UnsafeFormatStringCheck.cpp
   UnusedLocalNonTrivialVariableCheck.cpp
   UnusedRaiiCheck.cpp
   UnusedReturnValueCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
new file mode 100644
index 0..cd8f6b85ee1e2
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
@@ -0,0 +1,149 @@
+//===--- UnsafeFormatStringCheck.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 "UnsafeFormatStringCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");
+  Finder->addMatcher(
+  callExpr(callee(functionDecl(VulnerableFunctions,
+   anyOf(isInStdNamespace(),
+ hasParent(translationUnitDecl(),
+   anyOf(hasArgument(0, stringLiteral().bind("format")),
+ hasArgument(1, stringLiteral().bind

[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-02 Thread Daniel Krupp via cfe-commits


@@ -0,0 +1,34 @@
+//===*- 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_UNSAFEFORMATSTRINGCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNSAFEFORMATSTRINGCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::bugprone {
+
+/// Detects usage of vulnerable format string functions with unbounded %s
+/// specifiers that can cause buffer overflows.
+///
+/// For the user-facing documentation see:
+/// 
https://clang.llvm.org/extra/clang-tidy/checks/bugprone/unsafe-format-string.html
+class UnsafeFormatStringCheck : public ClangTidyCheck {
+public:
+  UnsafeFormatStringCheck(StringRef Name, ClangTidyContext *Context);
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  bool hasUnboundedStringSpecifier(StringRef Fmt, bool IsScanfFamily);
+  std::string getSafeAlternative(StringRef FunctionName);

dkrupp wrote:

removed

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-02 Thread Daniel Krupp via cfe-commits


@@ -0,0 +1,153 @@
+//===--- UnsafeFormatStringCheck.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 "UnsafeFormatStringCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");

dkrupp wrote:

I added now to config options CustomPrintfFunctions and CustomScanfFunctions. 
We need both, as the format string handling is different.

Also extended the documentation and the test.

please check. thanks.

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-02 Thread Daniel Krupp via cfe-commits

https://github.com/dkrupp updated 
https://github.com/llvm/llvm-project/pull/168691

>From 03433eec012de3ad51e44d0d96721d004ef1c7d7 Mon Sep 17 00:00:00 2001
From: Daniel Krupp 
Date: Thu, 30 Oct 2025 13:39:23 +0100
Subject: [PATCH 1/6] [clang-tidy] New bugprone-unsafe-format-string check

Adds a new check which warns for the usage of unbounded %s format string 
specifiers
in the sprintf and scanf family functions, which may cause buffer overlfow.
---
 .../bugprone/BugproneTidyModule.cpp   |   3 +
 .../clang-tidy/bugprone/CMakeLists.txt|   1 +
 .../bugprone/UnsafeFormatStringCheck.cpp  | 149 +++
 .../bugprone/UnsafeFormatStringCheck.h|  34 +++
 .../checks/bugprone/unsafe-format-string.rst  |  73 ++
 .../system-header-simulator.h |  57 
 .../checkers/bugprone/unsafe-format-string.c  | 243 ++
 .../bugprone/unsafe-format-string.cpp |  58 +
 8 files changed, 618 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-format-string.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unsafe-format-string/system-header-simulator.h
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-format-string.c
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-format-string.cpp

diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp 
b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 6859dc97c112a..15e8a6c3afb6a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -107,6 +107,7 @@
 #include "UnintendedCharOstreamOutputCheck.h"
 #include "UniquePtrArrayMismatchCheck.h"
 #include "UnsafeFunctionsCheck.h"
+#include "UnsafeFormatStringCheck.h"
 #include "UnusedLocalNonTrivialVariableCheck.h"
 #include "UnusedRaiiCheck.h"
 #include "UnusedReturnValueCheck.h"
@@ -308,6 +309,8 @@ class BugproneModule : public ClangTidyModule {
 "bugprone-crtp-constructor-accessibility");
 CheckFactories.registerCheck(
 "bugprone-unsafe-functions");
+CheckFactories.registerCheck(
+"bugprone-unsafe-format-string");
 CheckFactories.registerCheck(
 "bugprone-unused-local-non-trivial-variable");
 CheckFactories.registerCheck("bugprone-unused-raii");
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index db1256d91d311..0e9439423ce5a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -108,6 +108,7 @@ add_clang_library(clangTidyBugproneModule STATIC
   UnhandledSelfAssignmentCheck.cpp
   UniquePtrArrayMismatchCheck.cpp
   UnsafeFunctionsCheck.cpp
+  UnsafeFormatStringCheck.cpp
   UnusedLocalNonTrivialVariableCheck.cpp
   UnusedRaiiCheck.cpp
   UnusedReturnValueCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
new file mode 100644
index 0..cd8f6b85ee1e2
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
@@ -0,0 +1,149 @@
+//===--- UnsafeFormatStringCheck.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 "UnsafeFormatStringCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");
+  Finder->addMatcher(
+  callExpr(callee(functionDecl(VulnerableFunctions,
+   anyOf(isInStdNamespace(),
+ hasParent(translationUnitDecl(),
+   anyOf(hasArgument(0, stringLiteral().bind("format")),
+ hasArgument(1, stringLiteral().bind

[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-02 Thread Daniel Krupp via cfe-commits

https://github.com/dkrupp updated 
https://github.com/llvm/llvm-project/pull/168691

>From 03433eec012de3ad51e44d0d96721d004ef1c7d7 Mon Sep 17 00:00:00 2001
From: Daniel Krupp 
Date: Thu, 30 Oct 2025 13:39:23 +0100
Subject: [PATCH 1/5] [clang-tidy] New bugprone-unsafe-format-string check

Adds a new check which warns for the usage of unbounded %s format string 
specifiers
in the sprintf and scanf family functions, which may cause buffer overlfow.
---
 .../bugprone/BugproneTidyModule.cpp   |   3 +
 .../clang-tidy/bugprone/CMakeLists.txt|   1 +
 .../bugprone/UnsafeFormatStringCheck.cpp  | 149 +++
 .../bugprone/UnsafeFormatStringCheck.h|  34 +++
 .../checks/bugprone/unsafe-format-string.rst  |  73 ++
 .../system-header-simulator.h |  57 
 .../checkers/bugprone/unsafe-format-string.c  | 243 ++
 .../bugprone/unsafe-format-string.cpp |  58 +
 8 files changed, 618 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-format-string.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unsafe-format-string/system-header-simulator.h
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-format-string.c
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-format-string.cpp

diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp 
b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 6859dc97c112a..15e8a6c3afb6a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -107,6 +107,7 @@
 #include "UnintendedCharOstreamOutputCheck.h"
 #include "UniquePtrArrayMismatchCheck.h"
 #include "UnsafeFunctionsCheck.h"
+#include "UnsafeFormatStringCheck.h"
 #include "UnusedLocalNonTrivialVariableCheck.h"
 #include "UnusedRaiiCheck.h"
 #include "UnusedReturnValueCheck.h"
@@ -308,6 +309,8 @@ class BugproneModule : public ClangTidyModule {
 "bugprone-crtp-constructor-accessibility");
 CheckFactories.registerCheck(
 "bugprone-unsafe-functions");
+CheckFactories.registerCheck(
+"bugprone-unsafe-format-string");
 CheckFactories.registerCheck(
 "bugprone-unused-local-non-trivial-variable");
 CheckFactories.registerCheck("bugprone-unused-raii");
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index db1256d91d311..0e9439423ce5a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -108,6 +108,7 @@ add_clang_library(clangTidyBugproneModule STATIC
   UnhandledSelfAssignmentCheck.cpp
   UniquePtrArrayMismatchCheck.cpp
   UnsafeFunctionsCheck.cpp
+  UnsafeFormatStringCheck.cpp
   UnusedLocalNonTrivialVariableCheck.cpp
   UnusedRaiiCheck.cpp
   UnusedReturnValueCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
new file mode 100644
index 0..cd8f6b85ee1e2
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
@@ -0,0 +1,149 @@
+//===--- UnsafeFormatStringCheck.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 "UnsafeFormatStringCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");
+  Finder->addMatcher(
+  callExpr(callee(functionDecl(VulnerableFunctions,
+   anyOf(isInStdNamespace(),
+ hasParent(translationUnitDecl(),
+   anyOf(hasArgument(0, stringLiteral().bind("format")),
+ hasArgument(1, stringLiteral().bind

[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-02 Thread Baranov Victor via cfe-commits


@@ -0,0 +1,34 @@
+//===*- 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_UNSAFEFORMATSTRINGCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNSAFEFORMATSTRINGCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::bugprone {
+
+/// Detects usage of vulnerable format string functions with unbounded %s
+/// specifiers that can cause buffer overflows.
+///
+/// For the user-facing documentation see:
+/// 
https://clang.llvm.org/extra/clang-tidy/checks/bugprone/unsafe-format-string.html
+class UnsafeFormatStringCheck : public ClangTidyCheck {
+public:
+  UnsafeFormatStringCheck(StringRef Name, ClangTidyContext *Context);
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  bool hasUnboundedStringSpecifier(StringRef Fmt, bool IsScanfFamily);
+  std::string getSafeAlternative(StringRef FunctionName);

vbvictor wrote:

is this used?

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-02 Thread Baranov Victor via cfe-commits


@@ -0,0 +1,34 @@
+//===*- 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_UNSAFEFORMATSTRINGCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNSAFEFORMATSTRINGCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::bugprone {
+
+/// Detects usage of vulnerable format string functions with unbounded %s
+/// specifiers that can cause buffer overflows.
+///
+/// For the user-facing documentation see:
+/// 
https://clang.llvm.org/extra/clang-tidy/checks/bugprone/unsafe-format-string.html
+class UnsafeFormatStringCheck : public ClangTidyCheck {
+public:
+  UnsafeFormatStringCheck(StringRef Name, ClangTidyContext *Context);
+  void registerMatchers(ast_matchers::MatchFinder *Finder) override;
+  void check(const ast_matchers::MatchFinder::MatchResult &Result) override;
+
+private:
+  bool hasUnboundedStringSpecifier(StringRef Fmt, bool IsScanfFamily);

vbvictor wrote:

Could we make this as pure `static` function in .cpp file or mark it as static 
here because we don't use class state 

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-02 Thread Baranov Victor via cfe-commits

vbvictor wrote:

> @vbvictor @EugeneZelenko thanks for your review. I tried to address your 
> comments.

Would you push the changes since linter is still broken but comment is marked 
as resolved?

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-12-02 Thread Baranov Victor via cfe-commits


@@ -0,0 +1,153 @@
+//===--- UnsafeFormatStringCheck.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 "UnsafeFormatStringCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");

vbvictor wrote:

I think it's reasonable to add it in current PR if you are not opposed to it.
`CustomPrintFunctions` seems good for me thought comma-separation style is a 
bit odd for clang-tidy but I don't see a better approach for now.


https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-28 Thread Baranov Victor via cfe-commits


@@ -0,0 +1,151 @@
+//===--===//
+//
+// 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 "UnsafeFormatStringCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");
+  Finder->addMatcher(
+  callExpr(
+  callee(functionDecl(VulnerableFunctions,
+  anyOf(isInStdNamespace(),
+hasDeclContext(translationUnitDecl(),
+  anyOf(hasArgument(0, stringLiteral().bind("format")),
+hasArgument(1, stringLiteral().bind("format"
+  .bind("call"),
+  this);
+}
+
+void UnsafeFormatStringCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("call");
+  const auto *Format = Result.Nodes.getNodeAs("format");
+
+  assert(Call && Format);
+
+  std::string FormatString;
+  if (Format->getCharByteWidth() == 1) {
+FormatString = Format->getString().str();
+  } else if (Format->getCharByteWidth() == 2) {
+// Handle wide strings by converting to narrow string for analysis
+convertUTF16ToUTF8String(Format->getBytes(), FormatString);
+  } else if (Format->getCharByteWidth() == 4) {
+// Handle wide strings by converting to narrow string for analysis
+convertUTF32ToUTF8String(Format->getBytes(), FormatString);
+  }
+
+  const auto *Callee = cast(Call->getCalleeDecl());
+  const StringRef FunctionName = Callee->getName();
+
+  const bool IsScanfFamily = FunctionName.contains("scanf");
+
+  if (!hasUnboundedStringSpecifier(FormatString, IsScanfFamily))
+return;
+
+  diag(Call->getBeginLoc(),
+   IsScanfFamily
+   ? "format specifier '%%s' without field width may cause buffer "
+ "overflow; consider using '%%Ns' where N limits input length"
+   : "format specifier '%%s' without precision may cause buffer "
+ "overflow; consider using '%%.Ns' where N limits output length")
+  << Call->getSourceRange();
+}
+
+bool UnsafeFormatStringCheck::hasUnboundedStringSpecifier(StringRef Fmt,
+  bool IsScanfFamily) {
+  size_t Pos = 0;
+  size_t N = Fmt.size();

vbvictor wrote:

It's reported in 
https://github.com/llvm/llvm-project/pull/168691#issuecomment-3552061977

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-28 Thread Daniel Krupp via cfe-commits

https://github.com/dkrupp commented:

@vbvictor @EugeneZelenko thanks for your review. I tried to address your 
comments.

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-28 Thread Daniel Krupp via cfe-commits


@@ -0,0 +1,153 @@
+//===--- UnsafeFormatStringCheck.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 "UnsafeFormatStringCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");

dkrupp wrote:

These functions are now matched against function int std namespace and globally.

I can imagine introducing 2 config variables:
CustomPrintfFunctions
CustomScanfFunctions

These would be a list of regex definable functions like in 
https://clang.llvm.org/extra/clang-tidy/checks/bugprone/unsafe-functions.html#cmdoption-arg-CustomFunctions

CustomPrintFunctions: "mysprintf, 0; mylogger, 1;"
Where the first argument is a regex matching the function name and the second 
parameter would be indicating which parameter contains the format string (0 is 
the first parameter).

We need to distinguish between scanf like and printf like functions, as their 
format strings behave differently.

Is that what you mean?
Should this be added in this PR or as a later improvement in a follow-up PR?

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-28 Thread Daniel Krupp via cfe-commits

https://github.com/dkrupp updated 
https://github.com/llvm/llvm-project/pull/168691

>From 03433eec012de3ad51e44d0d96721d004ef1c7d7 Mon Sep 17 00:00:00 2001
From: Daniel Krupp 
Date: Thu, 30 Oct 2025 13:39:23 +0100
Subject: [PATCH 1/4] [clang-tidy] New bugprone-unsafe-format-string check

Adds a new check which warns for the usage of unbounded %s format string 
specifiers
in the sprintf and scanf family functions, which may cause buffer overlfow.
---
 .../bugprone/BugproneTidyModule.cpp   |   3 +
 .../clang-tidy/bugprone/CMakeLists.txt|   1 +
 .../bugprone/UnsafeFormatStringCheck.cpp  | 149 +++
 .../bugprone/UnsafeFormatStringCheck.h|  34 +++
 .../checks/bugprone/unsafe-format-string.rst  |  73 ++
 .../system-header-simulator.h |  57 
 .../checkers/bugprone/unsafe-format-string.c  | 243 ++
 .../bugprone/unsafe-format-string.cpp |  58 +
 8 files changed, 618 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-format-string.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unsafe-format-string/system-header-simulator.h
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-format-string.c
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-format-string.cpp

diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp 
b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 6859dc97c112a..15e8a6c3afb6a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -107,6 +107,7 @@
 #include "UnintendedCharOstreamOutputCheck.h"
 #include "UniquePtrArrayMismatchCheck.h"
 #include "UnsafeFunctionsCheck.h"
+#include "UnsafeFormatStringCheck.h"
 #include "UnusedLocalNonTrivialVariableCheck.h"
 #include "UnusedRaiiCheck.h"
 #include "UnusedReturnValueCheck.h"
@@ -308,6 +309,8 @@ class BugproneModule : public ClangTidyModule {
 "bugprone-crtp-constructor-accessibility");
 CheckFactories.registerCheck(
 "bugprone-unsafe-functions");
+CheckFactories.registerCheck(
+"bugprone-unsafe-format-string");
 CheckFactories.registerCheck(
 "bugprone-unused-local-non-trivial-variable");
 CheckFactories.registerCheck("bugprone-unused-raii");
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index db1256d91d311..0e9439423ce5a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -108,6 +108,7 @@ add_clang_library(clangTidyBugproneModule STATIC
   UnhandledSelfAssignmentCheck.cpp
   UniquePtrArrayMismatchCheck.cpp
   UnsafeFunctionsCheck.cpp
+  UnsafeFormatStringCheck.cpp
   UnusedLocalNonTrivialVariableCheck.cpp
   UnusedRaiiCheck.cpp
   UnusedReturnValueCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
new file mode 100644
index 0..cd8f6b85ee1e2
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
@@ -0,0 +1,149 @@
+//===--- UnsafeFormatStringCheck.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 "UnsafeFormatStringCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");
+  Finder->addMatcher(
+  callExpr(callee(functionDecl(VulnerableFunctions,
+   anyOf(isInStdNamespace(),
+ hasParent(translationUnitDecl(),
+   anyOf(hasArgument(0, stringLiteral().bind("format")),
+ hasArgument(1, stringLiteral().bind

[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-28 Thread Daniel Krupp via cfe-commits


@@ -0,0 +1,243 @@
+// RUN: %check_clang_tidy %s bugprone-unsafe-format-string %t -- -- -isystem 
%S/Inputs/unsafe-format-string
+
+#include 
+
+void test_sprintf() {
+  char buffer[100];
+  const char* input = "user input";
+
+  /* Positive: unsafe %s without field width */
+  sprintf(buffer, "%s", input);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: format specifier '%s' without 
precision may cause buffer overflow; consider using '%.Ns' where N limits 
output length [bugprone-unsafe-format-string]
+
+  /* Positive: field width doesn't prevent overflow in sprintf */
+  sprintf(buffer, "%99s", input);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: format specifier '%s' without 
precision may cause buffer overflow; consider using '%.Ns' where N limits 
output length [bugprone-unsafe-format-string]
+
+  /* Positive: dynamic field width doesn't prevent overflow */
+  sprintf(buffer, "%*s", 10, input);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: format specifier '%s' without 
precision may cause buffer overflow; consider using '%.Ns' where N limits 
output length [bugprone-unsafe-format-string]
+
+  /*Negative: precision limits string length */
+  sprintf(buffer, "%.99s", input);
+  /* no-warning */

dkrupp wrote:

I would keep the comments then show test intent.

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-28 Thread Daniel Krupp via cfe-commits


@@ -0,0 +1,153 @@
+//===--- UnsafeFormatStringCheck.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 "UnsafeFormatStringCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");
+  Finder->addMatcher(
+  callExpr(callee(functionDecl(VulnerableFunctions,
+   anyOf(isInStdNamespace(),
+ hasParent(translationUnitDecl(),
+   anyOf(hasArgument(0, stringLiteral().bind("format")),
+ hasArgument(1, stringLiteral().bind("format"
+  .bind("call"),
+  this);
+}
+
+void UnsafeFormatStringCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("call");
+  const auto *Format = Result.Nodes.getNodeAs("format");
+
+  if (!Call || !Format)
+return;
+
+  std::string FormatString;
+  if (Format->getCharByteWidth() == 1) {
+FormatString = Format->getString().str();
+  } else if (Format->getCharByteWidth() == 2) {
+// Handle wide strings by converting to narrow string for analysis
+convertUTF16ToUTF8String(Format->getBytes(), FormatString);
+  } else if (Format->getCharByteWidth() == 4) {
+// Handle wide strings by converting to narrow string for analysis
+convertUTF32ToUTF8String(Format->getBytes(), FormatString);
+  }
+
+  const auto *Callee = cast(Call->getCalleeDecl());
+  StringRef FunctionName = Callee->getName();
+
+  bool IsScanfFamily = FunctionName.contains("scanf");
+
+  if (!hasUnboundedStringSpecifier(FormatString, IsScanfFamily))
+return;
+
+  auto Diag =
+  diag(
+  Call->getBeginLoc(),
+  IsScanfFamily
+  ? "format specifier '%%s' without field width may cause buffer "
+"overflow; consider using '%%Ns' where N limits input length"
+  : "format specifier '%%s' without precision may cause buffer "
+"overflow; consider using '%%.Ns' where N limits output 
length")
+  << Call->getSourceRange();
+}
+
+bool UnsafeFormatStringCheck::hasUnboundedStringSpecifier(StringRef Fmt,

dkrupp wrote:

This parser was implemented particularly for this checker.

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-21 Thread Baranov Victor via cfe-commits


@@ -0,0 +1,153 @@
+//===--- UnsafeFormatStringCheck.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 "UnsafeFormatStringCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");
+  Finder->addMatcher(
+  callExpr(callee(functionDecl(VulnerableFunctions,
+   anyOf(isInStdNamespace(),
+ hasParent(translationUnitDecl(),
+   anyOf(hasArgument(0, stringLiteral().bind("format")),
+ hasArgument(1, stringLiteral().bind("format"
+  .bind("call"),
+  this);
+}
+
+void UnsafeFormatStringCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("call");
+  const auto *Format = Result.Nodes.getNodeAs("format");
+
+  if (!Call || !Format)
+return;
+
+  std::string FormatString;
+  if (Format->getCharByteWidth() == 1) {
+FormatString = Format->getString().str();
+  } else if (Format->getCharByteWidth() == 2) {
+// Handle wide strings by converting to narrow string for analysis
+convertUTF16ToUTF8String(Format->getBytes(), FormatString);
+  } else if (Format->getCharByteWidth() == 4) {
+// Handle wide strings by converting to narrow string for analysis
+convertUTF32ToUTF8String(Format->getBytes(), FormatString);
+  }
+
+  const auto *Callee = cast(Call->getCalleeDecl());
+  StringRef FunctionName = Callee->getName();
+
+  bool IsScanfFamily = FunctionName.contains("scanf");
+
+  if (!hasUnboundedStringSpecifier(FormatString, IsScanfFamily))
+return;
+
+  auto Diag =

vbvictor wrote:

No need to declare variable

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-21 Thread Baranov Victor via cfe-commits


@@ -0,0 +1,153 @@
+//===--- UnsafeFormatStringCheck.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 "UnsafeFormatStringCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");
+  Finder->addMatcher(
+  callExpr(callee(functionDecl(VulnerableFunctions,
+   anyOf(isInStdNamespace(),
+ hasParent(translationUnitDecl(),

vbvictor wrote:

Use `hasDeclContext(translationUnitDecl())`.

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-21 Thread Baranov Victor via cfe-commits


@@ -0,0 +1,153 @@
+//===--- UnsafeFormatStringCheck.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 "UnsafeFormatStringCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");
+  Finder->addMatcher(
+  callExpr(callee(functionDecl(VulnerableFunctions,
+   anyOf(isInStdNamespace(),
+ hasParent(translationUnitDecl(),
+   anyOf(hasArgument(0, stringLiteral().bind("format")),
+ hasArgument(1, stringLiteral().bind("format"
+  .bind("call"),
+  this);
+}
+
+void UnsafeFormatStringCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("call");
+  const auto *Format = Result.Nodes.getNodeAs("format");
+
+  if (!Call || !Format)
+return;

vbvictor wrote:

We expect matchers to work, no need for this (or you can place assert).

```suggestion
```

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-21 Thread Baranov Victor via cfe-commits


@@ -0,0 +1,243 @@
+// RUN: %check_clang_tidy %s bugprone-unsafe-format-string %t -- -- -isystem 
%S/Inputs/unsafe-format-string
+
+#include 
+
+void test_sprintf() {
+  char buffer[100];
+  const char* input = "user input";
+
+  /* Positive: unsafe %s without field width */
+  sprintf(buffer, "%s", input);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: format specifier '%s' without 
precision may cause buffer overflow; consider using '%.Ns' where N limits 
output length [bugprone-unsafe-format-string]
+
+  /* Positive: field width doesn't prevent overflow in sprintf */
+  sprintf(buffer, "%99s", input);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: format specifier '%s' without 
precision may cause buffer overflow; consider using '%.Ns' where N limits 
output length [bugprone-unsafe-format-string]
+
+  /* Positive: dynamic field width doesn't prevent overflow */
+  sprintf(buffer, "%*s", 10, input);
+  // CHECK-MESSAGES: :[[@LINE-1]]:3: warning: format specifier '%s' without 
precision may cause buffer overflow; consider using '%.Ns' where N limits 
output length [bugprone-unsafe-format-string]
+
+  /*Negative: precision limits string length */
+  sprintf(buffer, "%.99s", input);
+  /* no-warning */

vbvictor wrote:

I think this is unnecessary to write in test files in general, but no strong 
objection

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-21 Thread Baranov Victor via cfe-commits


@@ -0,0 +1,153 @@
+//===--- UnsafeFormatStringCheck.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 "UnsafeFormatStringCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");
+  Finder->addMatcher(
+  callExpr(callee(functionDecl(VulnerableFunctions,
+   anyOf(isInStdNamespace(),
+ hasParent(translationUnitDecl(),
+   anyOf(hasArgument(0, stringLiteral().bind("format")),
+ hasArgument(1, stringLiteral().bind("format"
+  .bind("call"),
+  this);
+}
+
+void UnsafeFormatStringCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("call");
+  const auto *Format = Result.Nodes.getNodeAs("format");
+
+  if (!Call || !Format)
+return;
+
+  std::string FormatString;
+  if (Format->getCharByteWidth() == 1) {
+FormatString = Format->getString().str();
+  } else if (Format->getCharByteWidth() == 2) {
+// Handle wide strings by converting to narrow string for analysis
+convertUTF16ToUTF8String(Format->getBytes(), FormatString);
+  } else if (Format->getCharByteWidth() == 4) {
+// Handle wide strings by converting to narrow string for analysis
+convertUTF32ToUTF8String(Format->getBytes(), FormatString);
+  }
+
+  const auto *Callee = cast(Call->getCalleeDecl());
+  StringRef FunctionName = Callee->getName();
+
+  bool IsScanfFamily = FunctionName.contains("scanf");
+
+  if (!hasUnboundedStringSpecifier(FormatString, IsScanfFamily))
+return;
+
+  auto Diag =
+  diag(
+  Call->getBeginLoc(),
+  IsScanfFamily
+  ? "format specifier '%%s' without field width may cause buffer "
+"overflow; consider using '%%Ns' where N limits input length"
+  : "format specifier '%%s' without precision may cause buffer "
+"overflow; consider using '%%.Ns' where N limits output 
length")
+  << Call->getSourceRange();
+}
+
+bool UnsafeFormatStringCheck::hasUnboundedStringSpecifier(StringRef Fmt,

vbvictor wrote:

Is part of this was copied somewhere from clang codebase or purely hand-crafted?

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-21 Thread Baranov Victor via cfe-commits


@@ -0,0 +1,153 @@
+//===--- UnsafeFormatStringCheck.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 "UnsafeFormatStringCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");

vbvictor wrote:

This list should be converted into an option in case users use custom 
printf/scanf-like functions

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-20 Thread Daniel Krupp via cfe-commits

https://github.com/dkrupp edited 
https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-19 Thread via cfe-commits


@@ -0,0 +1,73 @@
+.. title:: clang-tidy - bugprone-unsafe-format-string
+
+bugprone-unsafe-format-string
+==

EugeneZelenko wrote:

```suggestion
bugprone-unsafe-format-string
=
```

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-19 Thread via cfe-commits


@@ -0,0 +1,34 @@
+//===--- UnsafeFormatStringCheck.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_UNSAFEFORMATSTRINGCHECK_H
+#define LLVM_CLANG_TOOLS_EXTRA_CLANG_TIDY_BUGPRONE_UNSAFEFORMATSTRINGCHECK_H
+
+#include "../ClangTidyCheck.h"
+
+namespace clang::tidy::bugprone {
+
+/// Detects usage of vulnerable format string functions with unbounded %s
+/// specifiers that can cause buffer overflows.
+///
+/// For the user-facing documentation see:
+/// 
http://clang.llvm.org/extra/clang-tidy/checks/bugprone/unsafe-format-string.html

EugeneZelenko wrote:

```suggestion
/// 
https://clang.llvm.org/extra/clang-tidy/checks/bugprone/unsafe-format-string.html
```

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-19 Thread via cfe-commits


@@ -0,0 +1,57 @@
+#pragma clang system_header
+
+#ifdef __cplusplus
+#define restrict /*restrict*/
+#endif
+
+#ifndef __cplusplus
+typedef __WCHAR_TYPE__ wchar_t;
+#endif
+
+typedef __typeof(sizeof(int)) size_t;
+typedef long long __int64_t;
+typedef __int64_t __darwin_off_t;
+typedef __darwin_off_t fpos_t;
+typedef int off_t;
+typedef long ssize_t;
+
+typedef struct _FILE FILE;
+
+extern FILE *stdin;
+extern FILE *stdout;
+extern FILE *stderr;
+
+typedef __builtin_va_list va_list;
+#define va_start(ap, param) __builtin_va_start(ap, param)
+#define va_end(ap)  __builtin_va_end(ap)
+#define va_arg(ap, type)__builtin_va_arg(ap, type)
+#define va_copy(dst, src)   __builtin_va_copy(dst, src)
+
+
+#ifdef __cplusplus
+namespace std {
+#endif
+extern int fscanf ( FILE *restrict stream, const char *restrict format, ... );
+extern int scanf ( const char *restrict format, ... );
+extern int sscanf ( const char *restrict s, const char *restrict format, ...);
+extern int vscanf( const char *restrict format, va_list vlist );
+extern int vfscanf ( FILE *restrict stream, const char *restrict format, 
va_list arg );
+
+extern int vsscanf( const char *restrict buffer, const char *restrict format, 
va_list vlist );
+extern int vwscanf( const wchar_t* format, va_list vlist );
+extern int vfwscanf( FILE* stream, const wchar_t* format, va_list vlist );
+extern int vswscanf( const wchar_t* buffer, const wchar_t* format, va_list 
vlist );
+extern int swscanf (const wchar_t* ws, const wchar_t* format, ...);
+extern int wscanf( const wchar_t *format, ... );
+extern int fwscanf( FILE *stream, const wchar_t *format, ... );
+
+extern int printf( const char*  format, ... );
+extern int sprintf( char* buffer, const char* format, ... );
+extern int vsprintf (char * s, const char * format, va_list arg );
+extern int vsnprintf (char * s, size_t n, const char * format, va_list arg );
+extern int fprintf( FILE*  stream, const char*  format, ... );
+extern int snprintf( char* restrict buffer, size_t bufsz,
+  const char* restrict format, ... );
+#ifdef __cplusplus
+} //namespace std {
+#endif

EugeneZelenko wrote:

Please add newline.

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-19 Thread via cfe-commits


@@ -108,6 +108,7 @@ add_clang_library(clangTidyBugproneModule STATIC
   UnhandledSelfAssignmentCheck.cpp
   UniquePtrArrayMismatchCheck.cpp
   UnsafeFunctionsCheck.cpp
+  UnsafeFormatStringCheck.cpp

EugeneZelenko wrote:

Ditto.

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-19 Thread via cfe-commits


@@ -308,6 +309,8 @@ class BugproneModule : public ClangTidyModule {
 "bugprone-crtp-constructor-accessibility");
 CheckFactories.registerCheck(
 "bugprone-unsafe-functions");
+CheckFactories.registerCheck(

EugeneZelenko wrote:

Should be before `bugprone-unsafe-functions`.

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-19 Thread via cfe-commits


@@ -0,0 +1,73 @@
+.. title:: clang-tidy - bugprone-unsafe-format-string
+
+bugprone-unsafe-format-string
+==
+
+Detects usage of vulnerable format string functions with unbounded ``%s``
+specifiers that can cause buffer overflows.
+
+The check identifies calls to format string functions like ``sprintf``, 
``scanf``,
+and their variants that use ``%s`` format specifiers without proper limits.
+This can lead to buffer overflow vulnerabilities when the input string is 
longer
+than the destination buffer.
+
+Format Specifier Behavior
+--

EugeneZelenko wrote:

```suggestion
Format Specifier Behavior
-
```

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-19 Thread via cfe-commits


@@ -0,0 +1,153 @@
+//===--- UnsafeFormatStringCheck.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 "UnsafeFormatStringCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");
+  Finder->addMatcher(
+  callExpr(callee(functionDecl(VulnerableFunctions,
+   anyOf(isInStdNamespace(),
+ hasParent(translationUnitDecl(),
+   anyOf(hasArgument(0, stringLiteral().bind("format")),
+ hasArgument(1, stringLiteral().bind("format"
+  .bind("call"),
+  this);
+}
+
+void UnsafeFormatStringCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("call");
+  const auto *Format = Result.Nodes.getNodeAs("format");
+
+  if (!Call || !Format)
+return;
+
+  std::string FormatString;
+  if (Format->getCharByteWidth() == 1) {
+FormatString = Format->getString().str();
+  } else if (Format->getCharByteWidth() == 2) {
+// Handle wide strings by converting to narrow string for analysis
+convertUTF16ToUTF8String(Format->getBytes(), FormatString);
+  } else if (Format->getCharByteWidth() == 4) {
+// Handle wide strings by converting to narrow string for analysis
+convertUTF32ToUTF8String(Format->getBytes(), FormatString);
+  }
+
+  const auto *Callee = cast(Call->getCalleeDecl());
+  StringRef FunctionName = Callee->getName();

EugeneZelenko wrote:

```suggestion
  const StringRef FunctionName = Callee->getName();
```

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-19 Thread via cfe-commits


@@ -0,0 +1,153 @@
+//===--- UnsafeFormatStringCheck.cpp - clang-tidy ---===//

EugeneZelenko wrote:

```suggestion
//===--===//
```

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-19 Thread via cfe-commits


@@ -0,0 +1,34 @@
+//===--- UnsafeFormatStringCheck.h - clang-tidy ---*- C++ -*-===//

EugeneZelenko wrote:

```suggestion
//===--===//
```

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-19 Thread via cfe-commits


@@ -0,0 +1,153 @@
+//===--- UnsafeFormatStringCheck.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 "UnsafeFormatStringCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");
+  Finder->addMatcher(
+  callExpr(callee(functionDecl(VulnerableFunctions,
+   anyOf(isInStdNamespace(),
+ hasParent(translationUnitDecl(),
+   anyOf(hasArgument(0, stringLiteral().bind("format")),
+ hasArgument(1, stringLiteral().bind("format"
+  .bind("call"),
+  this);
+}
+
+void UnsafeFormatStringCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("call");
+  const auto *Format = Result.Nodes.getNodeAs("format");
+
+  if (!Call || !Format)
+return;
+
+  std::string FormatString;
+  if (Format->getCharByteWidth() == 1) {
+FormatString = Format->getString().str();
+  } else if (Format->getCharByteWidth() == 2) {
+// Handle wide strings by converting to narrow string for analysis
+convertUTF16ToUTF8String(Format->getBytes(), FormatString);
+  } else if (Format->getCharByteWidth() == 4) {
+// Handle wide strings by converting to narrow string for analysis
+convertUTF32ToUTF8String(Format->getBytes(), FormatString);
+  }
+
+  const auto *Callee = cast(Call->getCalleeDecl());
+  StringRef FunctionName = Callee->getName();
+
+  bool IsScanfFamily = FunctionName.contains("scanf");

EugeneZelenko wrote:

```suggestion
  const bool IsScanfFamily = FunctionName.contains("scanf");
```

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-19 Thread via cfe-commits

https://github.com/EugeneZelenko commented:

Missing Release Notes entry.

How about custom `printf/scanf` functions?

Are similar functionality covered by `-Wformat` or Clang Static Analyzer?

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-19 Thread via cfe-commits

https://github.com/EugeneZelenko edited 
https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-19 Thread Daniel Krupp via cfe-commits

https://github.com/dkrupp updated 
https://github.com/llvm/llvm-project/pull/168691

>From 03433eec012de3ad51e44d0d96721d004ef1c7d7 Mon Sep 17 00:00:00 2001
From: Daniel Krupp 
Date: Thu, 30 Oct 2025 13:39:23 +0100
Subject: [PATCH 1/3] [clang-tidy] New bugprone-unsafe-format-string check

Adds a new check which warns for the usage of unbounded %s format string 
specifiers
in the sprintf and scanf family functions, which may cause buffer overlfow.
---
 .../bugprone/BugproneTidyModule.cpp   |   3 +
 .../clang-tidy/bugprone/CMakeLists.txt|   1 +
 .../bugprone/UnsafeFormatStringCheck.cpp  | 149 +++
 .../bugprone/UnsafeFormatStringCheck.h|  34 +++
 .../checks/bugprone/unsafe-format-string.rst  |  73 ++
 .../system-header-simulator.h |  57 
 .../checkers/bugprone/unsafe-format-string.c  | 243 ++
 .../bugprone/unsafe-format-string.cpp |  58 +
 8 files changed, 618 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-format-string.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unsafe-format-string/system-header-simulator.h
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-format-string.c
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-format-string.cpp

diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp 
b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 6859dc97c112a..15e8a6c3afb6a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -107,6 +107,7 @@
 #include "UnintendedCharOstreamOutputCheck.h"
 #include "UniquePtrArrayMismatchCheck.h"
 #include "UnsafeFunctionsCheck.h"
+#include "UnsafeFormatStringCheck.h"
 #include "UnusedLocalNonTrivialVariableCheck.h"
 #include "UnusedRaiiCheck.h"
 #include "UnusedReturnValueCheck.h"
@@ -308,6 +309,8 @@ class BugproneModule : public ClangTidyModule {
 "bugprone-crtp-constructor-accessibility");
 CheckFactories.registerCheck(
 "bugprone-unsafe-functions");
+CheckFactories.registerCheck(
+"bugprone-unsafe-format-string");
 CheckFactories.registerCheck(
 "bugprone-unused-local-non-trivial-variable");
 CheckFactories.registerCheck("bugprone-unused-raii");
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index db1256d91d311..0e9439423ce5a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -108,6 +108,7 @@ add_clang_library(clangTidyBugproneModule STATIC
   UnhandledSelfAssignmentCheck.cpp
   UniquePtrArrayMismatchCheck.cpp
   UnsafeFunctionsCheck.cpp
+  UnsafeFormatStringCheck.cpp
   UnusedLocalNonTrivialVariableCheck.cpp
   UnusedRaiiCheck.cpp
   UnusedReturnValueCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
new file mode 100644
index 0..cd8f6b85ee1e2
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
@@ -0,0 +1,149 @@
+//===--- UnsafeFormatStringCheck.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 "UnsafeFormatStringCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");
+  Finder->addMatcher(
+  callExpr(callee(functionDecl(VulnerableFunctions,
+   anyOf(isInStdNamespace(),
+ hasParent(translationUnitDecl(),
+   anyOf(hasArgument(0, stringLiteral().bind("format")),
+ hasArgument(1, stringLiteral().bind

[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-19 Thread via cfe-commits

github-actions[bot] wrote:


# :penguin: Linux x64 Test Results

* 3054 tests passed
* 7 tests skipped

https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-19 Thread via cfe-commits

github-actions[bot] wrote:




:warning: C/C++ code linter clang-tidy found issues in your code. :warning:



You can test this locally with the following command:


```bash

git diff -U0 origin/main...HEAD -- 
clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp 
clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.h 
clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp |
python3 clang-tools-extra/clang-tidy/tool/clang-tidy-diff.py \
  -path build -p1 -quiet
```





View the output from clang-tidy here.


```

clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.h:28:8: warning: 
function 
'clang::tidy::bugprone::UnsafeFormatStringCheck::hasUnboundedStringSpecifier' 
has a definition with different parameter names 
[readability-inconsistent-declaration-parameter-name]
   28 |   bool hasUnboundedStringSpecifier(StringRef FormatString, bool 
IsScanfFamily);
  |^
clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp:71:31: note: 
the definition seen here
   71 | bool UnsafeFormatStringCheck::hasUnboundedStringSpecifier(StringRef Fmt,
  |   ^
clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.h:28:8: note: 
differing parameters are named here: ('FormatString'), in definition: ('Fmt')
   28 |   bool hasUnboundedStringSpecifier(StringRef FormatString, bool 
IsScanfFamily);
  |^ 
  |  Fmt
```




https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-19 Thread via cfe-commits

github-actions[bot] wrote:




:warning: C/C++ code formatter, clang-format found issues in your code. 
:warning:



You can test this locally with the following command:


``bash
git-clang-format --diff origin/main HEAD --extensions cpp,h,c -- 
clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp 
clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.h 
clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unsafe-format-string/system-header-simulator.h
 clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-format-string.c 
clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-format-string.cpp 
clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp 
--diff_from_common_commit
``

:warning:
The reproduction instructions above might return results for more than one PR
in a stack if you are using a stacked PR workflow. You can limit the results by
changing `origin/main` to the base branch/commit you want to compare against.
:warning:





View the diff from clang-format here.


``diff
diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp 
b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 15e8a6c3a..940d13bf6 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -106,8 +106,8 @@
 #include "UnhandledSelfAssignmentCheck.h"
 #include "UnintendedCharOstreamOutputCheck.h"
 #include "UniquePtrArrayMismatchCheck.h"
-#include "UnsafeFunctionsCheck.h"
 #include "UnsafeFormatStringCheck.h"
+#include "UnsafeFunctionsCheck.h"
 #include "UnusedLocalNonTrivialVariableCheck.h"
 #include "UnusedRaiiCheck.h"
 #include "UnusedReturnValueCheck.h"
diff --git a/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
index cd8f6b85e..48a05aa27 100644
--- a/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
@@ -61,11 +61,15 @@ void UnsafeFormatStringCheck::check(const 
MatchFinder::MatchResult &Result) {
   if (!hasUnboundedStringSpecifier(FormatString, IsScanfFamily))
 return;
 
-  auto Diag = diag(Call->getBeginLoc(),
-   IsScanfFamily
- ? "format specifier '%%s' without field width may cause 
buffer overflow; consider using '%%Ns' where N limits input length"
- : "format specifier '%%s' without precision may cause 
buffer overflow; consider using '%%.Ns' where N limits output length")
-  << Call->getSourceRange();
+  auto Diag =
+  diag(
+  Call->getBeginLoc(),
+  IsScanfFamily
+  ? "format specifier '%%s' without field width may cause buffer "
+"overflow; consider using '%%Ns' where N limits input length"
+  : "format specifier '%%s' without precision may cause buffer "
+"overflow; consider using '%%.Ns' where N limits output 
length")
+  << Call->getSourceRange();
 }
 
 bool UnsafeFormatStringCheck::hasUnboundedStringSpecifier(StringRef Fmt,

``




https://github.com/llvm/llvm-project/pull/168691
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-19 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang-tools-extra

Author: Daniel Krupp (dkrupp)


Changes

Adds a new check which warns for the usage of unbounded %s format string 
specifiers in the sprintf and scanf family functions, which may cause buffer 
overlfow.

---

Patch is 24.95 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/168691.diff


8 Files Affected:

- (modified) clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp (+3) 
- (modified) clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt (+1) 
- (added) clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp 
(+149) 
- (added) clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.h (+34) 
- (added) 
clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-format-string.rst 
(+73) 
- (added) 
clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unsafe-format-string/system-header-simulator.h
 (+57) 
- (added) 
clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-format-string.c 
(+243) 
- (added) 
clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-format-string.cpp 
(+58) 


``diff
diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp 
b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 6859dc97c112a..15e8a6c3afb6a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -107,6 +107,7 @@
 #include "UnintendedCharOstreamOutputCheck.h"
 #include "UniquePtrArrayMismatchCheck.h"
 #include "UnsafeFunctionsCheck.h"
+#include "UnsafeFormatStringCheck.h"
 #include "UnusedLocalNonTrivialVariableCheck.h"
 #include "UnusedRaiiCheck.h"
 #include "UnusedReturnValueCheck.h"
@@ -308,6 +309,8 @@ class BugproneModule : public ClangTidyModule {
 "bugprone-crtp-constructor-accessibility");
 CheckFactories.registerCheck(
 "bugprone-unsafe-functions");
+CheckFactories.registerCheck(
+"bugprone-unsafe-format-string");
 CheckFactories.registerCheck(
 "bugprone-unused-local-non-trivial-variable");
 CheckFactories.registerCheck("bugprone-unused-raii");
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index db1256d91d311..0e9439423ce5a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -108,6 +108,7 @@ add_clang_library(clangTidyBugproneModule STATIC
   UnhandledSelfAssignmentCheck.cpp
   UniquePtrArrayMismatchCheck.cpp
   UnsafeFunctionsCheck.cpp
+  UnsafeFormatStringCheck.cpp
   UnusedLocalNonTrivialVariableCheck.cpp
   UnusedRaiiCheck.cpp
   UnusedReturnValueCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
new file mode 100644
index 0..cd8f6b85ee1e2
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
@@ -0,0 +1,149 @@
+//===--- UnsafeFormatStringCheck.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 "UnsafeFormatStringCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");
+  Finder->addMatcher(
+  callExpr(callee(functionDecl(VulnerableFunctions,
+   anyOf(isInStdNamespace(),
+ hasParent(translationUnitDecl(),
+   anyOf(hasArgument(0, stringLiteral().bind("format")),
+ hasArgument(1, stringLiteral().bind("format"
+  .bind("call"),
+  this);
+}
+
+void UnsafeFormatStringCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("call");
+  const auto *Format = Result.Nodes.getNodeAs("format");
+
+  if (!Call || !Format)
+return;
+
+  std::string FormatString;
+  if (Format->getCharByteWidth() == 1) {
+FormatString = Format->getString().str();

[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-19 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-clang-tidy

Author: Daniel Krupp (dkrupp)


Changes

Adds a new check which warns for the usage of unbounded %s format string 
specifiers in the sprintf and scanf family functions, which may cause buffer 
overlfow.

---

Patch is 24.95 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/168691.diff


8 Files Affected:

- (modified) clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp (+3) 
- (modified) clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt (+1) 
- (added) clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp 
(+149) 
- (added) clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.h (+34) 
- (added) 
clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-format-string.rst 
(+73) 
- (added) 
clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unsafe-format-string/system-header-simulator.h
 (+57) 
- (added) 
clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-format-string.c 
(+243) 
- (added) 
clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-format-string.cpp 
(+58) 


``diff
diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp 
b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 6859dc97c112a..15e8a6c3afb6a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -107,6 +107,7 @@
 #include "UnintendedCharOstreamOutputCheck.h"
 #include "UniquePtrArrayMismatchCheck.h"
 #include "UnsafeFunctionsCheck.h"
+#include "UnsafeFormatStringCheck.h"
 #include "UnusedLocalNonTrivialVariableCheck.h"
 #include "UnusedRaiiCheck.h"
 #include "UnusedReturnValueCheck.h"
@@ -308,6 +309,8 @@ class BugproneModule : public ClangTidyModule {
 "bugprone-crtp-constructor-accessibility");
 CheckFactories.registerCheck(
 "bugprone-unsafe-functions");
+CheckFactories.registerCheck(
+"bugprone-unsafe-format-string");
 CheckFactories.registerCheck(
 "bugprone-unused-local-non-trivial-variable");
 CheckFactories.registerCheck("bugprone-unused-raii");
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index db1256d91d311..0e9439423ce5a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -108,6 +108,7 @@ add_clang_library(clangTidyBugproneModule STATIC
   UnhandledSelfAssignmentCheck.cpp
   UniquePtrArrayMismatchCheck.cpp
   UnsafeFunctionsCheck.cpp
+  UnsafeFormatStringCheck.cpp
   UnusedLocalNonTrivialVariableCheck.cpp
   UnusedRaiiCheck.cpp
   UnusedReturnValueCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
new file mode 100644
index 0..cd8f6b85ee1e2
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
@@ -0,0 +1,149 @@
+//===--- UnsafeFormatStringCheck.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 "UnsafeFormatStringCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");
+  Finder->addMatcher(
+  callExpr(callee(functionDecl(VulnerableFunctions,
+   anyOf(isInStdNamespace(),
+ hasParent(translationUnitDecl(),
+   anyOf(hasArgument(0, stringLiteral().bind("format")),
+ hasArgument(1, stringLiteral().bind("format"
+  .bind("call"),
+  this);
+}
+
+void UnsafeFormatStringCheck::check(const MatchFinder::MatchResult &Result) {
+  const auto *Call = Result.Nodes.getNodeAs("call");
+  const auto *Format = Result.Nodes.getNodeAs("format");
+
+  if (!Call || !Format)
+return;
+
+  std::string FormatString;
+  if (Format->getCharByteWidth() == 1) {
+FormatString = Format->getString().str();
+  } e

[clang-tools-extra] [clang-tidy] New bugprone-unsafe-format-string check (PR #168691)

2025-11-19 Thread Daniel Krupp via cfe-commits

https://github.com/dkrupp created 
https://github.com/llvm/llvm-project/pull/168691

Adds a new check which warns for the usage of unbounded %s format string 
specifiers in the sprintf and scanf family functions, which may cause buffer 
overlfow.

>From 03433eec012de3ad51e44d0d96721d004ef1c7d7 Mon Sep 17 00:00:00 2001
From: Daniel Krupp 
Date: Thu, 30 Oct 2025 13:39:23 +0100
Subject: [PATCH] [clang-tidy] New bugprone-unsafe-format-string check

Adds a new check which warns for the usage of unbounded %s format string 
specifiers
in the sprintf and scanf family functions, which may cause buffer overlfow.
---
 .../bugprone/BugproneTidyModule.cpp   |   3 +
 .../clang-tidy/bugprone/CMakeLists.txt|   1 +
 .../bugprone/UnsafeFormatStringCheck.cpp  | 149 +++
 .../bugprone/UnsafeFormatStringCheck.h|  34 +++
 .../checks/bugprone/unsafe-format-string.rst  |  73 ++
 .../system-header-simulator.h |  57 
 .../checkers/bugprone/unsafe-format-string.c  | 243 ++
 .../bugprone/unsafe-format-string.cpp |  58 +
 8 files changed, 618 insertions(+)
 create mode 100644 
clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
 create mode 100644 
clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.h
 create mode 100644 
clang-tools-extra/docs/clang-tidy/checks/bugprone/unsafe-format-string.rst
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/Inputs/unsafe-format-string/system-header-simulator.h
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-format-string.c
 create mode 100644 
clang-tools-extra/test/clang-tidy/checkers/bugprone/unsafe-format-string.cpp

diff --git a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp 
b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
index 6859dc97c112a..15e8a6c3afb6a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
+++ b/clang-tools-extra/clang-tidy/bugprone/BugproneTidyModule.cpp
@@ -107,6 +107,7 @@
 #include "UnintendedCharOstreamOutputCheck.h"
 #include "UniquePtrArrayMismatchCheck.h"
 #include "UnsafeFunctionsCheck.h"
+#include "UnsafeFormatStringCheck.h"
 #include "UnusedLocalNonTrivialVariableCheck.h"
 #include "UnusedRaiiCheck.h"
 #include "UnusedReturnValueCheck.h"
@@ -308,6 +309,8 @@ class BugproneModule : public ClangTidyModule {
 "bugprone-crtp-constructor-accessibility");
 CheckFactories.registerCheck(
 "bugprone-unsafe-functions");
+CheckFactories.registerCheck(
+"bugprone-unsafe-format-string");
 CheckFactories.registerCheck(
 "bugprone-unused-local-non-trivial-variable");
 CheckFactories.registerCheck("bugprone-unused-raii");
diff --git a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt 
b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
index db1256d91d311..0e9439423ce5a 100644
--- a/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
+++ b/clang-tools-extra/clang-tidy/bugprone/CMakeLists.txt
@@ -108,6 +108,7 @@ add_clang_library(clangTidyBugproneModule STATIC
   UnhandledSelfAssignmentCheck.cpp
   UniquePtrArrayMismatchCheck.cpp
   UnsafeFunctionsCheck.cpp
+  UnsafeFormatStringCheck.cpp
   UnusedLocalNonTrivialVariableCheck.cpp
   UnusedRaiiCheck.cpp
   UnusedReturnValueCheck.cpp
diff --git a/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp 
b/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
new file mode 100644
index 0..cd8f6b85ee1e2
--- /dev/null
+++ b/clang-tools-extra/clang-tidy/bugprone/UnsafeFormatStringCheck.cpp
@@ -0,0 +1,149 @@
+//===--- UnsafeFormatStringCheck.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 "UnsafeFormatStringCheck.h"
+#include "clang/ASTMatchers/ASTMatchFinder.h"
+#include "llvm/Support/ConvertUTF.h"
+
+using namespace clang::ast_matchers;
+
+namespace clang::tidy::bugprone {
+
+UnsafeFormatStringCheck::UnsafeFormatStringCheck(StringRef Name,
+ ClangTidyContext *Context)
+: ClangTidyCheck(Name, Context) {}
+
+void UnsafeFormatStringCheck::registerMatchers(MatchFinder *Finder) {
+  // Matches sprintf and scanf family functions in std namespace in C++ and
+  // globally in C.
+  auto VulnerableFunctions =
+  hasAnyName("sprintf", "vsprintf", "scanf", "fscanf", "sscanf", "vscanf",
+ "vfscanf", "vsscanf", "wscanf", "fwscanf", "swscanf",
+ "vwscanf", "vfwscanf", "vswscanf");
+  Finder->addMatcher(
+  callExpr(callee(functionDecl(VulnerableFunctions,
+   anyOf(isInStdNamespace(),
+ hasPa