https://github.com/ziqingluo-90 updated 
https://github.com/llvm/llvm-project/pull/151270

>From 50ea6041f13cdc4c9d4ae475d11b970f1e026fac Mon Sep 17 00:00:00 2001
From: Ziqing Luo <ziq...@udel.edu>
Date: Wed, 30 Jul 2025 11:23:32 +0800
Subject: [PATCH 1/2] [-Wunsafe-buffer-usage] Do not warn about class methods
 with libc function names

This commit fixes the false positive that C++ class methods with libc
function names would be false warned about. For example,

```
struct T {void strcpy() const;};
void test(const T& t) {  str.strcpy(); // no warn }
```

rdar://156264388
---
 clang/lib/Analysis/UnsafeBufferUsage.cpp       |  2 +-
 ...warn-unsafe-buffer-usage-libc-functions.cpp | 18 ++++++++++++++++++
 2 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index ac47b12cc8d72..6cd71c7674a92 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -1925,7 +1925,7 @@ class UnsafeLibcFunctionCallGadget : public WarningGadget 
{
     if (!CE || !CE->getDirectCallee())
       return false;
     const auto *FD = dyn_cast<FunctionDecl>(CE->getDirectCallee());
-    if (!FD)
+    if (!FD || isa<CXXMethodDecl>(FD))
       return false;
     auto isSingleStringLiteralArg = false;
     if (CE->getNumArgs() == 1) {
diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp 
b/clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp
index d6c32ca7baa5d..e6902c5a95dc0 100644
--- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp
@@ -155,3 +155,21 @@ void ff(char * p, char * q, std::span<char> s, 
std::span<char> s2) {
   wcscpy_s();
 #pragma clang diagnostic pop
 }
+
+
+namespace CXXMethodNoWarn {
+  struct StrBuff
+  {
+    void strcpy() const;
+    void strcpy(char* dst) const;
+    void Strcpy(char* dst) const;
+  };
+
+  void test(const StrBuff& str)
+  {
+    char buff[64];
+    str.strcpy();
+    str.strcpy(buff);
+    str.Strcpy(buff);
+  }
+} // namespace CXXMethodNoWarn

>From b1b87fbeb7c90214bbd3ba827e6d8c858e39a12e Mon Sep 17 00:00:00 2001
From: Ziqing Luo <ziq...@udel.edu>
Date: Fri, 1 Aug 2025 15:56:41 +0800
Subject: [PATCH 2/2] address comments

---
 clang/lib/Analysis/UnsafeBufferUsage.cpp      | 10 ++-
 ...arn-unsafe-buffer-usage-libc-functions.cpp | 79 ++++++++++++++-----
 2 files changed, 68 insertions(+), 21 deletions(-)

diff --git a/clang/lib/Analysis/UnsafeBufferUsage.cpp 
b/clang/lib/Analysis/UnsafeBufferUsage.cpp
index 6cd71c7674a92..0ef4d8e8ec86e 100644
--- a/clang/lib/Analysis/UnsafeBufferUsage.cpp
+++ b/clang/lib/Analysis/UnsafeBufferUsage.cpp
@@ -1925,7 +1925,15 @@ class UnsafeLibcFunctionCallGadget : public 
WarningGadget {
     if (!CE || !CE->getDirectCallee())
       return false;
     const auto *FD = dyn_cast<FunctionDecl>(CE->getDirectCallee());
-    if (!FD || isa<CXXMethodDecl>(FD))
+    if (!FD)
+      return false;
+
+    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)
       return false;
     auto isSingleStringLiteralArg = false;
     if (CE->getNumArgs() == 1) {
diff --git a/clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp 
b/clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp
index e6902c5a95dc0..5b0d494a6575b 100644
--- a/clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp
+++ b/clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp
@@ -4,8 +4,16 @@
 // RUN:            -verify %s -x objective-c++
 // RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage-in-libc-call \
 // RUN:            -verify %s
+// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage-in-libc-call \
+// RUN:            -verify %s -DTEST_STD_NS
 
 typedef struct {} FILE;
+typedef unsigned int size_t;
+
+#ifdef TEST_STD_NS
+namespace std {
+#endif
+
 void memcpy();
 void __asan_memcpy();
 void strcpy();
@@ -25,6 +33,11 @@ int sscanf(const char * buffer, const char * format, ... );
 int wprintf(const wchar_t* format, ... );
 int __asan_printf();
 
+#ifdef TEST_STD_NS
+} //namespace std
+using namespace std;
+#endif
+
 namespace std {
   template< class InputIt, class OutputIt >
   OutputIt copy( InputIt first, InputIt last,
@@ -51,10 +64,6 @@ namespace std {
 
   typedef basic_string<char> string;
   typedef basic_string<wchar_t> wstring;
-
-  // C function under std:
-  void memcpy();
-  void strcpy();
 }
 
 void f(char * p, char * q, std::span<char> s, std::span<char> s2) {
@@ -64,14 +73,16 @@ void f(char * p, char * q, std::span<char> s, 
std::span<char> s2) {
   aligned_char_ptr_t cp;
 
   memcpy();                   // expected-warning{{function 'memcpy' is 
unsafe}}
-  std::memcpy();              // expected-warning{{function 'memcpy' is 
unsafe}}
   __builtin_memcpy(p, q, 64); // expected-warning{{function '__builtin_memcpy' 
is unsafe}}
   __builtin___memcpy_chk(p, q, 8, 64);  // expected-warning{{function 
'__builtin___memcpy_chk' is unsafe}}
   __asan_memcpy();                      // expected-warning{{function 
