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