Skip to content
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions libcxx/include/__assert
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,7 @@
// optimization intent. See https://discourse.llvm.org/t/llvm-assume-blocks-optimization/71609 for a
// discussion.
#if __has_builtin(__builtin_assume)
# define _LIBCPP_ASSUME(expression) \
(_LIBCPP_DIAGNOSTIC_PUSH _LIBCPP_CLANG_DIAGNOSTIC_IGNORED("-Wassume") \
__builtin_assume(static_cast<bool>(expression)) _LIBCPP_DIAGNOSTIC_POP)
# define _LIBCPP_ASSUME(expression) __builtin_assume(static_cast<bool>(expression))
#else
# define _LIBCPP_ASSUME(expression) ((void)0)
#endif
Expand Down
16 changes: 16 additions & 0 deletions libcxx/include/__iterator/bounded_iter.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,10 +101,26 @@ struct __bounded_iter {
_LIBCPP_HIDE_FROM_ABI
_LIBCPP_CONSTEXPR_SINCE_CXX14 explicit __bounded_iter(_Iterator __current, _Iterator __begin, _Iterator __end)
: __current_(__current), __begin_(__begin), __end_(__end) {
// These are internal checks rather than hardening checks because the STL container is expected to ensure they are
// in order.
_LIBCPP_ASSERT_INTERNAL(
__begin <= __current, "__bounded_iter(current, begin, end): current and begin are inconsistent");
_LIBCPP_ASSERT_INTERNAL(
__current <= __end, "__bounded_iter(current, begin, end): current and end are inconsistent");

// However, this order is important to help the compiler reason about bounds checks. For example, `std::vector` sets
// `__end_ptr` to the capacity, not the true container end. To translate container-end fenceposts into hardening-end
// fenceposts, we must know that container-end <= hardening-end. `std::__to_address` is needed because `_Iterator`
// may be wrapped type, such that `operator<=` has side effects.
pointer __begin_ptr = std::__to_address(__begin);
pointer __current_ptr = std::__to_address(__current);
pointer __end_ptr = std::__to_address(__end);
_LIBCPP_ASSUME(__begin_ptr <= __current_ptr);
_LIBCPP_ASSUME(__current_ptr <= __end_ptr);
// Silence warnings when assumptions are disabled.
(void)__begin_ptr;
(void)__current_ptr;
(void)__end_ptr;
}

template <class _It>
Expand Down
10 changes: 9 additions & 1 deletion libcxx/include/__vector/vector.h
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,10 @@ class _LIBCPP_TEMPLATE_VIS vector {

_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator __make_iter(pointer __p) _NOEXCEPT {
#ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR
// `__bounded_iter` will tell the compiler that `__p` is bounded by `__begin_` and `__end_cap`, but nothing a priori
// relates `__p` to `__end_`.
_LIBCPP_ASSUME(__p <= this->__end_);

// Bound the iterator according to the capacity, rather than the size.
//
// Vector guarantees that iterators stay valid as long as no reallocation occurs even if new elements are inserted
Expand All @@ -673,7 +677,11 @@ class _LIBCPP_TEMPLATE_VIS vector {

_LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_iterator __make_iter(const_pointer __p) const _NOEXCEPT {
#ifdef _LIBCPP_ABI_BOUNDED_ITERATORS_IN_VECTOR
// Bound the iterator according to the capacity, rather than the size.
// `__bounded_iter` will tell the compiler that `__p` is bounded by `__begin_` and `__end_cap`, but nothing a priori
// relates `__p` to `__end_`.
_LIBCPP_ASSUME(__p <= this->__end_);

// Bound the iterator according to the capacity, rather than the size. See above.
return std::__make_bounded_iter(
std::__wrap_iter<const_pointer>(__p),
std::__wrap_iter<const_pointer>(this->__begin_),
Expand Down
Loading