'__asan_memcpy' is unsafe}}
   strcpy();                   // expected-warning{{function 'strcpy' is 
unsafe}}
-  std::strcpy();              // expected-warning{{function 'strcpy' is 
unsafe}}
   strcpy_s();                 // expected-warning{{function 'strcpy_s' is 
unsafe}}
   wcscpy_s();                 // expected-warning{{function 'wcscpy_s' is 
unsafe}}
+#ifdef TEST_STD_NS
+  std::strcpy();              // expected-warning{{function 'strcpy' is 
unsafe}}
+  std::memcpy();              // expected-warning{{function 'memcpy' is 
unsafe}}
+#endif
 
   /* Test printfs */
   fprintf((FILE*)p, "%s%d", p, *p);  // expected-warning{{function 'fprintf' 
is unsafe}} expected-note{{string argument is not guaranteed to be 
null-terminated}}
@@ -145,31 +156,59 @@ void ff(char * p, char * q, std::span<char> s, 
std::span<char> s2) {
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
   memcpy();
-  std::memcpy();
   __builtin_memcpy(p, q, 64);
   __builtin___memcpy_chk(p, q, 8, 64);
   __asan_memcpy();
   strcpy();
+#ifdef TEST_STD_NS
   std::strcpy();
+  std::memcpy();
+#endif
   strcpy_s();
   wcscpy_s();
 #pragma clang diagnostic pop
 }
 
 
-namespace CXXMethodNoWarn {
-  struct StrBuff
+
+// functions not in global scope or std:: namespace are not libc
+// functions regardless of their names:
+struct StrBuff
+{
+  void strcpy();
+  void strcpy(char* dst);
+  void memcpy(void *dst, const void *src, size_t size);
+};
+
+namespace NS {
+  void strcpy();
+  void strcpy(char* dst);
+  void memcpy(void *dst, const void *src, size_t size);
+}
+
+namespace std {
+  // class methods even in std namespace cannot be libc functions:
+  struct LibC
   {
-    void strcpy() const;
-    void strcpy(char* dst) const;
-    void Strcpy(char* dst) const;
+    void strcpy();
+    void strcpy(char* dst);
+    void memcpy(void *dst, const void *src, size_t size);
   };
+}
 
-  void test(const StrBuff& str)
-  {
-    char buff[64];
-    str.strcpy();
-    str.strcpy(buff);
-    str.Strcpy(buff);
-  }
-} // namespace CXXMethodNoWarn
+void test(StrBuff& str)
+{
+  char buff[64];
+  str.strcpy();
+  str.strcpy(buff);
+  str.memcpy(buff, buff, 64);
+  NS::strcpy();
+  NS::strcpy(buff);
+  NS::memcpy(buff, buff, 64);
+
+  std::LibC LibC;
+
+  LibC.strcpy();
+  LibC.strcpy(buff);
+  LibC.memcpy(buff, buff, 64);
+}

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

Reply via email to