xref: /llvm-project/clang/test/SemaCXX/warn-unsafe-buffer-usage-in-container-span-construct.cpp (revision c60b055d463a3e9f18a494aec075f35d38d447a0)
19816863dSZiqing Luo // RUN: %clang_cc1 -std=c++20  -Wno-all  -Wunsafe-buffer-usage-in-container -verify %s
29816863dSZiqing Luo 
39816863dSZiqing Luo namespace std {
49816863dSZiqing Luo   template <class T> class span {
59816863dSZiqing Luo   public:
69816863dSZiqing Luo     constexpr span(T *, unsigned){}
79816863dSZiqing Luo 
89816863dSZiqing Luo     template<class Begin, class End>
99816863dSZiqing Luo     constexpr span(Begin first, End last){}
109816863dSZiqing Luo 
119816863dSZiqing Luo     T * data();
129816863dSZiqing Luo 
139816863dSZiqing Luo     constexpr span() {};
149816863dSZiqing Luo 
159816863dSZiqing Luo     constexpr span(const std::span<T> &span) {};
169816863dSZiqing Luo 
179816863dSZiqing Luo     template<class R>
189816863dSZiqing Luo     constexpr span(R && range){};
199816863dSZiqing Luo   };
209816863dSZiqing Luo 
219816863dSZiqing Luo 
229816863dSZiqing Luo   template< class T >
239816863dSZiqing Luo   T&& move( T&& t ) noexcept;
240dcb0acfSMalavika Samak 
250dcb0acfSMalavika Samak   template <class _Tp>
260dcb0acfSMalavika Samak   _Tp* addressof(_Tp& __x) {
270dcb0acfSMalavika Samak     return &__x;
280dcb0acfSMalavika Samak   }
290dcb0acfSMalavika Samak 
309816863dSZiqing Luo }
319816863dSZiqing Luo 
329816863dSZiqing Luo namespace irrelevant_constructors {
339816863dSZiqing Luo   void non_two_param_constructors() {
349816863dSZiqing Luo     class Array {
359816863dSZiqing Luo     } a;
369816863dSZiqing Luo     std::span<int> S;      // no warn
379816863dSZiqing Luo     std::span<int> S1{};   // no warn
389816863dSZiqing Luo     std::span<int> S2{std::move(a)};  // no warn
399816863dSZiqing Luo     std::span<int> S3{S2};  // no warn
409816863dSZiqing Luo   }
419816863dSZiqing Luo } // irrelevant_constructors
429816863dSZiqing Luo 
439816863dSZiqing Luo namespace construct_wt_ptr_size {
449816863dSZiqing Luo   std::span<int> warnVarInit(int *p) {
459816863dSZiqing Luo     std::span<int> S{p, 10};                     // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
469816863dSZiqing Luo     std::span<int> S1(p, 10);                    // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
479816863dSZiqing Luo     std::span<int> S2 = std::span{p, 10};        // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
489816863dSZiqing Luo     std::span<int> S3 = std::span(p, 10);        // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
499816863dSZiqing Luo     std::span<int> S4 = std::span<int>{p, 10};   // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
509816863dSZiqing Luo     std::span<int> S5 = std::span<int>(p, 10);   // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
519816863dSZiqing Luo     std::span<int> S6 = {p, 10};                 // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
529816863dSZiqing Luo     auto S7 = std::span<int>{p, 10};             // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
539816863dSZiqing Luo     auto S8 = std::span<int>(p, 10);             // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
549816863dSZiqing Luo     const auto &S9 = std::span<int>{p, 10};      // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
559816863dSZiqing Luo     auto &&S10 = std::span<int>(p, 10);          // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
569816863dSZiqing Luo 
579816863dSZiqing Luo #define Ten 10
589816863dSZiqing Luo 
599816863dSZiqing Luo     std::span S11 = std::span<int>{p, Ten};      // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
609816863dSZiqing Luo 
619816863dSZiqing Luo     if (auto X = std::span<int>{p, Ten}; S10.data()) { // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
629816863dSZiqing Luo     }
639816863dSZiqing Luo 
649816863dSZiqing Luo     auto X = warnVarInit(p); // function return is fine
659816863dSZiqing Luo     return S;
669816863dSZiqing Luo   }
679816863dSZiqing Luo 
689816863dSZiqing Luo   template<typename T>
699816863dSZiqing Luo   void foo(const T &, const T &&, T);
709816863dSZiqing Luo 
719816863dSZiqing Luo   std::span<int> warnTemp(int *p) {
729816863dSZiqing Luo     foo(std::span<int>{p, 10},                       // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
739816863dSZiqing Luo 	std::move(std::span<int>{p, 10}),            // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
749816863dSZiqing Luo 	std::span<int>{p, 10});                      // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
759816863dSZiqing Luo 
769816863dSZiqing Luo     std::span<int> Arr[1] = {std::span<int>{p, 10}}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
779816863dSZiqing Luo 
789816863dSZiqing Luo     if (std::span<int>{p, 10}.data()) {              // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
799816863dSZiqing Luo     }
809816863dSZiqing Luo     return std::span<int>{p, 10};                    // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
819816863dSZiqing Luo   }
829816863dSZiqing Luo 
830dcb0acfSMalavika Samak   // addressof method defined outside std namespace.
840dcb0acfSMalavika Samak   template <class _Tp>
850dcb0acfSMalavika Samak   _Tp* addressof(_Tp& __x) {
860dcb0acfSMalavika Samak     return &__x;
870dcb0acfSMalavika Samak   }
880dcb0acfSMalavika Samak 
899816863dSZiqing Luo   void notWarnSafeCases(unsigned n, int *p) {
909816863dSZiqing Luo     int X;
919816863dSZiqing Luo     unsigned Y = 10;
929816863dSZiqing Luo     std::span<int> S = std::span{&X, 1}; // no-warning
930dcb0acfSMalavika Samak     S = std::span{std::addressof(X), 1}; // no-warning
949816863dSZiqing Luo     int Arr[10];
959aa3b53aSZiqing Luo     typedef int TenInts_t[10];
969aa3b53aSZiqing Luo     TenInts_t Arr2;
979816863dSZiqing Luo 
989816863dSZiqing Luo     S = std::span{&X, 2};                // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
990dcb0acfSMalavika Samak     S = std::span{std::addressof(X), 2}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1000dcb0acfSMalavika Samak     // Warn when a non std method also named addressof
1010dcb0acfSMalavika Samak     S = std::span{addressof(X), 1}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1020dcb0acfSMalavika Samak 
1039816863dSZiqing Luo     S = std::span{new int[10], 10};      // no-warning
1049816863dSZiqing Luo     S = std::span{new int[n], n};        // no-warning
1059816863dSZiqing Luo     S = std::span{new int, 1};           // no-warning
1069816863dSZiqing Luo     S = std::span{new int, X};           // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1079816863dSZiqing Luo     S = std::span{new int[n--], n--};    // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1089816863dSZiqing Luo     S = std::span{new int[10], 11};      // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1099816863dSZiqing Luo     S = std::span{new int[10], 9};       // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}  // not smart enough to tell its safe
1109816863dSZiqing Luo     S = std::span{new int[10], Y};       // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}  // not smart enough to tell its safe
1119816863dSZiqing Luo     S = std::span{Arr, 10};              // no-warning
1129aa3b53aSZiqing Luo     S = std::span{Arr2, 10};             // no-warning
1139816863dSZiqing Luo     S = std::span{Arr, Y};               // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}  // not smart enough to tell its safe
1149816863dSZiqing Luo     S = std::span{p, 0};                 // no-warning
1159816863dSZiqing Luo   }
1169816863dSZiqing Luo } // namespace construct_wt_ptr_size
1179816863dSZiqing Luo 
1189816863dSZiqing Luo namespace construct_wt_begin_end {
1199816863dSZiqing Luo   class It {};
1209816863dSZiqing Luo 
1219816863dSZiqing Luo   std::span<int> warnVarInit(It &First, It &Last) {
1229816863dSZiqing Luo     std::span<int> S{First, Last};                     // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1239816863dSZiqing Luo     std::span<int> S1(First, Last);                    // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1249816863dSZiqing Luo     std::span<int> S2 = std::span<int>{First, Last};   // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1259816863dSZiqing Luo     std::span<int> S3 = std::span<int>(First, Last);   // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1269816863dSZiqing Luo     std::span<int> S4 = std::span<int>{First, Last};   // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1279816863dSZiqing Luo     std::span<int> S5 = std::span<int>(First, Last);   // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1289816863dSZiqing Luo     std::span<int> S6 = {First, Last};                 // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1299816863dSZiqing Luo     auto S7 = std::span<int>{First, Last};             // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1309816863dSZiqing Luo     auto S8 = std::span<int>(First, Last);             // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1319816863dSZiqing Luo     const auto &S9 = std::span<int>{First, Last};      // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1329816863dSZiqing Luo     auto &&S10 = std::span<int>(First, Last);          // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1339816863dSZiqing Luo 
1349816863dSZiqing Luo     if (auto X = std::span<int>{First, Last}; S10.data()) { // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1359816863dSZiqing Luo     }
1369816863dSZiqing Luo 
1379816863dSZiqing Luo     auto X = warnVarInit(First, Last); // function return is fine
1389816863dSZiqing Luo     return S;
1399816863dSZiqing Luo   }
1409816863dSZiqing Luo 
1419816863dSZiqing Luo   template<typename T>
1429816863dSZiqing Luo   void foo(const T &, const T &&, T);
1439816863dSZiqing Luo 
1449816863dSZiqing Luo   std::span<int> warnTemp(It &First, It &Last) {
1459816863dSZiqing Luo     foo(std::span<int>{First, Last},                       // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1469816863dSZiqing Luo 	std::move(std::span<int>{First, Last}),            // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1479816863dSZiqing Luo 	std::span<int>{First, Last});                      // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1489816863dSZiqing Luo 
1499816863dSZiqing Luo     std::span<int> Arr[1] = {std::span<int>{First, Last}}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1509816863dSZiqing Luo 
1519816863dSZiqing Luo     if (std::span<int>{First, Last}.data()) {              // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1529816863dSZiqing Luo     }
1539816863dSZiqing Luo     return std::span<int>{First, Last};                    // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
1549816863dSZiqing Luo   }
1559816863dSZiqing Luo } // namespace construct_wt_begin_end
1569816863dSZiqing Luo 
1579816863dSZiqing Luo namespace test_flag {
1589816863dSZiqing Luo   void f(int *p) {
1599816863dSZiqing Luo #pragma clang diagnostic push
1609816863dSZiqing Luo #pragma clang diagnostic ignored "-Wunsafe-buffer-usage"  // this flag turns off every unsafe-buffer warning
1619816863dSZiqing Luo     std::span<int> S{p, 10};   // no-warning
1629816863dSZiqing Luo     p++;                       // no-warning
1639816863dSZiqing Luo #pragma clang diagnostic pop
1649816863dSZiqing Luo 
1659816863dSZiqing Luo #pragma clang diagnostic push
1669816863dSZiqing Luo #pragma clang diagnostic warning "-Wunsafe-buffer-usage"
1679816863dSZiqing Luo #pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-container"
1689816863dSZiqing Luo     // turn on all unsafe-buffer warnings except for the ones under `-Wunsafe-buffer-usage-in-container`
1699816863dSZiqing Luo     std::span<int> S2{p, 10};   // no-warning
1709816863dSZiqing Luo 
1719816863dSZiqing Luo     p++; // expected-warning{{unsafe pointer arithmetic}}\
1729816863dSZiqing Luo 	    expected-note{{pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions}}
1739816863dSZiqing Luo #pragma clang diagnostic pop
1749816863dSZiqing Luo 
1759816863dSZiqing Luo   }
1769816863dSZiqing Luo } //namespace test_flag
177*c60b055dSZequan Wu 
178*c60b055dSZequan Wu struct HoldsStdSpanAndInitializedInCtor {
179*c60b055dSZequan Wu   char* Ptr;
180*c60b055dSZequan Wu   unsigned Size;
181*c60b055dSZequan Wu   std::span<char> Span{Ptr, Size};  // no-warning (this code is unreachable)
182*c60b055dSZequan Wu 
183*c60b055dSZequan Wu   HoldsStdSpanAndInitializedInCtor(char* P, unsigned S)
184*c60b055dSZequan Wu       : Span(P, S)  // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
185*c60b055dSZequan Wu   {}
186*c60b055dSZequan Wu };
187*c60b055dSZequan Wu 
188*c60b055dSZequan Wu struct HoldsStdSpanAndNotInitializedInCtor {
189*c60b055dSZequan Wu   char* Ptr;
190*c60b055dSZequan Wu   unsigned Size;
191*c60b055dSZequan Wu   std::span<char> Span{Ptr, Size}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}
192*c60b055dSZequan Wu 
193*c60b055dSZequan Wu   HoldsStdSpanAndNotInitializedInCtor(char* P, unsigned S)
194*c60b055dSZequan Wu       : Ptr(P), Size(S)
195*c60b055dSZequan Wu   {}
196*c60b055dSZequan Wu };
197