// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage -Wno-gcc-compat\ // RUN: -verify %s // RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage -Wno-gcc-compat\ // RUN: -verify %s -x objective-c++ // RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage-in-libc-call \ // RUN: -Wunsafe-buffer-usage-in-format-attr-call -Wno-gcc-compat \ // RUN: -verify %s // RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage-in-libc-call \ // RUN: -Wunsafe-buffer-usage-in-format-attr-call -Wno-gcc-compat \ // 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 *memset(void *s, int c, size_t n); void strcpy(); void strcpy_s(); void wcscpy_s(); unsigned strlen( const char* str ); int fprintf( FILE* stream, const char* format, ... ); int printf( const char* format, ... ); int sprintf( char* buffer, const char* format, ... ); int swprintf( char* buffer, const char* format, ... ); int snprintf( char* buffer, unsigned buf_size, const char* format, ... ); int snwprintf( char* buffer, unsigned buf_size, const char* format, ... ); int snwprintf_s( char* buffer, unsigned buf_size, const char* format, ... ); int vsnprintf( char* buffer, unsigned buf_size, const char* format, ... ); int sscanf_s(const char * buffer, const char * format, ...); 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, OutputIt d_first ); struct iterator{}; template struct span { T * ptr; T * data(); unsigned size_bytes(); unsigned size(); iterator begin() const noexcept; iterator end() const noexcept; }; template struct basic_string { T* p; T *c_str(); T *data(); unsigned size_bytes(); unsigned size(); }; typedef basic_string string; typedef basic_string wstring; template struct basic_string_view { T *c_str() const noexcept; T *data() const noexcept; unsigned size(); const T* begin() const noexcept; const T* end() const noexcept; }; typedef basic_string_view string_view; typedef basic_string_view wstring_view; template T *addressof(T& arg); } void f(char * p, char * q, std::span s, std::span s2) { typedef FILE * _Nullable aligned_file_ptr_t __attribute__((align_value(64))); typedef char * _Nullable aligned_char_ptr_t __attribute__((align_value(64))); aligned_file_ptr_t fp; aligned_char_ptr_t cp; 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}} 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}} printf("%s%d", // expected-warning{{function 'printf' is unsafe}} p, // expected-note{{string argument is not guaranteed to be null-terminated}} note attached to the unsafe argument *p); printf(cp, p, *p); // expected-warning{{function 'printf' is unsafe}} // expected-note{{string argument is not guaranteed to be null-terminated}} sprintf(q, "%s%d", "hello", *p); // expected-warning{{function 'sprintf' is unsafe}} expected-note{{change to 'snprintf' for explicit bounds checking}} swprintf(q, "%s%d", "hello", *p); // expected-warning{{function 'swprintf' is unsafe}} expected-note{{change to 'snprintf' for explicit bounds checking}} snprintf(q, 10, "%s%d", "hello", *p); // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}} snprintf(cp, 10, "%s%d", "hello", *p); // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}} snprintf(s.data(), s2.size(), "%s%d", "hello", *p); // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}} printf(nullptr); // expected-warning{{function 'printf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}} printf("%s", nullptr); // expected-warning{{function 'printf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}} snwprintf(s.data(), s2.size(), "%s%d", "hello", *p); // expected-warning{{function 'snwprintf' is unsafe}} expected-note{{buffer pointer and size may not match}} snwprintf_s( // expected-warning{{function 'snwprintf_s' is unsafe}} s.data(), // expected-note{{buffer pointer and size may not match}} // note attached to the buffer s2.size(), "%s%d", "hello", *p); vsnprintf(s.data(), s.size_bytes(), "%s%d", "hello", *p); // expected-warning{{function 'vsnprintf' is unsafe}} expected-note{{'va_list' is unsafe}} sscanf(p, "%s%d", "hello", *p); // expected-warning{{function 'sscanf' is unsafe}} sscanf_s(p, "%s%d", "hello", *p); // expected-warning{{function 'sscanf_s' is unsafe}} fprintf((FILE*)p, "%P%d%p%i hello world %32s", *p, *p, p, *p, p); // expected-warning{{function 'fprintf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}} fprintf(fp, "%P%d%p%i hello world %32s", *p, *p, p, *p, p); // expected-warning{{function 'fprintf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}} wprintf(L"hello %s", p); // expected-warning{{function 'wprintf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}} char a[10], b[11]; int c[10]; std::wstring WS; snprintf(a, sizeof(b), "%s", __PRETTY_FUNCTION__); // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}} snprintf((char*)c, sizeof(c), "%s", __PRETTY_FUNCTION__); // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}} fprintf((FILE*)p, "%P%d%p%i hello world %32s", *p, *p, p, *p, "hello"); // no warn fprintf(fp, "%P%d%p%i hello world %32s", *p, *p, p, *p, "hello"); // no warn printf("%s%d", "hello", *p); // no warn snprintf(s.data(), s.size_bytes(), "%s%d", "hello", *p); // no warn snprintf(s.data(), s.size_bytes(), "%s%d", __PRETTY_FUNCTION__, *p); // no warn snwprintf(s.data(), s.size_bytes(), "%s%d", __PRETTY_FUNCTION__, *p); // no warn snwprintf_s(s.data(), s.size_bytes(), "%s%d", __PRETTY_FUNCTION__, *p); // no warn snprintf(s.data(), s.size_bytes(), "%s%d"); // no warn snprintf(s.data(), s.size_bytes(), "%s%d"); // no warn snwprintf(s.data(), s.size_bytes(), "%s%d"); // no warn snwprintf_s(s.data(), s.size_bytes(), "%s%d"); // no warn wprintf(L"hello %ls", L"world"); // no warn wprintf(L"hello %ls", WS.c_str()); // no warn strlen("hello");// no warn __asan_printf();// a printf but no argument, so no warn } void safe_examples(std::string s1, int *p) { snprintf(s1.data(), s1.size_bytes(), "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", p, s1.c_str()); // no warn snprintf(s1.data(), s1.size_bytes(), s1.c_str(), __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn printf("%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", p, s1.c_str()); // no warn printf(s1.c_str(), __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn fprintf((FILE*)0, "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", p, s1.c_str()); // no warn fprintf((FILE*)0, s1.c_str(), __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn char a[10]; char c = 'c'; snprintf(a, sizeof a, "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn snprintf(a, sizeof(decltype(a)), "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn snprintf(a, 10, "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn snprintf(&c, 1, "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn snprintf(nullptr, 0, "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn strlen(s1.c_str()); } void test_sarg_precision(std::string Str, std::string_view Sv, std::wstring_view WSv, std::span SpC, std::span SpI) { printf("%.*s"); printf("%.*s", (int)Str.size(), Str.data()); printf("%.*s", (int)Str.size_bytes(), Str.data()); printf("%.*s", (int)Sv.size(), Sv.data()); printf("%.*s", (int)SpC.size(), SpC.data()); printf("%.*s", SpC.size(), SpC.data()); printf("%.*ls", WSv.size(), WSv.data()); printf("%.*s", SpC.data()); // no warn because `SpC.data()` is passed to the precision while the actually string pointer is not given printf("%.*s", SpI.size(), SpI.data()); // expected-warning {{function 'printf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}} printf("%.*s", SpI.size(), SpC.data()); // expected-warning {{function 'printf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}} printf("%.*s", WSv.size(), WSv.data()); // expected-warning {{function 'printf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}} char a[10]; int b[10]; printf("%.10s", a); printf("%.11s", a); // expected-warning {{function 'printf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}} printf("%.10s", b); // expected-warning {{function 'printf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}} } void g(char *begin, char *end, char *p, std::span s) { std::copy(begin, end, p); // no warn std::copy(s.begin(), s.end(), s.begin()); // no warn } // warning gets turned off void ff(char * p, char * q, std::span s, std::span s2) { #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call" 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 } // 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(); void strcpy(char* dst); void memcpy(void *dst, const void *src, size_t size); }; } 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); } void dontCrashForInvalidFormatString() { snprintf((char*)0, 0, "%"); snprintf((char*)0, 0, "\0"); } // Also warn about unsafe printf/scanf-like functions: void myprintf(const char *, ...) __attribute__((__format__ (__printf__, 1, 2))); void myprintf_2(const char *, int, const char *) __attribute__((__format__ (__printf__, 1, 3))); void myprintf_3(const char *, const char *, int, const char *) __attribute__((__format__ (__printf__, 2, 4))); void myscanf(const char *, ...) __attribute__((__format__ (__scanf__, 1, 2))); void myprintf_default(const char *, const char * Fmt = "hello %s", int X = 0, const char * Str = "world") __attribute__((__format__ (__printf__, 2, 4))); struct FormatAttrTestMember { void myprintf(const char *, ...) __attribute__((__format__ (__printf__, 2, 3))); void myprintf_2(const char *, int, const char *) __attribute__((__format__ (__printf__, 2, 4))); void myprintf_3(const char *, const char *, int, const char *) __attribute__((__format__ (__printf__, 3, 5))); void myscanf(const char *, ...) __attribute__((__format__ (__scanf__, 2, 3))); void operator()(const char * Fmt, ...) __attribute__((__format__ (__printf__, 2, 3))); void operator[](const char * Fmt) __attribute__((__format__ (__printf__, 2, 3))); static const char * StrField; void myprintf_default(const char *, const char * Fmt = "hello %s", int X = 0, const char * Str = StrField) __attribute__((__format__ (__printf__, 3, 5))); }; struct FormatAttrTestMember2 { void operator()(const char * Fmt, char *) __attribute__((__format__ (__printf__, 2, 3))); }; void test_format_attr(char * Str, std::string StdStr) { myprintf("hello", Str); myprintf("hello %s", StdStr.c_str()); myprintf("hello %s", Str); // expected-warning{{formatting function 'myprintf' is unsafe}} \ expected-note{{string argument is not guaranteed to be null-terminated}} extern int errno; extern char *strerror(int errnum); myprintf("errno: %s", strerror(errno)); myprintf_2("hello", 0, Str); myprintf_2("hello %s", 0, StdStr.c_str()); myprintf_2("hello %s", 0, Str); // expected-warning{{formatting function 'myprintf_2' is unsafe}} \ expected-note{{string argument is not guaranteed to be null-terminated}} myprintf_3("irrelevant", "hello", 0, Str); myprintf_3("irrelevant", "hello %s", 0, StdStr.c_str()); myprintf_3("irrelevant", "hello %s", 0, Str); // expected-warning{{formatting function 'myprintf_3' is unsafe}} \ expected-note{{string argument is not guaranteed to be null-terminated}} myscanf("hello %s"); myscanf("hello %s", Str); // expected-warning{{function 'myscanf' is unsafe}} myprintf_default("irrelevant"); int X; myscanf("hello %d", &X); // expected-warning{{function 'myscanf' is unsafe}} // Test member functions: FormatAttrTestMember Obj; Obj.myprintf("hello", Str); Obj.myprintf("hello %s", StdStr.c_str()); Obj.myprintf("hello %s", Str); // expected-warning{{formatting function 'myprintf' is unsafe}} \ expected-note{{string argument is not guaranteed to be null-terminated}} Obj.myprintf_2("hello", 0, Str); Obj.myprintf_2("hello %s", 0, StdStr.c_str()); Obj.myprintf_2("hello %s", 0, Str); // expected-warning{{formatting function 'myprintf_2' is unsafe}} \ expected-note{{string argument is not guaranteed to be null-terminated}} Obj.myprintf_3("irrelevant", "hello", 0, Str); Obj.myprintf_3("irrelevant", "hello %s", 0, StdStr.c_str()); Obj.myprintf_3("irrelevant", "hello %s", 0, Str); // expected-warning{{formatting function 'myprintf_3' is unsafe}} \ expected-note{{string argument is not guaranteed to be null-terminated}} Obj.myscanf("hello %s"); Obj.myscanf("hello %s", Str); // expected-warning{{formatting function 'myscanf' is unsafe}} Obj.myscanf("hello %d", &X); // expected-warning{{formatting function 'myscanf' is unsafe}} Obj.myprintf_default("irrelevant"); // expected-warning{{formatting function 'myprintf_default' is unsafe}} // expected-note@*{{string argument is not guaranteed to be null-terminated}} Obj("hello", Str); Obj("hello %s", StdStr.c_str()); Obj("hello %s", Str); // expected-warning{{formatting function 'operator()' is unsafe}} \ expected-note{{string argument is not guaranteed to be null-terminated}} Obj["hello"]; Obj["hello %s"]; FormatAttrTestMember2 Obj2; Obj2("hello", Str); Obj2("hello %s", StdStr.c_str()); Obj2("hello %s", Str); // expected-warning{{formatting function 'operator()' is unsafe}} \ expected-note{{string argument is not guaranteed to be null-terminated}} } // The second attribute argument, which points the starting index of // format string arguments, may not be a valid argument index: void myprintf_arg_idx_oob(const char *) __attribute__((__format__ (__printf__, 1, 2))); void test_format_attr_invalid_arg_idx(char * Str, std::string StdStr) { myprintf_arg_idx_oob("hello"); myprintf_arg_idx_oob(Str); // expected-warning{{formatting function 'myprintf_arg_idx_oob' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}} myprintf_arg_idx_oob(StdStr.c_str()); myprintf("hello"); myprintf(Str); // expected-warning{{formatting function 'myprintf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}} myprintf(StdStr.c_str()); } void memset_address_of_operator() { int i = 0; // memory-safe and considered safe by the check memset(&i, 0, sizeof(i)); memset(&i, 0, sizeof i); memset(&(i), 0, sizeof(i)); memset(&(i), 0, sizeof i); // memory-safe but considered unsafe by the check memset(&i, 0, 0); // expected-warning{{function 'memset' is unsafe}} memset(&i, 0, 1); // expected-warning{{function 'memset' is unsafe}} memset(&i, 0, sizeof(int)); // expected-warning{{function 'memset' is unsafe}} memset(&(++i), 0, sizeof(i)); // expected-warning{{function 'memset' is unsafe}} // unsafe memset(nullptr, 0, 10); // expected-warning{{function 'memset' is unsafe}} memset(&i, 0, 10); // expected-warning{{function 'memset' is unsafe}} } void memset_address_of_function() { int i = 0; // memory-safe and considered safe by the check memset(std::addressof(i), 0, sizeof(i)); memset(std::addressof(i), 0, sizeof i); memset(std::addressof((i)), 0, sizeof(i)); memset(std::addressof((i)), 0, sizeof i); // memory-safe but considered unsafe by the check memset(std::addressof(i), 0, 0); // expected-warning{{function 'memset' is unsafe}} memset(std::addressof(i), 0, 1); // expected-warning{{function 'memset' is unsafe}} memset(std::addressof(i), 0, sizeof(int)); // expected-warning{{function 'memset' is unsafe}} memset(std::addressof(++i), 0, sizeof(i)); // expected-warning{{function 'memset' is unsafe}} // unsafe memset(std::addressof(i), 0, 10); // expected-warning{{function 'memset' is unsafe}} } // Unknown `memset`s with more or less parameters. void *memset(void *s, size_t n); void *memset(void *s, int c, size_t n, size_t destlen); void unknown_memset_unsafe() { int i = 0; memset(&i, sizeof(i)); // expected-warning{{function 'memset' is unsafe}} memset(&i, 0, sizeof(i), sizeof(i)); // expected-warning{{function 'memset' is unsafe}} memset(std::addressof(i), sizeof(i)); // expected-warning{{function 'memset' is unsafe}} memset(std::addressof(i), 0, sizeof(i), sizeof(i)); // expected-warning{{function 'memset' is unsafe}} } void builtin_memset() { int i = 0; // memory-safe and considered safe by the check __builtin_memset(&i, 0, sizeof(i)); // may be memory-safe but considered unsafe by the check __builtin_memset(&i, 0 , 4); // expected-warning{{function '__builtin_memset' is unsafe}} __builtin___memset_chk(&i, 0 , 4, 4); // expected-warning{{function '__builtin___memset_chk' is unsafe}} __builtin___memset_chk(&i, 0 , sizeof(i), sizeof(i)); // expected-warning{{function '__builtin___memset_chk' is unsafe}} } namespace ms { void memset(void *s, int c, size_t n); void __builtin_memset(void *s, int c, size_t n); } // Custom-written `memset` functions are not included in the check. // Note: `using namespace ms;` results in compilation errors // ("call to 'memset' is ambiguous") which block other warnings, // so we don't include a test for it. void using_custom_memset_safe() { int i = 0; ms::memset(&i, 0, 10); ms::__builtin_memset(&i, 0, 10); using ms::memset; memset(&i, 0, 10); using ms::__builtin_memset; __builtin_memset(&i, 0, 10); } #ifdef TEST_STD_NS void qualified_std_memset() { int i = 0; // memory-safe and considered safe by the check std::memset(&i, 0, sizeof(i)); // unsafe std::memset(&i, 0 , 10); // expected-warning{{function 'memset' is unsafe}} } #endif