Skip to content

Commit 0abf497

Browse files
authored
[-Wunsafe-buffer-usage] Do not warn about class methods with libc function names (#151270)
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
1 parent 13daf3b commit 0abf497

File tree

2 files changed

+72
-7
lines changed

2 files changed

+72
-7
lines changed

clang/lib/Analysis/UnsafeBufferUsage.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1986,6 +1986,14 @@ class UnsafeLibcFunctionCallGadget : public WarningGadget {
19861986
const auto *FD = dyn_cast<FunctionDecl>(CE->getDirectCallee());
19871987
if (!FD)
19881988
return false;
1989+
1990+
bool IsGlobalAndNotInAnyNamespace =
1991+
FD->isGlobal() && !FD->getEnclosingNamespaceContext()->isNamespace();
1992+
1993+
// A libc function must either be in the std:: namespace or a global
1994+
// function that is not in any namespace:
1995+
if (!FD->isInStdNamespace() && !IsGlobalAndNotInAnyNamespace)
1996+
return false;
19891997
auto isSingleStringLiteralArg = false;
19901998
if (CE->getNumArgs() == 1) {
19911999
isSingleStringLiteralArg =

clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp

Lines changed: 64 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,16 @@
44
// RUN: -verify %s -x objective-c++
55
// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage-in-libc-call \
66
// RUN: -verify %s
7+
// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage-in-libc-call \
8+
// RUN: -verify %s -DTEST_STD_NS
79

810
typedef struct {} FILE;
11+
typedef unsigned int size_t;
12+
13+
#ifdef TEST_STD_NS
14+
namespace std {
15+
#endif
16+
917
void memcpy();
1018
void __asan_memcpy();
1119
void strcpy();
@@ -25,6 +33,11 @@ int sscanf(const char * buffer, const char * format, ... );
2533
int wprintf(const wchar_t* format, ... );
2634
int __asan_printf();
2735

36+
#ifdef TEST_STD_NS
37+
} //namespace std
38+
using namespace std;
39+
#endif
40+
2841
namespace std {
2942
template< class InputIt, class OutputIt >
3043
OutputIt copy( InputIt first, InputIt last,
@@ -64,10 +77,6 @@ namespace std {
6477

6578
typedef basic_string_view<char> string_view;
6679
typedef basic_string_view<wchar_t> wstring_view;
67-
68-
// C function under std:
69-
void memcpy();
70-
void strcpy();
7180
}
7281

7382
void f(char * p, char * q, std::span<char> s, std::span<char> s2) {
@@ -77,14 +86,16 @@ void f(char * p, char * q, std::span<char> s, std::span<char> s2) {
7786
aligned_char_ptr_t cp;
7887

7988
memcpy(); // expected-warning{{function 'memcpy' is unsafe}}
80-
std::memcpy(); // expected-warning{{function 'memcpy' is unsafe}}
8189
__builtin_memcpy(p, q, 64); // expected-warning{{function '__builtin_memcpy' is unsafe}}
8290
__builtin___memcpy_chk(p, q, 8, 64); // expected-warning{{function '__builtin___memcpy_chk' is unsafe}}
8391
__asan_memcpy(); // expected-warning{{function '__asan_memcpy' is unsafe}}
8492
strcpy(); // expected-warning{{function 'strcpy' is unsafe}}
85-
std::strcpy(); // expected-warning{{function 'strcpy' is unsafe}}
8693
strcpy_s(); // expected-warning{{function 'strcpy_s' is unsafe}}
8794
wcscpy_s(); // expected-warning{{function 'wcscpy_s' is unsafe}}
95+
#ifdef TEST_STD_NS
96+
std::strcpy(); // expected-warning{{function 'strcpy' is unsafe}}
97+
std::memcpy(); // expected-warning{{function 'memcpy' is unsafe}}
98+
#endif
8899

89100
/* Test printfs */
90101
fprintf((FILE*)p, "%s%d", p, *p); // expected-warning{{function 'fprintf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}
@@ -181,13 +192,59 @@ void ff(char * p, char * q, std::span<char> s, std::span<char> s2) {
181192
#pragma clang diagnostic push
182193
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
183194
memcpy();
184-
std::memcpy();
185195
__builtin_memcpy(p, q, 64);
186196
__builtin___memcpy_chk(p, q, 8, 64);
187197
__asan_memcpy();
188198
strcpy();
199+
#ifdef TEST_STD_NS
189200
std::strcpy();
201+
std::memcpy();
202+
#endif
190203
strcpy_s();
191204
wcscpy_s();
192205
#pragma clang diagnostic pop
193206
}
207+
208+
209+
210+
// functions not in global scope or std:: namespace are not libc
211+
// functions regardless of their names:
212+
struct StrBuff
213+
{
214+
void strcpy();
215+
void strcpy(char* dst);
216+
void memcpy(void *dst, const void *src, size_t size);
217+
};
218+
219+
namespace NS {
220+
void strcpy();
221+
void strcpy(char* dst);
222+
void memcpy(void *dst, const void *src, size_t size);
223+
}
224+
225+
namespace std {
226+
// class methods even in std namespace cannot be libc functions:
227+
struct LibC
228+
{
229+
void strcpy();
230+
void strcpy(char* dst);
231+
void memcpy(void *dst, const void *src, size_t size);
232+
};
233+
}
234+
235+
void test(StrBuff& str)
236+
{
237+
char buff[64];
238+
str.strcpy();
239+
str.strcpy(buff);
240+
str.memcpy(buff, buff, 64);
241+
NS::strcpy();
242+
NS::strcpy(buff);
243+
NS::memcpy(buff, buff, 64);
244+
245+
std::LibC LibC;
246+
247+
LibC.strcpy();
248+
LibC.strcpy(buff);
249+
LibC.memcpy(buff, buff, 64);
250+
}

0 commit comments

Comments
 (0)