diff --git a/libcxx/include/__assert b/libcxx/include/__assert index 90eaa6023587b..18245c03bf475 100644 --- a/libcxx/include/__assert +++ b/libcxx/include/__assert @@ -115,4 +115,10 @@ #endif // _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_FAST // clang-format on +#if _LIBCPP_HARDENING_MODE == _LIBCPP_HARDENING_MODE_NONE +# define _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION [[_Clang::__unsafe_buffer_usage__]] +#else +# define _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION // those are checked +#endif + #endif // _LIBCPP___ASSERT diff --git a/libcxx/include/__iterator/wrap_iter.h b/libcxx/include/__iterator/wrap_iter.h index 966c4675b7049..cbac5054277bb 100644 --- a/libcxx/include/__iterator/wrap_iter.h +++ b/libcxx/include/__iterator/wrap_iter.h @@ -10,6 +10,7 @@ #ifndef _LIBCPP___ITERATOR_WRAP_ITER_H #define _LIBCPP___ITERATOR_WRAP_ITER_H +#include <__assert> #include <__compare/ordering.h> #include <__compare/three_way_comparable.h> #include <__config> @@ -57,7 +58,10 @@ class __wrap_iter { int> = 0> _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __wrap_iter(const __wrap_iter<_OtherIter>& __u) _NOEXCEPT : __i_(__u.__i_) {} - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference operator*() const _NOEXCEPT { return *__i_; } + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference + operator*() const _NOEXCEPT { + return *__i_; + } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pointer operator->() const _NOEXCEPT { return std::__to_address(__i_); } @@ -96,7 +100,8 @@ class __wrap_iter { *this += -__n; return *this; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference operator[](difference_type __n) const _NOEXCEPT { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference + operator[](difference_type __n) const _NOEXCEPT { return __i_[__n]; } diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h index 6ba7ba7bcf724..96207c3c48173 100644 --- a/libcxx/include/__vector/vector.h +++ b/libcxx/include/__vector/vector.h @@ -391,11 +391,13 @@ class _LIBCPP_TEMPLATE_VIS vector { // // element access // - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference operator[](size_type __n) _NOEXCEPT { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference + operator[](size_type __n) _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < size(), "vector[] index out of bounds"); return this->__begin_[__n]; } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference operator[](size_type __n) const _NOEXCEPT { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference + operator[](size_type __n) const _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n < size(), "vector[] index out of bounds"); return this->__begin_[__n]; } @@ -410,19 +412,23 @@ class _LIBCPP_TEMPLATE_VIS vector { return this->__begin_[__n]; } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference front() _NOEXCEPT { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference + front() _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "front() called on an empty vector"); return *this->__begin_; } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference front() const _NOEXCEPT { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference + front() const _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "front() called on an empty vector"); return *this->__begin_; } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() _NOEXCEPT { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference + back() _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "back() called on an empty vector"); return *(this->__end_ - 1); } - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference + back() const _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "back() called on an empty vector"); return *(this->__end_ - 1); } @@ -462,7 +468,7 @@ class _LIBCPP_TEMPLATE_VIS vector { } #endif - _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void pop_back() { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void pop_back() { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "vector::pop_back called on an empty vector"); this->__destruct_at_end(this->__end_ - 1); } @@ -1115,7 +1121,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 inline } template -_LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI typename vector<_Tp, _Allocator>::iterator +_LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_CONSTEXPR_SINCE_CXX20 inline _LIBCPP_HIDE_FROM_ABI +typename vector<_Tp, _Allocator>::iterator vector<_Tp, _Allocator>::erase(const_iterator __position) { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( __position != end(), "vector::erase(iterator) called with a non-dereferenceable iterator"); @@ -1126,7 +1133,7 @@ vector<_Tp, _Allocator>::erase(const_iterator __position) { } template -_LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator +_LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator vector<_Tp, _Allocator>::erase(const_iterator __first, const_iterator __last) { _LIBCPP_ASSERT_VALID_INPUT_RANGE(__first <= __last, "vector::erase(first, last) called with invalid range"); pointer __p = this->__begin_ + (__first - begin()); diff --git a/libcxx/include/span b/libcxx/include/span index 2d43d1d1079e4..34d8209f929c6 100644 --- a/libcxx/include/span +++ b/libcxx/include/span @@ -320,12 +320,14 @@ public: return span{data() + size() - _Count, _Count}; } - _LIBCPP_HIDE_FROM_ABI constexpr span first(size_type __count) const noexcept { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI constexpr span + first(size_type __count) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count <= size(), "span::first(count): count out of range"); return {data(), __count}; } - _LIBCPP_HIDE_FROM_ABI constexpr span last(size_type __count) const noexcept { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI constexpr span + last(size_type __count) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count <= size(), "span::last(count): count out of range"); return {data() + size() - __count, __count}; } @@ -341,7 +343,7 @@ public: return _ReturnType{data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count}; } - _LIBCPP_HIDE_FROM_ABI constexpr span + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI constexpr span subspan(size_type __offset, size_type __count = dynamic_extent) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__offset <= size(), "span::subspan(offset, count): offset out of range"); if (__count == dynamic_extent) @@ -355,7 +357,8 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr size_type size_bytes() const noexcept { return _Extent * sizeof(element_type); } [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const noexcept { return _Extent == 0; } - _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](size_type __idx) const noexcept { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI constexpr reference + operator[](size_type __idx) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__idx < size(), "span::operator[](index): index out of range"); return __data_[__idx]; } @@ -368,12 +371,12 @@ public: } # endif - _LIBCPP_HIDE_FROM_ABI constexpr reference front() const noexcept { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI constexpr reference front() const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "span::front() on empty span"); return __data_[0]; } - _LIBCPP_HIDE_FROM_ABI constexpr reference back() const noexcept { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI constexpr reference back() const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "span::back() on empty span"); return __data_[size() - 1]; } @@ -477,36 +480,41 @@ public: : __data_{__other.data()}, __size_{__other.size()} {} template - _LIBCPP_HIDE_FROM_ABI constexpr span first() const noexcept { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI constexpr span + first() const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(_Count <= size(), "span::first(): Count out of range"); return span{data(), _Count}; } template - _LIBCPP_HIDE_FROM_ABI constexpr span last() const noexcept { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI constexpr span + last() const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(_Count <= size(), "span::last(): Count out of range"); return span{data() + size() - _Count, _Count}; } - _LIBCPP_HIDE_FROM_ABI constexpr span first(size_type __count) const noexcept { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI constexpr span + first(size_type __count) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count <= size(), "span::first(count): count out of range"); return {data(), __count}; } - _LIBCPP_HIDE_FROM_ABI constexpr span last(size_type __count) const noexcept { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI constexpr span + last(size_type __count) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__count <= size(), "span::last(count): count out of range"); return {data() + size() - __count, __count}; } template - _LIBCPP_HIDE_FROM_ABI constexpr span subspan() const noexcept { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI constexpr span + subspan() const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(_Offset <= size(), "span::subspan(): Offset out of range"); _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(_Count == dynamic_extent || _Count <= size() - _Offset, "span::subspan(): Offset + Count out of range"); return span{data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count}; } - constexpr span _LIBCPP_HIDE_FROM_ABI + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI constexpr span subspan(size_type __offset, size_type __count = dynamic_extent) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__offset <= size(), "span::subspan(offset, count): offset out of range"); if (__count == dynamic_extent) @@ -520,7 +528,8 @@ public: _LIBCPP_HIDE_FROM_ABI constexpr size_type size_bytes() const noexcept { return __size_ * sizeof(element_type); } [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr bool empty() const noexcept { return __size_ == 0; } - _LIBCPP_HIDE_FROM_ABI constexpr reference operator[](size_type __idx) const noexcept { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI constexpr reference + operator[](size_type __idx) const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__idx < size(), "span::operator[](index): index out of range"); return __data_[__idx]; } @@ -533,12 +542,12 @@ public: } # endif - _LIBCPP_HIDE_FROM_ABI constexpr reference front() const noexcept { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI constexpr reference front() const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "span::front() on empty span"); return __data_[0]; } - _LIBCPP_HIDE_FROM_ABI constexpr reference back() const noexcept { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI constexpr reference back() const noexcept { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "span::back() on empty span"); return __data_[size() - 1]; } diff --git a/libcxx/include/string b/libcxx/include/string index 17bf4b3b98bf3..d6a09951ad1a1 100644 --- a/libcxx/include/string +++ b/libcxx/include/string @@ -1340,7 +1340,8 @@ public: return size() == 0; } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference operator[](size_type __pos) const _NOEXCEPT { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference + operator[](size_type __pos) const _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__pos <= size(), "string index out of bounds"); if (__builtin_constant_p(__pos) && !__fits_in_sso(__pos)) { return *(__get_long_pointer() + __pos); @@ -1348,7 +1349,8 @@ public: return *(data() + __pos); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference operator[](size_type __pos) _NOEXCEPT { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference + operator[](size_type __pos) _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__pos <= size(), "string index out of bounds"); if (__builtin_constant_p(__pos) && !__fits_in_sso(__pos)) { return *(__get_long_pointer() + __pos); @@ -1446,24 +1448,31 @@ public: # endif // _LIBCPP_CXX03_LANG _LIBCPP_CONSTEXPR_SINCE_CXX20 void push_back(value_type __c); - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void pop_back(); + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 void pop_back() { + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "string::pop_back(): string is already empty"); + __erase_to_end(size() - 1); + } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference front() _NOEXCEPT { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference + front() _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "string::front(): string is empty"); return *__get_pointer(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference front() const _NOEXCEPT { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference + front() const _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "string::front(): string is empty"); return *data(); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference back() _NOEXCEPT { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 reference + back() _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "string::back(): string is empty"); return *(__get_pointer() + size() - 1); } - _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference back() const _NOEXCEPT { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 const_reference + back() const _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "string::back(): string is empty"); return *(data() + size() - 1); } @@ -3311,12 +3320,6 @@ basic_string<_CharT, _Traits, _Allocator>::erase(const_iterator __first, const_i return __b + static_cast(__r); } -template -inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::pop_back() { - _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "string::pop_back(): string is already empty"); - __erase_to_end(size() - 1); -} - template inline _LIBCPP_CONSTEXPR_SINCE_CXX20 void basic_string<_CharT, _Traits, _Allocator>::clear() _NOEXCEPT { size_type __old_size = size(); diff --git a/libcxx/include/string_view b/libcxx/include/string_view index 27b9f152ea290..d58ed418fc470 100644 --- a/libcxx/include/string_view +++ b/libcxx/include/string_view @@ -403,7 +403,8 @@ public: [[__nodiscard__]] _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool empty() const _NOEXCEPT { return __size_ == 0; } // [string.view.access], element access - _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_reference operator[](size_type __pos) const _NOEXCEPT { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_reference + operator[](size_type __pos) const _NOEXCEPT { return _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__pos < size(), "string_view[] index out of bounds"), __data_[__pos]; } @@ -411,24 +412,28 @@ public: return __pos >= size() ? (__throw_out_of_range("string_view::at"), __data_[0]) : __data_[__pos]; } - _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_reference front() const _NOEXCEPT { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_reference + front() const _NOEXCEPT { return _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "string_view::front(): string is empty"), __data_[0]; } - _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_reference + back() const _NOEXCEPT { return _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(!empty(), "string_view::back(): string is empty"), __data_[__size_ - 1]; } _LIBCPP_CONSTEXPR _LIBCPP_HIDE_FROM_ABI const_pointer data() const _NOEXCEPT { return __data_; } // [string.view.modifiers], modifiers: - _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI void remove_prefix(size_type __n) _NOEXCEPT { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI void + remove_prefix(size_type __n) _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n <= size(), "remove_prefix() can't remove more than size()"); __data_ += __n; __size_ -= __n; } - _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI void remove_suffix(size_type __n) _NOEXCEPT { + _LIBCPP_VALID_ELEMENT_ACCESS_PRECONDITION _LIBCPP_CONSTEXPR_SINCE_CXX14 _LIBCPP_HIDE_FROM_ABI void + remove_suffix(size_type __n) _NOEXCEPT { _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(__n <= size(), "remove_suffix() can't remove more than size()"); __size_ -= __n; } diff --git a/libcxx/test/libcxx/containers/sequences/vector/unsafe-buffer-usage.verify.cpp b/libcxx/test/libcxx/containers/sequences/vector/unsafe-buffer-usage.verify.cpp new file mode 100644 index 0000000000000..b4fb7d8dd1185 --- /dev/null +++ b/libcxx/test/libcxx/containers/sequences/vector/unsafe-buffer-usage.verify.cpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: gcc + +// Make sure that std::vector's operations produce unsafe buffer access warnings when +// -Wunsafe-buffer-usage is used, when hardening is disabled. +// +// Note: We disable _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER to ensure that the libc++ +// headers are considered system headers, to validate that users would get +// those diagnostics. +// +// ADDITIONAL_COMPILE_FLAGS: -Wunsafe-buffer-usage -U_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER +// REQUIRES: libcpp-hardening-mode=none + +#include +#include + +void f(std::vector v, std::vector const cv, std::size_t n) { + auto it = v.begin(); + + (void)v[n]; // expected-warning {{function introduces unsafe buffer manipulation}} + (void)cv[n]; // expected-warning {{function introduces unsafe buffer manipulation}} + (void)v.front(); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)cv.front(); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)v.back(); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)cv.back(); // expected-warning {{function introduces unsafe buffer manipulation}} + v.pop_back(); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)v.erase(it); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)v.erase(it, it); // expected-warning {{function introduces unsafe buffer manipulation}} + +#if defined(_LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR) + (void)*it; // nothing + (void)it[n]; // nothing +#else + (void)*it; // expected-warning {{function introduces unsafe buffer manipulation}} + (void)it[n]; // expected-warning {{function introduces unsafe buffer manipulation}} +#endif +} diff --git a/libcxx/test/libcxx/containers/views/views.span/unsafe-buffer-usage.verify.cpp b/libcxx/test/libcxx/containers/views/views.span/unsafe-buffer-usage.verify.cpp new file mode 100644 index 0000000000000..c0735a8098ccd --- /dev/null +++ b/libcxx/test/libcxx/containers/views/views.span/unsafe-buffer-usage.verify.cpp @@ -0,0 +1,68 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14, c++17 +// UNSUPPORTED: gcc + +// Make sure that std::span's operations produce unsafe buffer access warnings when +// -Wunsafe-buffer-usage is used, when hardening is disabled. +// +// Note: We disable _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER to ensure that the libc++ +// headers are considered system headers, to validate that users would get +// those diagnostics. +// +// ADDITIONAL_COMPILE_FLAGS: -Wunsafe-buffer-usage -U_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER +// REQUIRES: libcpp-hardening-mode=none + +#include +#include + +void f1(std::span s, std::size_t n) { + (void)s.first<10>(); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)s.first(n); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)s.last<10>(); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)s.last(n); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)s.subspan<10, 20>(); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)s.subspan<10>(); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)s.subspan(n, n); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)s.subspan(n); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)s[n]; // expected-warning {{function introduces unsafe buffer manipulation}} + (void)s.front(); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)s.back(); // expected-warning {{function introduces unsafe buffer manipulation}} + + auto it = s.begin(); +#ifdef _LIBCPP_ABI_BOUNDED_ITERATORS + (void)*it; // nothing + (void)it[n]; // nothing +#else + (void)*it; // expected-warning {{function introduces unsafe buffer manipulation}} + (void)it[n]; // expected-warning {{function introduces unsafe buffer manipulation}} +#endif +} + +void f2(std::span s, std::size_t n) { + (void)s.first<10>(); // nothing + (void)s.first(n); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)s.last<10>(); // nothing + (void)s.last(n); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)s.subspan<10, 20>(); // nothing + (void)s.subspan(n, n); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)s.subspan(n); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)s[n]; // expected-warning {{function introduces unsafe buffer manipulation}} + (void)s.front(); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)s.back(); // expected-warning {{function introduces unsafe buffer manipulation}} + + auto it = s.begin(); +#ifdef _LIBCPP_ABI_BOUNDED_ITERATORS + (void)*it; // nothing + (void)it[n]; // nothing +#else + (void)*it; // expected-warning {{function introduces unsafe buffer manipulation}} + (void)it[n]; // expected-warning {{function introduces unsafe buffer manipulation}} +#endif +} diff --git a/libcxx/test/libcxx/strings/basic.string/unsafe-buffer-usage.verify.cpp b/libcxx/test/libcxx/strings/basic.string/unsafe-buffer-usage.verify.cpp new file mode 100644 index 0000000000000..f8aa512e9643f --- /dev/null +++ b/libcxx/test/libcxx/strings/basic.string/unsafe-buffer-usage.verify.cpp @@ -0,0 +1,41 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: gcc + +// Make sure that std::string's operations produce unsafe buffer access warnings when +// -Wunsafe-buffer-usage is used, when hardening is disabled. +// +// Note: We disable _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER to ensure that the libc++ +// headers are considered system headers, to validate that users would get +// those diagnostics. +// +// ADDITIONAL_COMPILE_FLAGS: -Wunsafe-buffer-usage -U_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER +// REQUIRES: libcpp-hardening-mode=none + +#include +#include + +void f(std::string s, std::string const cs, std::size_t n) { + (void)s[n]; // expected-warning {{function introduces unsafe buffer manipulation}} + (void)cs[n]; // expected-warning {{function introduces unsafe buffer manipulation}} + (void)s.front(); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)cs.front(); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)s.back(); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)cs.back(); // expected-warning {{function introduces unsafe buffer manipulation}} + s.pop_back(); // expected-warning {{function introduces unsafe buffer manipulation}} + + auto it = s.begin(); +#if defined(_LIBCPP_ABI_BOUNDED_ITERATORS_IN_STRING) + (void)*it; // nothing + (void)it[n]; // nothing +#else + (void)*it; // expected-warning {{function introduces unsafe buffer manipulation}} + (void)it[n]; // expected-warning {{function introduces unsafe buffer manipulation}} +#endif +} diff --git a/libcxx/test/std/strings/string.view/unsafe-buffer-usage.verify.cpp b/libcxx/test/std/strings/string.view/unsafe-buffer-usage.verify.cpp new file mode 100644 index 0000000000000..3d9333c7e219c --- /dev/null +++ b/libcxx/test/std/strings/string.view/unsafe-buffer-usage.verify.cpp @@ -0,0 +1,43 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++03, c++11, c++14 +// UNSUPPORTED: gcc + +// Make sure that std::string_view's operations produce unsafe buffer access warnings when +// -Wunsafe-buffer-usage is used, when hardening is disabled. +// +// Note: We disable _LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER to ensure that the libc++ +// headers are considered system headers, to validate that users would get +// those diagnostics. +// +// ADDITIONAL_COMPILE_FLAGS: -Wunsafe-buffer-usage -U_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER +// REQUIRES: libcpp-hardening-mode=none + +#include +#include + +void f(std::string_view s, std::size_t n) { + (void)s[n]; // expected-warning {{function introduces unsafe buffer manipulation}} + (void)s.front(); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)s.back(); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)s.remove_prefix(n); // expected-warning {{function introduces unsafe buffer manipulation}} + (void)s.remove_suffix(n); // expected-warning {{function introduces unsafe buffer manipulation}} + + auto it = s.begin(); +#if defined(_LIBCPP_ABI_BOUNDED_ITERATORS) + (void)*it; // nothing + (void)it[n]; // nothing +#elif defined(_LIBCPP_ABI_USE_WRAP_ITER_IN_STD_STRING_VIEW) + (void)*it; // expected-warning {{function introduces unsafe buffer manipulation}} + (void)it[n]; // expected-warning {{function introduces unsafe buffer manipulation}} +#else + (void)*it; // TODO: Why does this trigger nothing? + (void)it[n]; // expected-warning {{unsafe buffer access}} +#endif +}