xref: /llvm-project/clang/test/SemaCXX/warn-unsafe-buffer-usage-in-container-span-construct.cpp (revision c60b055d463a3e9f18a494aec075f35d38d447a0)
1 // RUN: %clang_cc1 -std=c++20  -Wno-all  -Wunsafe-buffer-usage-in-container -verify %s
2 
3 namespace std {
4   template <class T> class span {
5   public:
6     constexpr span(T *, unsigned){}
7 
8     template<class Begin, class End>
9     constexpr span(Begin first, End last){}
10 
11     T * data();
12 
13     constexpr span() {};
14 
15     constexpr span(const std::span<T> &span) {};
16 
17     template<class R>
18     constexpr span(R && range){};
19   };
20 
21 
22   template< class T >
23   T&& move( T&& t ) noexcept;
24 
25   template <class _Tp>
26   _Tp* addressof(_Tp& __x) {
27     return &__x;
28   }
29 
30 }
31 
32 namespace irrelevant_constructors {
33   void non_two_param_constructors() {
34     class Array {
35     } a;
36     std::span<int> S;      // no warn
37     std::span<int> S1{};   // no warn
38     std::span<int> S2{std::move(a)};  // no warn
39     std::span<int> S3{S2};  // no warn
40   }
41 } // irrelevant_constructors
42 
43 namespace construct_wt_ptr_size {
44   std::span<int> warnVarInit(int *p) {
45     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}}
46     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}}
47     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}}
48     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}}
49     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}}
50     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}}
51     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}}
52     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}}
53     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}}
54     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}}
55     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}}
56 
57 #define Ten 10
58 
59     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}}
60 
61     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}}
62     }
63 
64     auto X = warnVarInit(p); // function return is fine
65     return S;
66   }
67 
68   template<typename T>
69   void foo(const T &, const T &&, T);
70 
71   std::span<int> warnTemp(int *p) {
72     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}}
73 	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}}
74 	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}}
75 
76     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}}
77 
78     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}}
79     }
80     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}}
81   }
82 
83   // addressof method defined outside std namespace.
84   template <class _Tp>
85   _Tp* addressof(_Tp& __x) {
86     return &__x;
87   }
88 
89   void notWarnSafeCases(unsigned n, int *p) {
90     int X;
91     unsigned Y = 10;
92     std::span<int> S = std::span{&X, 1}; // no-warning
93     S = std::span{std::addressof(X), 1}; // no-warning
94     int Arr[10];
95     typedef int TenInts_t[10];
96     TenInts_t Arr2;
97 
98     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}}
99     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}}
100     // Warn when a non std method also named addressof
101     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}}
102 
103     S = std::span{new int[10], 10};      // no-warning
104     S = std::span{new int[n], n};        // no-warning
105     S = std::span{new int, 1};           // no-warning
106     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}}
107     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}}
108     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}}
109     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
110     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
111     S = std::span{Arr, 10};              // no-warning
112     S = std::span{Arr2, 10};             // no-warning
113     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
114     S = std::span{p, 0};                 // no-warning
115   }
116 } // namespace construct_wt_ptr_size
117 
118 namespace construct_wt_begin_end {
119   class It {};
120 
121   std::span<int> warnVarInit(It &First, It &Last) {
122     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}}
123     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}}
124     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}}
125     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}}
126     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}}
127     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}}
128     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}}
129     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}}
130     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}}
131     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}}
132     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}}
133 
134     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}}
135     }
136 
137     auto X = warnVarInit(First, Last); // function return is fine
138     return S;
139   }
140 
141   template<typename T>
142   void foo(const T &, const T &&, T);
143 
144   std::span<int> warnTemp(It &First, It &Last) {
145     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}}
146 	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}}
147 	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}}
148 
149     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}}
150 
151     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}}
152     }
153     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}}
154   }
155 } // namespace construct_wt_begin_end
156 
157 namespace test_flag {
158   void f(int *p) {
159 #pragma clang diagnostic push
160 #pragma clang diagnostic ignored "-Wunsafe-buffer-usage"  // this flag turns off every unsafe-buffer warning
161     std::span<int> S{p, 10};   // no-warning
162     p++;                       // no-warning
163 #pragma clang diagnostic pop
164 
165 #pragma clang diagnostic push
166 #pragma clang diagnostic warning "-Wunsafe-buffer-usage"
167 #pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-container"
168     // turn on all unsafe-buffer warnings except for the ones under `-Wunsafe-buffer-usage-in-container`
169     std::span<int> S2{p, 10};   // no-warning
170 
171     p++; // expected-warning{{unsafe pointer arithmetic}}\
172 	    expected-note{{pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions}}
173 #pragma clang diagnostic pop
174 
175   }
176 } //namespace test_flag
177 
178 struct HoldsStdSpanAndInitializedInCtor {
179   char* Ptr;
180   unsigned Size;
181   std::span<char> Span{Ptr, Size};  // no-warning (this code is unreachable)
182 
183   HoldsStdSpanAndInitializedInCtor(char* P, unsigned S)
184       : 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   {}
186 };
187 
188 struct HoldsStdSpanAndNotInitializedInCtor {
189   char* Ptr;
190   unsigned Size;
191   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 
193   HoldsStdSpanAndNotInitializedInCtor(char* P, unsigned S)
194       : Ptr(P), Size(S)
195   {}
196 };
197