llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang-analysis

Author: Ilyas Mallah (ilyas-mallah)

<details>
<summary>Changes</summary>

Depends on #<!-- -->232898. The first commit is from that PR, so only the 
second one is new here.

#<!-- -->127849 asks to turn off `strlen` while keeping `memcpy`, which isn't 
possible while all unsafe libc calls share one diagnostic. Clang can't create 
warning groups at run time, and one group per function would be about 70 
diagnostics. So each family that `PredefinedNames` already lists in its 
comments gets a subgroup of `-Wunsafe-buffer-usage-in-libc-call`: 
numeric-conversion, string-manipulation, string-examination, memory, io, printf 
and scanf.

The parent flag, `-Werror=` included, still covers all of them, and the warning 
text doesn't change. `strerror_s`, `strerror_r`, `bsearch` and `qsort` have no 
family and stay under the parent only. `bcopy` and `bzero` moved from "others" 
to memory. A call whose family is off is dropped in the reporter, so a libc 
`printf` never moves to `-Wunsafe-buffer-usage-in-format-attr-call`.

Fixes #<!-- -->127849.

AI usage: Claude Code helped with the test runs and test scaffolding. I traced 
the issue, made the fix, and validated every change.


---

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


8 Files Affected:

- (modified) clang/docs/ReleaseNotes.md (+12) 
- (modified) clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h (+23-1) 
- (modified) clang/include/clang/Basic/DiagnosticGroups.td (+8-1) 
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (+19-2) 
- (modified) clang/lib/Analysis/UnsafeBufferUsage.cpp (+140-83) 
- (modified) clang/lib/Sema/AnalysisBasedWarnings.cpp (+50-5) 
- (added) clang/test/SemaCXX/warn-unsafe-buffer-usage-in-format-attr-call.cpp 
(+36) 
- (added) 
clang/test/SemaCXX/warn-unsafe-buffer-usage-in-libc-call-subgroups.cpp (+66) 


``````````diff
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index aba1dba5854fea..c8247f2e91562d 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -679,6 +679,18 @@ features cannot lower the translation-unit ABI level;
   `-Wunsafe-buffer-usage` to control warnings on `main`'s `argv` parameter,
   allowing users to suppress them with `-Wno-unsafe-buffer-usage-main-argv`.
 
+- `-Wno-unsafe-buffer-usage-in-libc-call` no longer turns off
+  `-Wunsafe-buffer-usage-in-format-attr-call`, and
+  `-Wunsafe-buffer-usage-in-format-attr-call` now works when it is the only
+  Safe Buffers warning enabled.
+
+- Added one diagnostic group per family of libc functions under
+  `-Wunsafe-buffer-usage-in-libc-call`, named by the suffixes
+  `-numeric-conversion`, `-string-manipulation`, `-string-examination`,
+  `-memory`, `-io`, `-printf` and `-scanf`. For example,
+  `-Wno-unsafe-buffer-usage-in-libc-call-string-examination` silences `strlen`
+  while `memcpy` is still diagnosed. (#GH127849)
+
 ### Improvements to Clang's time-trace
 
 ### Improvements to Coverage Mapping
diff --git a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h 
b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
index 05a580bed5c39a..f9fb731e489ed4 100644
--- a/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
+++ b/clang/include/clang/Analysis/Analyses/UnsafeBufferUsage.h
@@ -82,6 +82,19 @@ class FixitStrategy {
   }
 };
 
