295 lines · cpp
1// RUN: %clang_cc1 -std=c++20 -Wno-all -Wunsafe-buffer-usage-in-container -verify %s2 3typedef unsigned int size_t;4 5namespace std {6 template <class T> class span {7 public:8 constexpr span(T *, unsigned){}9 10 template<class Begin, class End>11 constexpr span(Begin first, End last){}12 13 T * data();14 15 constexpr span() {};16 17 constexpr span(const std::span<T> &span) {};18 19 template<class R>20 constexpr span(R && range){};21 22 T* begin() noexcept;23 T* end() noexcept;24 };25 26 27 template< class T >28 T&& move( T&& t ) noexcept;29 30 template <class _Tp>31 _Tp* addressof(_Tp& __x) {32 return &__x;33 }34 35 template <typename T, size_t N>36 struct array {37 T* begin() noexcept;38 const T* begin() const noexcept;39 T* end() noexcept;40 const T* end() const noexcept;41 size_t size() const noexcept;42 T * data() const noexcept;43 T& operator[](size_t n);44 };45 46 template<class T>47 class initializer_list {48 public:49 size_t size() const noexcept;50 const T* begin() const noexcept;51 const T* end() const noexcept;52 T * data() const noexcept;53 };54 55 template<typename T>56 struct basic_string {57 T *c_str() const noexcept;58 T *data() const noexcept;59 unsigned size();60 const T* begin() const noexcept;61 const T* end() const noexcept;62 };63 64 typedef basic_string<char> string;65 typedef basic_string<wchar_t> wstring;66}67 68namespace irrelevant_constructors {69 void non_two_param_constructors() {70 class Array {71 } a;72 std::span<int> S; // no warn73 std::span<int> S1{}; // no warn74 std::span<int> S2{std::move(a)}; // no warn75 std::span<int> S3{S2}; // no warn76 }77} // irrelevant_constructors78 79namespace construct_wt_ptr_size {80 std::span<int> warnVarInit(int *p) {81 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}}82 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}}83 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}}84 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}}85 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}}86 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}}87 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}}88 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}}89 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}}90 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}}91 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}}92 93#define Ten 1094 95 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}}96 97 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}}98 }99 100 auto X = warnVarInit(p); // function return is fine101 return S;102 }103 104 template<typename T>105 void foo(const T &, const T &&, T);106 107 std::span<int> warnTemp(int *p) {108 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}}109 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}}110 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}}111 112 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}}113 114 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}}115 }116 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}}117 }118 119 // addressof method defined outside std namespace.120 template <class _Tp>121 _Tp* addressof(_Tp& __x) {122 return &__x;123 }124 125 void notWarnSafeCases(unsigned n, int *p) {126 int X;127 unsigned Y = 10;128 std::span<int> S = std::span{&X, 1}; // no-warning129 S = std::span{std::addressof(X), 1}; // no-warning130 int Arr[10];131 typedef int TenInts_t[10];132 TenInts_t Arr2;133 134 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}}135 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}}136 // Warn when a non std method also named addressof137 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}}138 139 S = std::span{new int[10], 10}; // no-warning140 S = std::span{new int[n], n}; // no-warning141 S = std::span{new int, 1}; // no-warning142 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}}143 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}}144 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}}145 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 safe146 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 safe147 S = std::span{Arr, 10}; // no-warning148 S = std::span{Arr2, 10}; // no-warning149 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 safe150 S = std::span{p, 0}; // no-warning151 }152} // namespace construct_wt_ptr_size153 154namespace construct_wt_begin_end {155 class It {};156 157 std::span<int> warnVarInit(It &First, It &Last) {158 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}}159 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}}160 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}}161 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}}162 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}}163 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}}164 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}}165 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}}166 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}}167 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}}168 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}}169 170 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}}171 }172 173 auto X = warnVarInit(First, Last); // function return is fine174 return S;175 }176 177 template<typename T>178 void foo(const T &, const T &&, T);179 180 std::span<int> warnTemp(It &First, It &Last) {181 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}}182 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}}183 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}}184 185 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}}186 187 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}}188 }189 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}}190 }191} // namespace construct_wt_begin_end192 193namespace test_alloc_size_attr {194 void * my_alloc(unsigned size) __attribute__((alloc_size(1)));195 void * my_alloc2(unsigned count, unsigned size) __attribute__((alloc_size(1,2)));196 197 void safe(int x, unsigned y) {198 std::span<char>{(char *)my_alloc(10), 10};199 std::span<char>{(char *)my_alloc(x), x};200 std::span<char>{(char *)my_alloc(x * y), x * y};201 std::span<char>{(char *)my_alloc(x * y), y * x};202 std::span<char>{(char *)my_alloc(x * y + x), x * y + x};203 std::span<char>{(char *)my_alloc(x * y + x), x + y * x};204 205 std::span<char>{(char *)my_alloc2(x, y), x * y};206 std::span<char>{(char *)my_alloc2(x, y), y * x};207 //foo(std::span<char>{(char *)my_alloc2(x, sizeof(char)), x}); // lets not worry about this case for now208 std::span<char>{(char *)my_alloc2(x, sizeof(char)), x * sizeof(char)};209 //foo(std::span<char>{(char *)my_alloc2(10, sizeof(char)), 10});210 std::span<char>{(char *)my_alloc2(10, sizeof(char)), 10 * sizeof(char)};211 }212 213 void unsafe(int x, int y) {214 std::span<char>{(char *)my_alloc(10), 11}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}215 std::span<char>{(char *)my_alloc(x * y), x + y}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}216 std::span<int>{(int *)my_alloc(x), x}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}217 std::span<char>{(char *)my_alloc2(x, y), x + y}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}218 }219 220 void unsupport(int x, int y, int z) {221 // Casting to `T*` where sizeof(T) > 1 is not supported yet:222 std::span<int>{(int *)my_alloc2(x, y), x * y}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}223 std::span<long>{(long *)my_alloc(10 * sizeof(long)), 10}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}224 std::span<long>{(long *)my_alloc2(x, sizeof(long)), x}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}225 std::span<long>{(long *)my_alloc2(x, sizeof(long)), x}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}226 // The expression is too complicated:227 std::span<char>{(char *)my_alloc(x + y + z), z + y + x}; // expected-warning{{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}228 }229}230 231namespace test_flag {232 void f(int *p) {233#pragma clang diagnostic push234#pragma clang diagnostic ignored "-Wunsafe-buffer-usage" // this flag turns off every unsafe-buffer warning235 std::span<int> S{p, 10}; // no-warning236 p++; // no-warning237#pragma clang diagnostic pop238 239#pragma clang diagnostic push240#pragma clang diagnostic warning "-Wunsafe-buffer-usage"241#pragma clang diagnostic ignored "-Wunsafe-buffer-usage-in-container"242 // turn on all unsafe-buffer warnings except for the ones under `-Wunsafe-buffer-usage-in-container`243 std::span<int> S2{p, 10}; // no-warning244 245 p++; // expected-warning{{unsafe pointer arithmetic}}\246 expected-note{{pass -fsafe-buffer-usage-suggestions to receive code hardening suggestions}}247#pragma clang diagnostic pop248 249 }250} //namespace test_flag251 252struct HoldsStdSpanAndInitializedInCtor {253 char* Ptr;254 unsigned Size;255 std::span<char> Span{Ptr, Size}; // no-warning (this code is unreachable)256 257 HoldsStdSpanAndInitializedInCtor(char* P, unsigned S)258 : 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}}259 {}260};261 262struct HoldsStdSpanAndNotInitializedInCtor {263 char* Ptr;264 unsigned Size;265 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}}266 267 HoldsStdSpanAndNotInitializedInCtor(char* P, unsigned S)268 : Ptr(P), Size(S)269 {}270};271 272namespace test_begin_end {273 struct Object {274 int * begin();275 int * end();276 };277 void safe_cases(std::span<int> Sp, std::array<int, 10> Arr, std::string Str, std::initializer_list<Object> Il) {278 std::span<int>{Sp.begin(), Sp.end()};279 std::span<int>{Arr.begin(), Arr.end()};280 std::span<char>{Str.begin(), Str.end()};281 std::span<Object>{Il.begin(), Il.end()};282 }283 284 void unsafe_cases(std::span<int> Sp, std::array<int, 10> Arr, std::string Str, std::initializer_list<Object> Il,285 Object Obj) {286 std::span<int>{Obj.begin(), Obj.end()}; // expected-warning {{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}287 std::span<int>{Sp.end(), Sp.begin()}; // expected-warning {{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}288 std::span<int>{Sp.begin(), Arr.end()}; // expected-warning {{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}289 }290 291 void unsupport_cases(std::array<Object, 10> Arr) {292 std::span<int>{Arr[0].begin(), Arr[0].end()}; // expected-warning {{the two-parameter std::span construction is unsafe as it can introduce mismatch between buffer size and the bound information}}293 }294}295