xref: /llvm-project/clang/test/SemaCXX/warn-unsafe-buffer-usage-libc-functions.cpp (revision 090dc77a8d636415b772f7e5f95cd120370e41d1)
1 // RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage \
2 // RUN:            -verify %s
3 // 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 %s
7 
8 typedef struct {} FILE;
9 void memcpy();
10 void __asan_memcpy();
11 void strcpy();
12 void strcpy_s();
13 void wcscpy_s();
14 unsigned strlen( const char* str );
15 int fprintf( FILE* stream, const char* format, ... );
16 int printf( const char* format, ... );
17 int sprintf( char* buffer, const char* format, ... );
18 int swprintf( char* buffer, const char* format, ... );
19 int snprintf( char* buffer, unsigned buf_size, const char* format, ... );
20 int snwprintf( char* buffer, unsigned buf_size, const char* format, ... );
21 int snwprintf_s( char* buffer, unsigned buf_size, const char* format, ... );
22 int vsnprintf( char* buffer, unsigned buf_size, const char* format, ... );
23 int sscanf_s(const char * buffer, const char * format, ...);
24 int sscanf(const char * buffer, const char * format, ... );
25 int wprintf(const wchar_t* format, ... );
26 int __asan_printf();
27 
28 namespace std {
29   template< class InputIt, class OutputIt >
30   OutputIt copy( InputIt first, InputIt last,
31 		 OutputIt d_first );
32 
33   struct iterator{};
34   template<typename T>
35   struct span {
36     T * ptr;
37     T * data();
38     unsigned size_bytes();
39     unsigned size();
40     iterator begin() const noexcept;
41     iterator end() const noexcept;
42   };
43 
44   template<typename T>
45   struct basic_string {
46     T* p;
47     T *c_str();
48     T *data();
49     unsigned size_bytes();
50   };
51 
52   typedef basic_string<char> string;
53   typedef basic_string<wchar_t> wstring;
54 
55   // C function under std:
56   void memcpy();
57   void strcpy();
58 }
59 
60 void f(char * p, char * q, std::span<char> s, std::span<char> s2) {
61   typedef FILE * _Nullable aligned_file_ptr_t __attribute__((align_value(64)));
62   typedef char * _Nullable aligned_char_ptr_t __attribute__((align_value(64)));
63   aligned_file_ptr_t fp;
64   aligned_char_ptr_t cp;
65 
66   memcpy();                   // expected-warning{{function 'memcpy' is unsafe}}
67   std::memcpy();              // expected-warning{{function 'memcpy' is unsafe}}
68   __builtin_memcpy(p, q, 64); // expected-warning{{function '__builtin_memcpy' is unsafe}}
69   __builtin___memcpy_chk(p, q, 8, 64);  // expected-warning{{function '__builtin___memcpy_chk' is unsafe}}
70   __asan_memcpy();                      // expected-warning{{function '__asan_memcpy' is unsafe}}
71   strcpy();                   // expected-warning{{function 'strcpy' is unsafe}}
72   std::strcpy();              // expected-warning{{function 'strcpy' is unsafe}}
73   strcpy_s();                 // expected-warning{{function 'strcpy_s' is unsafe}}
74   wcscpy_s();                 // expected-warning{{function 'wcscpy_s' is unsafe}}
75 
76   /* Test printfs */
77   fprintf((FILE*)p, "%s%d", p, *p);  // expected-warning{{function 'fprintf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}
78   printf("%s%d", // expected-warning{{function 'printf' is unsafe}}
79 	 p,    // expected-note{{string argument is not guaranteed to be null-terminated}} note attached to the unsafe argument
80 	 *p);
81   printf(cp, p, *p); // expected-warning{{function 'printf' is unsafe}} // expected-note{{string argument is not guaranteed to be null-terminated}}
82   sprintf(q, "%s%d", "hello", *p); // expected-warning{{function 'sprintf' is unsafe}} expected-note{{change to 'snprintf' for explicit bounds checking}}
83   swprintf(q, "%s%d", "hello", *p); // expected-warning{{function 'swprintf' is unsafe}} expected-note{{change to 'snprintf' for explicit bounds checking}}
84   snprintf(q, 10, "%s%d", "hello", *p); // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}}
85   snprintf(cp, 10, "%s%d", "hello", *p); // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}}
86   snprintf(s.data(), s2.size(), "%s%d", "hello", *p); // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}}
87   snwprintf(s.data(), s2.size(), "%s%d", "hello", *p); // expected-warning{{function 'snwprintf' is unsafe}} expected-note{{buffer pointer and size may not match}}
88   snwprintf_s(                      // expected-warning{{function 'snwprintf_s' is unsafe}}
89 	      s.data(),             // expected-note{{buffer pointer and size may not match}} // note attached to the buffer
90 	      s2.size(),
91 	      "%s%d", "hello", *p);
92   vsnprintf(s.data(), s.size_bytes(), "%s%d", "hello", *p); // expected-warning{{function 'vsnprintf' is unsafe}} expected-note{{'va_list' is unsafe}}
93   sscanf(p, "%s%d", "hello", *p);    // expected-warning{{function 'sscanf' is unsafe}}
94   sscanf_s(p, "%s%d", "hello", *p);  // expected-warning{{function 'sscanf_s' is unsafe}}
95   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}}
96   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}}
97   wprintf(L"hello %s", p); // expected-warning{{function 'wprintf' is unsafe}} expected-note{{string argument is not guaranteed to be null-terminated}}
98 
99 
100   char a[10], b[11];
101   int c[10];
102   std::wstring WS;
103 
104   snprintf(a, sizeof(b), "%s", __PRETTY_FUNCTION__);         // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}}
105   snprintf((char*)c, sizeof(c), "%s", __PRETTY_FUNCTION__);  // expected-warning{{function 'snprintf' is unsafe}} expected-note{{buffer pointer and size may not match}}
106   fprintf((FILE*)p, "%P%d%p%i hello world %32s", *p, *p, p, *p, "hello"); // no warn
107   fprintf(fp, "%P%d%p%i hello world %32s", *p, *p, p, *p, "hello"); // no warn
108   printf("%s%d", "hello", *p); // no warn
109   snprintf(s.data(), s.size_bytes(), "%s%d", "hello", *p); // no warn
110   snprintf(s.data(), s.size_bytes(), "%s%d", __PRETTY_FUNCTION__, *p); // no warn
111   snwprintf(s.data(), s.size_bytes(), "%s%d", __PRETTY_FUNCTION__, *p); // no warn
112   snwprintf_s(s.data(), s.size_bytes(), "%s%d", __PRETTY_FUNCTION__, *p); // no warn
113   wprintf(L"hello %ls", L"world"); // no warn
114   wprintf(L"hello %ls", WS.c_str()); // no warn
115   strlen("hello");// no warn
116   __asan_printf();// a printf but no argument, so no warn
117 }
118 
119 void safe_examples(std::string s1, int *p) {
120   snprintf(s1.data(), s1.size_bytes(), "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", p, s1.c_str()); // no warn
121   snprintf(s1.data(), s1.size_bytes(), s1.c_str(), __PRETTY_FUNCTION__, *p, "hello", s1.c_str());      // no warn
122   printf("%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", p, s1.c_str());              // no warn
123   printf(s1.c_str(), __PRETTY_FUNCTION__, *p, "hello", s1.c_str());                   // no warn
124   fprintf((FILE*)0, "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", p, s1.c_str());   // no warn
125   fprintf((FILE*)0, s1.c_str(), __PRETTY_FUNCTION__, *p, "hello", s1.c_str());        // no warn
126 
127   char a[10];
128 
129   snprintf(a, sizeof a, "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", s1.c_str());         // no warn
130   snprintf(a, sizeof(decltype(a)), "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", s1.c_str());          // no warn
131   snprintf(a, 10, "%s%d%s%p%s", __PRETTY_FUNCTION__, *p, "hello", s1.c_str());                // no warn
132 }
133 
134 
135 void g(char *begin, char *end, char *p, std::span<char> s) {
136   std::copy(begin, end, p); // no warn
137   std::copy(s.begin(), s.end(), s.begin()); // no warn
138 }
139 
140 // warning gets turned off
141 void ff(char * p, char * q, std::span<char> s, std::span<char> s2) {
142 #pragma clang diagnostic push
143 #pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-libc-call"
144   memcpy();
145   std::memcpy();
146   __builtin_memcpy(p, q, 64);
147   __builtin___memcpy_chk(p, q, 8, 64);
148   __asan_memcpy();
149   strcpy();
150   std::strcpy();
151   strcpy_s();
152   wcscpy_s();
153 #pragma clang diagnostic pop
154 }
155