251 lines · cpp
1// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage \2// RUN: -verify %s3// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage \4// RUN: -verify %s -x objective-c++5// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage-in-libc-call \6// RUN: -verify %s7// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage-in-libc-call \8// RUN: -verify %s -DTEST_STD_NS9 10typedef struct {} FILE;11typedef unsigned int size_t;12 13#ifdef TEST_STD_NS14namespace std {15#endif16 17void memcpy();18void __asan_memcpy();19void strcpy();20void strcpy_s();21void wcscpy_s();22unsigned strlen( const char* str );23int fprintf( FILE* stream, const char* format, ... );24int printf( const char* format, ... );25int sprintf( char* buffer, const char* format, ... );26int swprintf( char* buffer, const char* format, ... );27int snprintf( char* buffer, unsigned buf_size, const char* format, ... );28int snwprintf( char* buffer, unsigned buf_size, const char* format, ... );29int snwprintf_s( char* buffer, unsigned buf_size, const char* format, ... );30int vsnprintf( char* buffer, unsigned buf_size, const char* format, ... );31int sscanf_s(const char * buffer, const char * format, ...);32int sscanf(const char * buffer, const char * format, ... );33int wprintf(const wchar_t* format, ... );34int __asan_printf();35 36#ifdef TEST_STD_NS37} //namespace std38using namespace std;39#endif40 41namespace std {42 template< class InputIt, class OutputIt >43 OutputIt copy( InputIt first, InputIt last,44 OutputIt d_first );45 46 struct iterator{};47 template<typename T>48 struct span {49 T * ptr;50 T * data();51 unsigned size_bytes();52 unsigned size();53 iterator begin() const noexcept;54 iterator end() const noexcept;55 };56 57 template<typename T>58 struct basic_string {59 T* p;60 T *c_str();61 T *data();62 unsigned size_bytes();63 unsigned size();64 };65 66 typedef basic_string<char> string;67 typedef basic_string<wchar_t> wstring;68 69 template<typename T>70 struct basic_string_view {71 T *c_str() const noexcept;72 T *data() const noexcept;73 unsigned size();74 const T* begin() const noexcept;75 const T* end() const noexcept;76 };77 78 typedef basic_string_view<char> string_view;79 typedef basic_string_view<wchar_t> wstring_view;80}81 82void f(char * p, char * q, std::span<char> s, std::span<char> s2) {83 typedef FILE * _Nullable aligned_file_ptr_t __attribute__((align_value(64)));84 typedef char * _Nullable aligned_char_ptr_t __attribute__((align_value(64)));85 aligned_file_ptr_t fp;86 aligned_char_ptr_t cp;87 88 memcpy(); // expected-warning{{function 'memcpy' is unsafe}}89 __builtin_memcpy(p, q, 64); // expected-warning{{function '__builtin_memcpy' is unsafe}}90 __builtin___memcpy_chk(p, q, 8, 64); // expected-warning{{function '__builtin___memcpy_chk' is unsafe}}91 __asan_memcpy(); // expected-warning{{function '__asan_memcpy' is unsafe}}92 strcpy(); // expected-warning{{function 'strcpy' is unsafe}}93 strcpy_s(); // expected-warning{{function 'strcpy_s' is unsafe}}94 wcscpy_s(); // expected-warning{{function 'wcscpy_s' is unsafe}}95#ifdef TEST_STD_NS96 std::strcpy(); // expected-warning{{function 'strcpy' is unsafe}}97 std::memcpy(); // expected-warning{{function 'memcpy' is unsafe}}98#endif99 100 /* Test printfs */101 fprintf((FILE*)p, "%s%d", p, *p); // expected-warning{{function 'fprintf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}102 printf("%s%d", // expected-warning{{function 'printf' is unsafe}}103 p, // expected-note{{string argument is not guaranteed to be null-terminated}} note attached to the unsafe argument104 *p);105 printf(cp, p, *p); // expected-warning{{function 'printf' is unsafe}} // expected-note{{string argument is not guaranteed to be null-terminated}}106 sprintf(q, "%s%d", "hello", *p); // expected-warning{{function 'sprintf' is unsafe}} expected-note{{change to 'snprintf' for explicit bounds checking}}107 swprintf(q, "%s%d", "hello", *p); // expected-warning{{function 'swprintf' is unsafe}} expected-note{{change to 'snprintf' for explicit bounds checking}}108 snprintf(q, 10, "%s%d", "hello", *p); // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}}109 snprintf(cp, 10, "%s%d", "hello", *p); // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}}110 snprintf(s.data(), s2.size(), "%s%d", "hello", *p); // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}}111 snwprintf(s.data(), s2.size(), "%s%d", "hello", *p); // expected-warning{{function 'snwprintf' is unsafe}} expected-note{{buffer pointer and size may not match}}112 snwprintf_s( // expected-warning{{function 'snwprintf_s' is unsafe}}113 s.data(), // expected-note{{buffer pointer and size may not match}} // note attached to the buffer114 s2.size(),115 "%s%d", "hello", *p);116 vsnprintf(s.data(), s.size_bytes(), "%s%d", "hello", *p); // expected-warning{{function 'vsnprintf' is unsafe}} expected-note{{'va_list' is unsafe}}117 sscanf(p, "%s%d", "hello", *p); // expected-warning{{function 'sscanf' is unsafe}}118 sscanf_s(p, "%s%d", "hello", *p); // expected-warning{{function 'sscanf_s' is unsafe}}119 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}}120 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}}121 wprintf(L"hello %s", p); // expected-warning{{function 'wprintf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}122 123 124 char a[10], b[11];125 int c[10];126 std::wstring WS;127 128 snprintf(a, sizeof(b), "%s", __PRETTY_FUNCTION__); // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}}129 snprintf((char*)c, sizeof(c), "%s", __PRETTY_FUNCTION__); // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}}130 fprintf((FILE*)p, "%P%d%p%i hello world %32s", *p, *p, p, *p, "hello"); // no warn131 fprintf(fp, "%P%d%p%i hello world %32s", *p, *p, p, *p, "hello"); // no warn132 printf("%s%d", "hello", *p); // no warn133 snprintf(s.data(), s.size_bytes(), "%s%d", "hello", *p); // no warn134 snprintf(s.data(), s.size_bytes(), "%s%d", __PRETTY_FUNCTION__, *p); // no warn135 snwprintf(s.data(), s.size_bytes(), "%s%d", __PRETTY_FUNCTION__, *p); // no warn136 snwprintf_s(s.data(), s.size_bytes(), "%s%d", __PRETTY_FUNCTION__, *p); // no warn137 wprintf(L"hello %ls", L"world"); // no warn138 wprintf(L"hello %ls", WS.c_str()); // no warn139 strlen("hello");// no warn140 __asan_printf();// a printf but no argument, so no warn141}142 143void safe_examples(std::string s1, int *p) {144 snprintf(s1.data(), s1.size_bytes(), "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", p, s1.c_str()); // no warn145 snprintf(s1.data(), s1.size_bytes(), s1.c_str(), __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn146 printf("%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", p, s1.c_str()); // no warn147 printf(s1.c_str(), __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn148 fprintf((FILE*)0, "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", p, s1.c_str()); // no warn149 fprintf((FILE*)0, s1.c_str(), __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn150 151 char a[10];152 char c = 'c';153 154 snprintf(a, sizeof a, "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn155 snprintf(a, sizeof(decltype(a)), "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn156 snprintf(a, 10, "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn157 snprintf(&c, 1, "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn158 snprintf(nullptr, 0, "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", s1.c_str()); // no warn159}160 161void test_sarg_precision(std::string Str, std::string_view Sv, std::wstring_view WSv,162 std::span<char> SpC, std::span<int> SpI) {163 printf("%.*s");164 printf("%.*s", (int)Str.size(), Str.data());165 printf("%.*s", (int)Str.size_bytes(), Str.data());166 printf("%.*s", (int)Sv.size(), Sv.data());167 printf("%.*s", (int)SpC.size(), SpC.data());168 printf("%.*s", SpC.size(), SpC.data());169 printf("%.*ls", WSv.size(), WSv.data());170 printf("%.*s", SpC.data()); // no warn because `SpC.data()` is passed to the precision while the actually string pointer is not given171 172 printf("%.*s", SpI.size(), SpI.data()); // expected-warning {{function 'printf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}173 printf("%.*s", SpI.size(), SpC.data()); // expected-warning {{function 'printf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}174 printf("%.*s", WSv.size(), WSv.data()); // expected-warning {{function 'printf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}175 176 char a[10];177 int b[10];178 179 printf("%.10s", a);180 printf("%.11s", a); // expected-warning {{function 'printf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}181 printf("%.10s", b); // expected-warning {{function 'printf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}182}183 184 185void g(char *begin, char *end, char *p, std::span<char> s) {186 std::copy(begin, end, p); // no warn187 std::copy(s.begin(), s.end(), s.begin()); // no warn188}189 190// warning gets turned off191void ff(char * p, char * q, std::span<char> s, std::span<char> s2) {192#pragma clang diagnostic push193#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"194 memcpy();195 __builtin_memcpy(p, q, 64);196 __builtin___memcpy_chk(p, q, 8, 64);197 __asan_memcpy();198 strcpy();199#ifdef TEST_STD_NS200 std::strcpy();201 std::memcpy();202#endif203 strcpy_s();204 wcscpy_s();205#pragma clang diagnostic pop206}207 208 209 210// functions not in global scope or std:: namespace are not libc211// functions regardless of their names:212struct StrBuff213{214 void strcpy();215 void strcpy(char* dst);216 void memcpy(void *dst, const void *src, size_t size);217};218 219namespace NS {220 void strcpy();221 void strcpy(char* dst);222 void memcpy(void *dst, const void *src, size_t size);223}224 225namespace std {226 // class methods even in std namespace cannot be libc functions:227 struct LibC228 {229 void strcpy();230 void strcpy(char* dst);231 void memcpy(void *dst, const void *src, size_t size);232 };233}234 235void 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}251