+/// The family of an unsafe libc function. Each family except `Other` has its
+/// own subgroup of -Wunsafe-buffer-usage-in-libc-call.
+enum class UnsafeLibcFunctionFamily {
+  Other,
+  NumericConversion,
+  StringManipulation,
+  StringExamination,
+  Memory,
+  IO,
+  Printf,
+  Scanf,
+};
+
 /// The interface that lets the caller handle unsafe buffer usage analysis
 /// results by overriding this class's handle... methods.
 class UnsafeBufferUsageHandler {
@@ -118,9 +131,12 @@ class UnsafeBufferUsageHandler {
   ///  is 3 if string arguments do not guarantee null-termination
   ///  is 4 if the callee takes va_list
   ///  has bit 3 (0x8) set if the callee is a function with the format 
attribute
+  /// \param Family the family of the callee, ignored when `PrintfInfo` has the
+  /// format attribute bit set
   /// \param UnsafeArg one of the actual arguments that is unsafe, non-null
   /// only when `2 <= PrintfInfo <= 3 (ignoring the "format attribute" bit)`
   virtual void handleUnsafeLibcCall(const CallExpr *Call, unsigned PrintfInfo,
+                                    UnsafeLibcFunctionFamily Family,
                                     ASTContext &Ctx,
                                     const Expr *UnsafeArg = nullptr) = 0;
 
@@ -179,10 +195,16 @@ class UnsafeBufferUsageHandler {
   virtual bool
   ignoreUnsafeBufferInContainer(const SourceLocation &Loc) const = 0;
 
-  /// \return true iff unsafe libc call should NOT be reported at `Loc`
+  /// \return true iff every kind of unsafe libc call warning should NOT be
+  /// reported at `Loc`
   virtual bool
   ignoreUnsafeBufferInLibcCall(const SourceLocation &Loc) const = 0;
 
+  /// \return true iff unsafe calls to functions with the format attribute
+  /// should NOT be reported at `Loc`
+  virtual bool
+  ignoreUnsafeBufferInFormatAttrCall(const SourceLocation &Loc) const = 0;
+
   /// \return true iff array subscript accesses on fixed size arrays should NOT
   /// be reported at `Loc`
   virtual bool
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td 
b/clang/include/clang/Basic/DiagnosticGroups.td
index b6c7ff7276260f..c025b4e0366690 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -2004,7 +2004,14 @@ def ReadOnlyPlacementChecks : 
DiagGroup<"read-only-types">;
 
 // Warnings and fixes to support the "safe buffers" programming model.
 def UnsafeBufferUsageInContainer : 
DiagGroup<"unsafe-buffer-usage-in-container">;
-def UnsafeBufferUsageInLibcCall : 
DiagGroup<"unsafe-buffer-usage-in-libc-call">;
+def UnsafeBufferUsageInLibcCallNumericConversion : 
DiagGroup<"unsafe-buffer-usage-in-libc-call-numeric-conversion">;
+def UnsafeBufferUsageInLibcCallStringManipulation : 
DiagGroup<"unsafe-buffer-usage-in-libc-call-string-manipulation">;
+def UnsafeBufferUsageInLibcCallStringExamination : 
DiagGroup<"unsafe-buffer-usage-in-libc-call-string-examination">;
+def UnsafeBufferUsageInLibcCallMemory : 
DiagGroup<"unsafe-buffer-usage-in-libc-call-memory">;
+def UnsafeBufferUsageInLibcCallIO : 
DiagGroup<"unsafe-buffer-usage-in-libc-call-io">;
+def UnsafeBufferUsageInLibcCallPrintf : 
DiagGroup<"unsafe-buffer-usage-in-libc-call-printf">;
+def UnsafeBufferUsageInLibcCallScanf : 
DiagGroup<"unsafe-buffer-usage-in-libc-call-scanf">;
+def UnsafeBufferUsageInLibcCall : 
DiagGroup<"unsafe-buffer-usage-in-libc-call", 
[UnsafeBufferUsageInLibcCallNumericConversion, 
UnsafeBufferUsageInLibcCallStringManipulation, 
UnsafeBufferUsageInLibcCallStringExamination, 
UnsafeBufferUsageInLibcCallMemory, UnsafeBufferUsageInLibcCallIO, 
UnsafeBufferUsageInLibcCallPrintf, UnsafeBufferUsageInLibcCallScanf]>;
 def UnsafeBufferUsageInUniquePtrArrayAccess : 
DiagGroup<"unsafe-buffer-usage-in-unique-ptr-array-access">;
 def UnsafeBufferUsageInStaticSizedArray : 
DiagGroup<"unsafe-buffer-usage-in-static-sized-array">;
 def UnsafeBufferUsageInFormatAttrCall : 
DiagGroup<"unsafe-buffer-usage-in-format-attr-call">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td 
b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 48b166d2a48a05..2084bedcf38991 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -13988,6 +13988,7 @@ defvar UnsafeBufferOperationMsg =
   "%select{unsafe pointer operation|unsafe pointer arithmetic|"
   "unsafe buffer access|function introduces unsafe buffer manipulation|"
   "unsafe invocation of %1|field %1 prone to unsafe buffer manipulation}0";
+defvar UnsafeBufferLibcCallMsg = "function %0 is unsafe";
 def warn_unsafe_buffer_variable : Warning<UnsafeBufferVariableMsg>,
   InGroup<UnsafeBufferUsage>, DefaultIgnore;
 def warn_unsafe_buffer_variable_main_argv : Warning<UnsafeBufferVariableMsg>,
@@ -13996,9 +13997,25 @@ def warn_unsafe_buffer_operation : 
Warning<UnsafeBufferOperationMsg>,
   InGroup<UnsafeBufferUsage>, DefaultIgnore;
 def warn_unsafe_buffer_operation_main_argv : Warning<UnsafeBufferOperationMsg>,
   InGroup<UnsafeBufferUsageMainArgv>, DefaultIgnore;
-def warn_unsafe_buffer_libc_call : Warning<
-  "function %0 is unsafe">,
+def warn_unsafe_buffer_libc_call : Warning<UnsafeBufferLibcCallMsg>,
   InGroup<UnsafeBufferUsageInLibcCall>, DefaultIgnore;
+def warn_unsafe_buffer_libc_call_numeric_conversion :
+  Warning<UnsafeBufferLibcCallMsg>,
+  InGroup<UnsafeBufferUsageInLibcCallNumericConversion>, DefaultIgnore;
+def warn_unsafe_buffer_libc_call_string_manipulation :
+  Warning<UnsafeBufferLibcCallMsg>,
+  InGroup<UnsafeBufferUsageInLibcCallStringManipulation>, DefaultIgnore;
+def warn_unsafe_buffer_libc_call_string_examination :
+  Warning<UnsafeBufferLibcCallMsg>,
+  InGroup<UnsafeBufferUsageInLibcCallStringExamination>, DefaultIgnore;
+def warn_unsafe_buffer_libc_call_memory : Warning<UnsafeBufferLibcCallMsg>,
+  InGroup<UnsafeBufferUsageInLibcCallMemory>, DefaultIgnore;
+def warn_unsafe_buffer_libc_call_io : Warning<UnsafeBufferLibcCallMsg>,
+  InGroup<UnsafeBufferUsageInLibcCallIO>, DefaultIgnore;
+def warn_unsafe_buffer_libc_call_printf : Warning<UnsafeBufferLibcCallMsg>,
+  InGroup<UnsafeBufferUsageInLibcCallPrintf>, DefaultIgnore;
+def warn_unsafe_buffer_libc_call_scanf : Warning<UnsafeBufferLibcCallMsg>,
+  InGroup<UnsafeBufferUsageInLibcCallScanf>, DefaultIgnore;
 def warn_unsafe_buffer_format_attr_call : Warning<
   "formatting function %0 is unsafe">,
   InGroup<UnsafeBufferUsageInFormatAttrCall>, DefaultIgnore;
diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index 09f610358ca65e..ce8d8e63b39674 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -31,6 +31,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/STLFunctionalExtras.h"
 #include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringMap.h"
 #include "llvm/ADT/StringRef.h"
 #include <cstddef>
 #include <optional>
@@ -299,6 +300,14 @@ static bool ignoreUnsafeLibcCall(const ASTContext &Ctx, 
const Stmt &Node,
   return true; /* Only warn about libc calls for C++ */
 }
 
+static bool
+ignoreUnsafeFormatAttrCall(const ASTContext &Ctx, const Stmt &Node,
+                           const UnsafeBufferUsageHandler *Handler) {
+  if (Ctx.getLangOpts().CPlusPlus)
+    return Handler->ignoreUnsafeBufferInFormatAttrCall(Node.getBeginLoc());
+  return true; /* Only warn about format attribute calls for C++ */
+}
+
 // Finds any expression 'e' such that `OnResult`
 // matches 'e' and 'e' is in an Unspecified Lvalue Context.
 static void findStmtsInUnspecifiedLvalueContext(
@@ -1140,93 +1149,97 @@ hasUnsafeFormatOrSArg(ASTContext &Ctx, const CallExpr 
*Call,
 //  1. It's name, after stripping off predefined prefix and suffix, is
 //     `CoreName`; and
 //  2. `CoreName` or `CoreName[str/wcs]` is one of the `PredefinedNames`, which
-//     is a set of libc function names.
+//     maps libc function names to their families.
 //
 //  Note: For predefined prefix and suffix, see `matchName()`.
 //  The notation `CoreName[str/wcs]` means a new name obtained from replace
 //  string "wcs" with "str" in `CoreName`.
-static bool isPredefinedUnsafeLibcFunc(const FunctionDecl &Node) {
-  static const std::set<StringRef> PredefinedNames = {
+//
+// Returns the family of the matched function, or std::nullopt if it does not
+// match.
+static std::optional<UnsafeLibcFunctionFamily>
+getPredefinedUnsafeLibcFuncFamily(const FunctionDecl &Node) {
+  static const llvm::StringMap<UnsafeLibcFunctionFamily> PredefinedNames = {
       // numeric conversion:
-      "atof",
-      "atoi",
-      "atol",
-      "atoll",
-      "strtol",
-      "strtoll",
-      "strtoul",
-      "strtoull",
-      "strtof",
-      "strtod",
-      "strtold",
-      "strtoimax",
-      "strtoumax",
+      {"atof", UnsafeLibcFunctionFamily::NumericConversion},
+      {"atoi", UnsafeLibcFunctionFamily::NumericConversion},
+      {"atol", UnsafeLibcFunctionFamily::NumericConversion},
+      {"atoll", UnsafeLibcFunctionFamily::NumericConversion},
+      {"strtol", UnsafeLibcFunctionFamily::NumericConversion},
+      {"strtoll", UnsafeLibcFunctionFamily::NumericConversion},
+      {"strtoul", UnsafeLibcFunctionFamily::NumericConversion},
+      {"strtoull", UnsafeLibcFunctionFamily::NumericConversion},
+      {"strtof", UnsafeLibcFunctionFamily::NumericConversion},
+      {"strtod", UnsafeLibcFunctionFamily::NumericConversion},
+      {"strtold", UnsafeLibcFunctionFamily::NumericConversion},
+      {"strtoimax", UnsafeLibcFunctionFamily::NumericConversion},
+      {"strtoumax", UnsafeLibcFunctionFamily::NumericConversion},
       // "strfromf",  "strfromd", "strfroml", // C23?
       // string manipulation:
-      "strcpy",
-      "strncpy",
-      "strlcpy",
-      "strcat",
-      "strncat",
-      "strlcat",
-      "strxfrm",
-      "strdup",
-      "strndup",
+      {"strcpy", UnsafeLibcFunctionFamily::StringManipulation},
+      {"strncpy", UnsafeLibcFunctionFamily::StringManipulation},
+      {"strlcpy", UnsafeLibcFunctionFamily::StringManipulation},
+      {"strcat", UnsafeLibcFunctionFamily::StringManipulation},
+      {"strncat", UnsafeLibcFunctionFamily::StringManipulation},
+      {"strlcat", UnsafeLibcFunctionFamily::StringManipulation},
+      {"strxfrm", UnsafeLibcFunctionFamily::StringManipulation},
+      {"strdup", UnsafeLibcFunctionFamily::StringManipulation},
+      {"strndup", UnsafeLibcFunctionFamily::StringManipulation},
       // string examination:
-      "strlen",
-      "strnlen",
-      "strcmp",
-      "strncmp",
-      "stricmp",
-      "strcasecmp",
-      "strcoll",
-      "strchr",
-      "strrchr",
-      "strspn",
-      "strcspn",
-      "strpbrk",
-      "strstr",
-      "strtok",
+      {"strlen", UnsafeLibcFunctionFamily::StringExamination},
+      {"strnlen", UnsafeLibcFunctionFamily::StringExamination},
+      {"strcmp", UnsafeLibcFunctionFamily::StringExamination},
+      {"strncmp", UnsafeLibcFunctionFamily::StringExamination},
+      {"stricmp", UnsafeLibcFunctionFamily::StringExamination},
+      {"strcasecmp", UnsafeLibcFunctionFamily::StringExamination},
+      {"strcoll", UnsafeLibcFunctionFamily::StringExamination},
+      {"strchr", UnsafeLibcFunctionFamily::StringExamination},
+      {"strrchr", UnsafeLibcFunctionFamily::StringExamination},
+      {"strspn", UnsafeLibcFunctionFamily::StringExamination},
+      {"strcspn", UnsafeLibcFunctionFamily::StringExamination},
+      {"strpbrk", UnsafeLibcFunctionFamily::StringExamination},
+      {"strstr", UnsafeLibcFunctionFamily::StringExamination},
+      {"strtok", UnsafeLibcFunctionFamily::StringExamination},
       // "mem-" functions
-      "memchr",
-      "wmemchr",
-      "memcmp",
-      "wmemcmp",
-      "memcpy",
-      "memccpy",
-      "mempcpy",
-      "wmemcpy",
-      "memmove",
-      "wmemmove",
-      "wmemset",
+      {"memchr", UnsafeLibcFunctionFamily::Memory},
+      {"wmemchr", UnsafeLibcFunctionFamily::Memory},
+      {"memcmp", UnsafeLibcFunctionFamily::Memory},
+      {"wmemcmp", UnsafeLibcFunctionFamily::Memory},
+      {"memcpy", UnsafeLibcFunctionFamily::Memory},
+      {"memccpy", UnsafeLibcFunctionFamily::Memory},
+      {"mempcpy", UnsafeLibcFunctionFamily::Memory},
+      {"wmemcpy", UnsafeLibcFunctionFamily::Memory},
+      {"memmove", UnsafeLibcFunctionFamily::Memory},
+      {"wmemmove", UnsafeLibcFunctionFamily::Memory},
+      {"wmemset", UnsafeLibcFunctionFamily::Memory},
+      {"bcopy", UnsafeLibcFunctionFamily::Memory},
+      {"bzero", UnsafeLibcFunctionFamily::Memory},
       // IO:
-      "fread",
-      "fwrite",
-      "fgets",
-      "fgetws",
-      "gets",
-      "fputs",
-      "fputws",
-      "puts",
+      {"fread", UnsafeLibcFunctionFamily::IO},
+      {"fwrite", UnsafeLibcFunctionFamily::IO},
+      {"fgets", UnsafeLibcFunctionFamily::IO},
+      {"fgetws", UnsafeLibcFunctionFamily::IO},
+      {"gets", UnsafeLibcFunctionFamily::IO},
+      {"fputs", UnsafeLibcFunctionFamily::IO},
+      {"fputws", UnsafeLibcFunctionFamily::IO},
+      {"puts", UnsafeLibcFunctionFamily::IO},
       // others
-      "strerror_s",
-      "strerror_r",
-      "bcopy",
-      "bzero",
-      "bsearch",
-      "qsort",
+      {"strerror_s", UnsafeLibcFunctionFamily::Other},
+      {"strerror_r", UnsafeLibcFunctionFamily::Other},
+      {"bsearch", UnsafeLibcFunctionFamily::Other},
+      {"qsort", UnsafeLibcFunctionFamily::Other},
   };
 
   auto *II = Node.getIdentifier();
 
   if (!II)
-    return false;
+    return std::nullopt;
 
   StringRef Name = matchName(II->getName(), Node.getBuiltinID());
 
   // Match predefined names:
-  if (PredefinedNames.count(Name))
-    return true;
+  if (auto It = PredefinedNames.find(Name); It != PredefinedNames.end())
+    return It->second;
 
   std::string NameWCS = Name.str();
   size_t WcsPos = NameWCS.find("wcs");
@@ -1237,11 +1250,26 @@ static bool isPredefinedUnsafeLibcFunc(const 
FunctionDecl &Node) {
     NameWCS[WcsPos++] = 'r';
     WcsPos = NameWCS.find("wcs", WcsPos);
   }
-  if (PredefinedNames.count(NameWCS))
-    return true;
+  if (auto It = PredefinedNames.find(NameWCS); It != PredefinedNames.end())
+    return It->second;
   // All `scanf` functions are unsafe (including `sscanf`, `vsscanf`, etc.. 
They
   // all should end with "scanf"):
-  return Name.ends_with("scanf");
+  if (Name.ends_with("scanf"))
+    return UnsafeLibcFunctionFamily::Scanf;
+  return std::nullopt;
+}
+
+static bool isPredefinedUnsafeLibcFunc(const FunctionDecl &Node) {
+  return getPredefinedUnsafeLibcFuncFamily(Node).has_value();
+}
+
+// Returns the family of a callee that isPredefinedUnsafeLibcFunc or
+// isUnsafeMemset matched. Only memset is not in PredefinedNames.
+static UnsafeLibcFunctionFamily
+getUnsafeLibcFunctionFamily(const FunctionDecl &Node) {
+  if (auto Family = getPredefinedUnsafeLibcFuncFamily(Node))
+    return *Family;
+  return UnsafeLibcFunctionFamily::Memory;
 }
 
 // Returns true if this is an unsafe call to `memset`.
@@ -1433,6 +1461,23 @@ static bool hasUnsafeSnprintfBuffer(const CallExpr 
&Node, ASTContext &Ctx) {
 
   return !isPtrBufferSafe(Buf, Size, Ctx);
 }
+
+// A libc function must either be in the std:: namespace or a global function
+// that is not in any namespace.
+static bool isInLibcScope(const FunctionDecl &FD) {
+  const bool IsGlobalAndNotInAnyNamespace =
+      FD.isGlobal() && !FD.getEnclosingNamespaceContext()->isNamespace();
+
+  return FD.isInStdNamespace() || IsGlobalAndNotInAnyNamespace;
+}
+
+// Matches a function that UnsafeLibcFunctionCallGadget treats as a libc
+// function: in the libc scope, with a libc name.
+static bool isLibcFunction(const FunctionDecl &FD) {
+  return isInLibcScope(FD) &&
+         (isPredefinedUnsafeLibcFunc(FD) || isUnsafeVaListPrintfFunc(FD) ||
+          isUnsafeSprintfFunc(FD) || isNormalPrintfFunc(FD));
+}
 } // namespace libc_func_matchers
 
 namespace {
@@ -2476,6 +2521,7 @@ class UnsafeLibcFunctionCallGadget : public WarningGadget 
{
                  // considered unsafe as it is not compile-time check
     FORMAT_ATTR = 8, // flag: the callee has the format attribute
   } WarnedFunKind = OTHERS;
+  UnsafeLibcFunctionFamily Family = UnsafeLibcFunctionFamily::Other;
 
   UnsafeLibcFunctionCallGadget(const MatchResult &Result)
       : WarningGadget(Kind::UnsafeLibcFunctionCall),
@@ -2490,6 +2536,12 @@ class UnsafeLibcFunctionCallGadget : public 
WarningGadget {
       UnsafeArg = Call->getArg(0);
     } else if (Result.getNodeAs<Decl>(UnsafeVaListTag))
       WarnedFunKind = VA_LIST;
+    // Only the predefined-name and memset matches leave `WarnedFunKind` at
+    // `OTHERS`. The printf matches always set a kind.
+    Family = WarnedFunKind != OTHERS
+                 ? UnsafeLibcFunctionFamily::Printf
+                 : libc_func_matchers::getUnsafeLibcFunctionFamily(
+                       *Call->getDirectCallee());
   }
 
   static bool matches(const Stmt *S, ASTContext &Ctx,
@@ -2501,15 +2553,11 @@ class UnsafeLibcFunctionCallGadget : public 
WarningGadget {
     const auto *FD = CE->getDirectCallee();
     if (!FD)
       return false;
-    if (ignoreUnsafeLibcCall(Ctx, *S, Handler))
+    if (!libc_func_matchers::isInLibcScope(*FD))
       return false;
-
-    const bool IsGlobalAndNotInAnyNamespace =
-        FD->isGlobal() && !FD->getEnclosingNamespaceContext()->isNamespace();
-
-    // A libc function must either be in the std:: namespace or a global
-    // function that is not in any namespace:
-    if (!FD->isInStdNamespace() && !IsGlobalAndNotInAnyNamespace)
+    // The check looks up every libc-call warning, so it runs after the cheaper
+    // scope test.
+    if (ignoreUnsafeLibcCall(Ctx, *S, Handler))
       return false;
     // If the call has a sole null-terminated argument, e.g., strlen,
     //  printf, atoi, we consider it safe:
@@ -2562,7 +2610,7 @@ class UnsafeLibcFunctionCallGadget : public WarningGadget 
{
   void handleUnsafeOperation(UnsafeBufferUsageHandler &Handler,
                              bool IsRelatedToDecl,
                              ASTContext &Ctx) const override {
-    Handler.handleUnsafeLibcCall(Call, WarnedFunKind, Ctx, UnsafeArg);
+    Handler.handleUnsafeLibcCall(Call, WarnedFunKind, Family, Ctx, UnsafeArg);
   }
 
   DeclUseList getClaimedVarUseSites() const override { return {}; }
@@ -2592,7 +2640,7 @@ class UnsafeFormatAttributedFunctionCallGadget : public 
WarningGadget {
     const FunctionDecl *FD = CE->getDirectCallee();
     if (!FD)
       return false;
-    if (ignoreUnsafeLibcCall(Ctx, *S, Handler))
+    if (ignoreUnsafeFormatAttrCall(Ctx, *S, Handler))
       return false;
 
     const FormatAttr *Attr = nullptr;
@@ -2613,6 +2661,10 @@ class UnsafeFormatAttributedFunctionCallGadget : public 
WarningGadget {
 
     if (!AnyAttr)
       return false;
+    // Calls to libc functions belong to -Wunsafe-buffer-usage-in-libc-call.
+    if (ignoreUnsafeLibcCall(Ctx, *S, Handler) &&
+        libc_func_matchers::isLibcFunction(*FD))
+      return false;
 
     //...
[truncated]

``````````

</details>


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

Reply via email to