[libcxx-commits] [libcxx] [libc++][hardening] Check bounds on arithmetic in __bounded_iter (PR #78876)

David Benjamin via libcxx-commits libcxx-commits at lists.llvm.org
Sat Jan 20 22:22:03 PST 2024


https://github.com/davidben updated https://github.com/llvm/llvm-project/pull/78876

>From b4aff9757719ce624a030ebda852cbbd9a4a2771 Mon Sep 17 00:00:00 2001
From: David Benjamin <davidben at google.com>
Date: Sat, 20 Jan 2024 17:32:14 -0500
Subject: [PATCH 1/4] [libc++][hardening] Check bounds on arithmetic in
 __bounded_iter

Previously, __bounded_iter only checked operator*. It allowed the
pointer to go out of bounds with operator++, etc., and relied on
operator* (which checked begin <= current < end) to handle everything.
This has several unfortunate consequences:

First, pointer arithmetic is UB if it goes out of bounds. So by the time
operator* checks, it may be too late and the optimizer may have done
something bad. Checking both operations is safer.

Second, std::copy and friends currently bypass bounded iterator checks.
I think the only hope we have to fix this is to key on iter + n doing a
check. See #78771 for further discussion. Note this PR is not sufficient
to fix this. It adds the output bounds check, but ends up doing it after
the memmove, which is too late.

Finally, doing these checks is actually *more* optimizable. See #78829,
which is fixed by this PR. Keeping the iterator always in bounds means
operator* can rely on some invariants and only needs to check
current != end. This aligns better with the ways that callers tend to
condition iterator operations. At least for the common case of iterating
over the entire

See https://godbolt.org/z/vEWrWEf8h for how this new __bounded_iter
impacts compiler output. The old __bounded_iter injected checks inside
the loops for all the sum() functions, which not only added a check
inside a loop, but also impeded Clang's vectorization. The new
__bounded_iter allows all the checks to be optimized out and we emit the
same code as if it wasn't here.

Not everything is ideal however. add_and_deref ends up emitting two
comparisons now instead of one. This is because a missed optimization in
Clang. I've filed #78875 for that. I suspect (with no data)  that this
PR is still a net performance win because impeding ranged-for loops is
particularly egregious. But ideally we'd fix the optimizer and make
add_and_deref fine too.

There's also something funny going on with std::ranges::find which I
have not yet figured out yet, but I suspect there are some further
missed optimization opportunities.

Fixes #78829.
---
 libcxx/include/__iterator/bounded_iter.h      |  50 +++--
 .../debug.iterator-indexing.pass.cpp          | 168 +++++++++++-----
 .../debug.iterator-indexing.pass.cpp          | 181 ++++++++++++------
 3 files changed, 269 insertions(+), 130 deletions(-)

diff --git a/libcxx/include/__iterator/bounded_iter.h b/libcxx/include/__iterator/bounded_iter.h
index 2a667648871c4c1..3ea20734ac66cba 100644
--- a/libcxx/include/__iterator/bounded_iter.h
+++ b/libcxx/include/__iterator/bounded_iter.h
@@ -31,13 +31,10 @@ _LIBCPP_BEGIN_NAMESPACE_STD
 // Iterator wrapper that carries the valid range it is allowed to access.
 //
 // This is a simple iterator wrapper for contiguous iterators that points
-// within a [begin, end) range and carries these bounds with it. The iterator
-// ensures that it is pointing within that [begin, end) range when it is
-// dereferenced.
-//
-// Arithmetic operations are allowed and the bounds of the resulting iterator
-// are not checked. Hence, it is possible to create an iterator pointing outside
-// its range, but it is not possible to dereference it.
+// within a [begin, end] range and carries these bounds with it. The iterator
+// ensures that it is pointing within [begin, end) range when it is
+// dereferenced. It also ensures that it is never iterated outside of
+// [begin, end].
 template <class _Iterator, class = __enable_if_t< __libcpp_is_contiguous_iterator<_Iterator>::value > >
 struct __bounded_iter {
   using value_type        = typename iterator_traits<_Iterator>::value_type;
@@ -70,18 +67,18 @@ struct __bounded_iter {
 
 private:
   // Create an iterator wrapping the given iterator, and whose bounds are described
-  // by the provided [begin, end) range.
+  // by the provided [begin, end] range.
   //
-  // This constructor does not check whether the resulting iterator is within its bounds.
-  // However, it does check that the provided [begin, end) range is a valid range (that
-  // is, begin <= end).
+  // Except in debug builds, the constructor does not check whether the resulting iterator
+  // is within its bounds. The container is assumed to be self-consistent.
   //
   // Since it is non-standard for iterators to have this constructor, __bounded_iter must
   // be created via `std::__make_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) {
-    _LIBCPP_ASSERT_INTERNAL(__begin <= __end, "__bounded_iter(current, begin, end): [begin, end) is not a valid range");
+    _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");
   }
 
   template <class _It>
@@ -91,21 +88,25 @@ struct __bounded_iter {
   // Dereference and indexing operations.
   //
   // These operations check that the iterator is dereferenceable, that is within [begin, end).
+  // The iterator is always within [begin, end], so we only need to check for end. This is
+  // easier to optimize out. See https://github.com/llvm/llvm-project/issues/78829
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference operator*() const _NOEXCEPT {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
-        __in_bounds(__current_), "__bounded_iter::operator*: Attempt to dereference an out-of-range iterator");
+        __current_ != __end_, "__bounded_iter::operator*: Attempt to dereference an iterator at the end");
     return *__current_;
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pointer operator->() const _NOEXCEPT {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
-        __in_bounds(__current_), "__bounded_iter::operator->: Attempt to dereference an out-of-range iterator");
+        __current_ != __end_, "__bounded_iter::operator->: Attempt to dereference an iterator at the end");
     return std::__to_address(__current_);
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 reference operator[](difference_type __n) const _NOEXCEPT {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
-        __in_bounds(__current_ + __n), "__bounded_iter::operator[]: Attempt to index an iterator out-of-range");
+        __n >= __begin_ - __current_, "__bounded_iter::operator[]: Attempt to index an iterator past the start");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+        __n < __end_ - __current_, "__bounded_iter::operator[]: Attempt to index an iterator past the end");
     return __current_[__n];
   }
 
@@ -114,6 +115,8 @@ struct __bounded_iter {
   // These operations do not check that the resulting iterator is within the bounds, since that
   // would make it impossible to create a past-the-end iterator.
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __bounded_iter& operator++() _NOEXCEPT {
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+        __current_ != __end_, "__bounded_iter::operator++: Attempt to advance an iterator past the end");
     ++__current_;
     return *this;
   }
@@ -124,6 +127,8 @@ struct __bounded_iter {
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __bounded_iter& operator--() _NOEXCEPT {
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+        __current_ != __begin_, "__bounded_iter::operator--: Attempt to rewind an iterator past the start");
     --__current_;
     return *this;
   }
@@ -134,6 +139,10 @@ struct __bounded_iter {
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __bounded_iter& operator+=(difference_type __n) _NOEXCEPT {
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+        __n >= __begin_ - __current_, "__bounded_iter::operator+=: Attempt to rewind an iterator past the start");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+        __n <= __end_ - __current_, "__bounded_iter::operator+=: Attempt to advance an iterator past the end");
     __current_ += __n;
     return *this;
   }
@@ -151,6 +160,10 @@ struct __bounded_iter {
   }
 
   _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 __bounded_iter& operator-=(difference_type __n) _NOEXCEPT {
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+        __n <= __current_ - __begin_, "__bounded_iter::operator-=: Attempt to rewind an iterator past the start");
+    _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
+        __n >= __current_ - __end_, "__bounded_iter::operator-=: Attempt to advance an iterator past the end");
     __current_ -= __n;
     return *this;
   }
@@ -197,15 +210,10 @@ struct __bounded_iter {
   }
 
 private:
-  // Return whether the given iterator is in the bounds of this __bounded_iter.
-  _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR bool __in_bounds(_Iterator const& __iter) const {
-    return __iter >= __begin_ && __iter < __end_;
-  }
-
   template <class>
   friend struct pointer_traits;
   _Iterator __current_;       // current iterator
-  _Iterator __begin_, __end_; // valid range represented as [begin, end)
+  _Iterator __begin_, __end_; // valid range represented as [begin, end]
 };
 
 template <class _It>
diff --git a/libcxx/test/libcxx/containers/views/views.span/debug.iterator-indexing.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/debug.iterator-indexing.pass.cpp
index 360e7a981a0dfe9..4a77da56e95e799 100644
--- a/libcxx/test/libcxx/containers/views/views.span/debug.iterator-indexing.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/views.span/debug.iterator-indexing.pass.cpp
@@ -20,77 +20,149 @@ struct Foo {
     int x;
 };
 
+template <typename Iter>
+void test_iterator(Iter begin, Iter end, bool reverse) {
+  ptrdiff_t distance = std::distance(begin, end);
+
+  // Dereferencing an iterator at the end.
+  {
+    TEST_LIBCPP_ASSERT_FAILURE(
+        *end,
+        reverse ? "__bounded_iter::operator--: Attempt to rewind an iterator past the start"
+                : "__bounded_iter::operator*: Attempt to dereference an iterator at the end");
+#if _LIBCPP_STD_VER >= 20
+    // In C++20 mode, std::reverse_iterator implements operator->, but not operator*, with
+    // std::prev instead of operator--. std::prev ultimately calls operator+
+    TEST_LIBCPP_ASSERT_FAILURE(
+        end->x,
+        reverse ? "__bounded_iter::operator+=: Attempt to rewind an iterator past the start"
+                : "__bounded_iter::operator->: Attempt to dereference an iterator at the end");
+#else
+    TEST_LIBCPP_ASSERT_FAILURE(
+        end->x,
+        reverse ? "__bounded_iter::operator--: Attempt to rewind an iterator past the start"
+                : "__bounded_iter::operator->: Attempt to dereference an iterator at the end");
+#endif
+  }
+
+  // Incrementing an iterator past the end.
+  {
+    const char* msg = reverse ? "__bounded_iter::operator--: Attempt to rewind an iterator past the start"
+                              : "__bounded_iter::operator++: Attempt to advance an iterator past the end";
+    auto it         = end;
+    TEST_LIBCPP_ASSERT_FAILURE(it++, msg);
+    it = end;
+    TEST_LIBCPP_ASSERT_FAILURE(++it, msg);
+  }
+
+  // Decrementing an iterator past the start.
+  {
+    const char* msg = reverse ? "__bounded_iter::operator++: Attempt to advance an iterator past the end"
+                              : "__bounded_iter::operator--: Attempt to rewind an iterator past the start";
+    auto it         = begin;
+    TEST_LIBCPP_ASSERT_FAILURE(it--, msg);
+    it = begin;
+    TEST_LIBCPP_ASSERT_FAILURE(--it, msg);
+  }
+
+  // Advancing past the end with operator+= and operator+.
+  {
+    const char* msg = reverse ? "__bounded_iter::operator-=: Attempt to rewind an iterator past the start"
+                              : "__bounded_iter::operator+=: Attempt to advance an iterator past the end";
+    auto it         = end;
+    TEST_LIBCPP_ASSERT_FAILURE(it += 1, msg);
+    TEST_LIBCPP_ASSERT_FAILURE(end + 1, msg);
+    it = begin;
+    TEST_LIBCPP_ASSERT_FAILURE(it += (distance + 1), msg);
+    TEST_LIBCPP_ASSERT_FAILURE(begin + (distance + 1), msg);
+  }
+
+  // Advancing past the end with operator-= and operator-.
+  {
+    const char* msg = reverse ? "__bounded_iter::operator+=: Attempt to rewind an iterator past the start"
+                              : "__bounded_iter::operator-=: Attempt to advance an iterator past the end";
+    auto it         = end;
+    TEST_LIBCPP_ASSERT_FAILURE(it -= (-1), msg);
+    TEST_LIBCPP_ASSERT_FAILURE(end - (-1), msg);
+    it = begin;
+    TEST_LIBCPP_ASSERT_FAILURE(it -= (-distance - 1), msg);
+    TEST_LIBCPP_ASSERT_FAILURE(begin - (-distance - 1), msg);
+  }
+
+  // Rewinding past the start with operator+= and operator+.
+  {
+    const char* msg = reverse ? "__bounded_iter::operator-=: Attempt to advance an iterator past the end"
+                              : "__bounded_iter::operator+=: Attempt to rewind an iterator past the start";
+    auto it         = begin;
+    TEST_LIBCPP_ASSERT_FAILURE(it += (-1), msg);
+    TEST_LIBCPP_ASSERT_FAILURE(begin + (-1), msg);
+    it = end;
+    TEST_LIBCPP_ASSERT_FAILURE(it += (-distance - 1), msg);
+    TEST_LIBCPP_ASSERT_FAILURE(end + (-distance - 1), msg);
+  }
+
+  // Rewinding past the start with operator-= and operator-.
+  {
+    const char* msg = reverse ? "__bounded_iter::operator+=: Attempt to advance an iterator past the end"
+                              : "__bounded_iter::operator-=: Attempt to rewind an iterator past the start";
+    auto it         = begin;
+    TEST_LIBCPP_ASSERT_FAILURE(it -= 1, msg);
+    TEST_LIBCPP_ASSERT_FAILURE(begin - 1, msg);
+    it = end;
+    TEST_LIBCPP_ASSERT_FAILURE(it -= (distance + 1), msg);
+    TEST_LIBCPP_ASSERT_FAILURE(end - (distance + 1), msg);
+  }
+
+  // Out-of-bounds operator[].
+  {
+    const char* end_msg = reverse ? "__bounded_iter::operator--: Attempt to rewind an iterator past the start"
+                                  : "__bounded_iter::operator[]: Attempt to index an iterator past the end";
+    const char* past_end_msg =
+        reverse ? "__bounded_iter::operator-=: Attempt to rewind an iterator past the start"
+                : "__bounded_iter::operator[]: Attempt to index an iterator past the end";
+    const char* past_start_msg =
+        reverse ? "__bounded_iter::operator-=: Attempt to advance an iterator past the end"
+                : "__bounded_iter::operator[]: Attempt to index an iterator past the start";
+    TEST_LIBCPP_ASSERT_FAILURE(begin[distance], end_msg);
+    TEST_LIBCPP_ASSERT_FAILURE(begin[distance + 1], past_end_msg);
+    TEST_LIBCPP_ASSERT_FAILURE(begin[-1], past_start_msg);
+    TEST_LIBCPP_ASSERT_FAILURE(begin[-99], past_start_msg);
+
+    auto it = begin + 1;
+    TEST_LIBCPP_ASSERT_FAILURE(it[distance - 1], end_msg);
+    TEST_LIBCPP_ASSERT_FAILURE(it[distance], past_end_msg);
+    TEST_LIBCPP_ASSERT_FAILURE(it[-2], past_start_msg);
+    TEST_LIBCPP_ASSERT_FAILURE(it[-99], past_start_msg);
+  }
+}
+
 int main(int, char**) {
     // span<T>::iterator
     {
         Foo array[] = {{0}, {1}, {2}};
         std::span<Foo> const span(array, 3);
-        {
-            auto it = span.end();
-            TEST_LIBCPP_ASSERT_FAILURE(*it, "__bounded_iter::operator*: Attempt to dereference an out-of-range iterator");
-        }
-        {
-            auto it = span.end();
-            TEST_LIBCPP_ASSERT_FAILURE(it->x, "__bounded_iter::operator->: Attempt to dereference an out-of-range iterator");
-        }
-        {
-            auto it = span.begin();
-            TEST_LIBCPP_ASSERT_FAILURE(it[3], "__bounded_iter::operator[]: Attempt to index an iterator out-of-range");
-        }
+        test_iterator(span.begin(), span.end(), /*reverse=*/false);
     }
 
     // span<T, N>::iterator
     {
         Foo array[] = {{0}, {1}, {2}};
         std::span<Foo, 3> const span(array, 3);
-        {
-            auto it = span.end();
-            TEST_LIBCPP_ASSERT_FAILURE(*it, "__bounded_iter::operator*: Attempt to dereference an out-of-range iterator");
-        }
-        {
-            auto it = span.end();
-            TEST_LIBCPP_ASSERT_FAILURE(it->x, "__bounded_iter::operator->: Attempt to dereference an out-of-range iterator");
-        }
-        {
-            auto it = span.begin();
-            TEST_LIBCPP_ASSERT_FAILURE(it[3], "__bounded_iter::operator[]: Attempt to index an iterator out-of-range");
-        }
+        test_iterator(span.begin(), span.end(), /*reverse=*/false);
     }
 
     // span<T>::reverse_iterator
     {
         Foo array[] = {{0}, {1}, {2}};
         std::span<Foo> const span(array, 3);
-        {
-            auto it = span.rend();
-            TEST_LIBCPP_ASSERT_FAILURE(*it, "__bounded_iter::operator*: Attempt to dereference an out-of-range iterator");
-        }
-        {
-            auto it = span.rend();
-            TEST_LIBCPP_ASSERT_FAILURE(it->x, "__bounded_iter::operator->: Attempt to dereference an out-of-range iterator");
-        }
-        {
-            auto it = span.rbegin();
-            TEST_LIBCPP_ASSERT_FAILURE(it[3], "__bounded_iter::operator*: Attempt to dereference an out-of-range iterator");
-        }
+        test_iterator(span.rbegin(), span.rend(), /*reverse=*/true);
     }
 
     // span<T, N>::reverse_iterator
     {
         Foo array[] = {{0}, {1}, {2}};
         std::span<Foo, 3> const span(array, 3);
-        {
-            auto it = span.rend();
-            TEST_LIBCPP_ASSERT_FAILURE(*it, "__bounded_iter::operator*: Attempt to dereference an out-of-range iterator");
-        }
-        {
-            auto it = span.rend();
-            TEST_LIBCPP_ASSERT_FAILURE(it->x, "__bounded_iter::operator->: Attempt to dereference an out-of-range iterator");
-        }
-        {
-            auto it = span.rbegin();
-            TEST_LIBCPP_ASSERT_FAILURE(it[3], "__bounded_iter::operator*: Attempt to dereference an out-of-range iterator");
-        }
+        test_iterator(span.rbegin(), span.rend(), /*reverse=*/true);
     }
 
     return 0;
diff --git a/libcxx/test/libcxx/strings/string.view/string.view.iterators/debug.iterator-indexing.pass.cpp b/libcxx/test/libcxx/strings/string.view/string.view.iterators/debug.iterator-indexing.pass.cpp
index 5064319a0aee1b2..aa466d0b247cd35 100644
--- a/libcxx/test/libcxx/strings/string.view/string.view.iterators/debug.iterator-indexing.pass.cpp
+++ b/libcxx/test/libcxx/strings/string.view/string.view.iterators/debug.iterator-indexing.pass.cpp
@@ -11,82 +11,141 @@
 // REQUIRES: has-unix-headers, libcpp-has-abi-bounded-iterators
 // UNSUPPORTED: libcpp-hardening-mode=none
 
+#include <iterator>
 #include <string_view>
 
 #include "check_assertion.h"
 
-int main(int, char**) {
-  // string_view::iterator
+template <typename Iter>
+void test_iterator(Iter begin, Iter end, bool reverse) {
+  ptrdiff_t distance = std::distance(begin, end);
+
+  // Dereferencing an iterator at the end.
   {
-    std::string_view const str("hello world");
-    {
-      auto it = str.end();
-      TEST_LIBCPP_ASSERT_FAILURE(*it, "__bounded_iter::operator*: Attempt to dereference an out-of-range iterator");
-    }
-    {
-      auto it = str.end();
-      TEST_LIBCPP_ASSERT_FAILURE(
-          it.operator->(), "__bounded_iter::operator->: Attempt to dereference an out-of-range iterator");
-    }
-    {
-      auto it = str.begin();
-      TEST_LIBCPP_ASSERT_FAILURE(it[99], "__bounded_iter::operator[]: Attempt to index an iterator out-of-range");
-    }
+    TEST_LIBCPP_ASSERT_FAILURE(
+        *end,
+        reverse ? "__bounded_iter::operator--: Attempt to rewind an iterator past the start"
+                : "__bounded_iter::operator*: Attempt to dereference an iterator at the end");
+#if _LIBCPP_STD_VER >= 20
+    // In C++20 mode, std::reverse_iterator implements operator->, but not operator*, with
+    // std::prev instead of operator--. std::prev ultimately calls operator+
+    TEST_LIBCPP_ASSERT_FAILURE(
+        end.operator->(),
+        reverse ? "__bounded_iter::operator+=: Attempt to rewind an iterator past the start"
+                : "__bounded_iter::operator->: Attempt to dereference an iterator at the end");
+#else
+    TEST_LIBCPP_ASSERT_FAILURE(
+        end.operator->(),
+        reverse ? "__bounded_iter::operator--: Attempt to rewind an iterator past the start"
+                : "__bounded_iter::operator->: Attempt to dereference an iterator at the end");
+#endif
   }
 
-  // string_view::const_iterator
+  // Incrementing an iterator past the end.
   {
-    std::string_view const str("hello world");
-    {
-      auto it = str.cend();
-      TEST_LIBCPP_ASSERT_FAILURE(*it, "__bounded_iter::operator*: Attempt to dereference an out-of-range iterator");
-    }
-    {
-      auto it = str.cend();
-      TEST_LIBCPP_ASSERT_FAILURE(
-          it.operator->(), "__bounded_iter::operator->: Attempt to dereference an out-of-range iterator");
-    }
-    {
-      auto it = str.cbegin();
-      TEST_LIBCPP_ASSERT_FAILURE(it[99], "__bounded_iter::operator[]: Attempt to index an iterator out-of-range");
-    }
+    const char* msg = reverse ? "__bounded_iter::operator--: Attempt to rewind an iterator past the start"
+                              : "__bounded_iter::operator++: Attempt to advance an iterator past the end";
+    auto it         = end;
+    TEST_LIBCPP_ASSERT_FAILURE(it++, msg);
+    it = end;
+    TEST_LIBCPP_ASSERT_FAILURE(++it, msg);
   }
 
-  // string_view::reverse_iterator
+  // Decrementing an iterator past the start.
   {
-    std::string_view const str("hello world");
-    {
-      auto it = str.rend();
-      TEST_LIBCPP_ASSERT_FAILURE(*it, "__bounded_iter::operator*: Attempt to dereference an out-of-range iterator");
-    }
-    {
-      auto it = str.rend();
-      TEST_LIBCPP_ASSERT_FAILURE(
-          it.operator->(), "__bounded_iter::operator->: Attempt to dereference an out-of-range iterator");
-    }
-    {
-      auto it = str.rbegin();
-      TEST_LIBCPP_ASSERT_FAILURE(it[99], "__bounded_iter::operator*: Attempt to dereference an out-of-range iterator");
-    }
+    const char* msg = reverse ? "__bounded_iter::operator++: Attempt to advance an iterator past the end"
+                              : "__bounded_iter::operator--: Attempt to rewind an iterator past the start";
+    auto it         = begin;
+    TEST_LIBCPP_ASSERT_FAILURE(it--, msg);
+    it = begin;
+    TEST_LIBCPP_ASSERT_FAILURE(--it, msg);
   }
 
-  // string_view::const_reverse_iterator
+  // Advancing past the end with operator+= and operator+.
+  {
+    const char* msg = reverse ? "__bounded_iter::operator-=: Attempt to rewind an iterator past the start"
+                              : "__bounded_iter::operator+=: Attempt to advance an iterator past the end";
+    auto it         = end;
+    TEST_LIBCPP_ASSERT_FAILURE(it += 1, msg);
+    TEST_LIBCPP_ASSERT_FAILURE(end + 1, msg);
+    it = begin;
+    TEST_LIBCPP_ASSERT_FAILURE(it += (distance + 1), msg);
+    TEST_LIBCPP_ASSERT_FAILURE(begin + (distance + 1), msg);
+  }
+
+  // Advancing past the end with operator-= and operator-.
+  {
+    const char* msg = reverse ? "__bounded_iter::operator+=: Attempt to rewind an iterator past the start"
+                              : "__bounded_iter::operator-=: Attempt to advance an iterator past the end";
+    auto it         = end;
+    TEST_LIBCPP_ASSERT_FAILURE(it -= (-1), msg);
+    TEST_LIBCPP_ASSERT_FAILURE(end - (-1), msg);
+    it = begin;
+    TEST_LIBCPP_ASSERT_FAILURE(it -= (-distance - 1), msg);
+    TEST_LIBCPP_ASSERT_FAILURE(begin - (-distance - 1), msg);
+  }
+
+  // Rewinding past the start with operator+= and operator+.
+  {
+    const char* msg = reverse ? "__bounded_iter::operator-=: Attempt to advance an iterator past the end"
+                              : "__bounded_iter::operator+=: Attempt to rewind an iterator past the start";
+    auto it         = begin;
+    TEST_LIBCPP_ASSERT_FAILURE(it += (-1), msg);
+    TEST_LIBCPP_ASSERT_FAILURE(begin + (-1), msg);
+    it = end;
+    TEST_LIBCPP_ASSERT_FAILURE(it += (-distance - 1), msg);
+    TEST_LIBCPP_ASSERT_FAILURE(end + (-distance - 1), msg);
+  }
+
+  // Rewinding past the start with operator-= and operator-.
   {
-    std::string_view const str("hello world");
-    {
-      auto it = str.crend();
-      TEST_LIBCPP_ASSERT_FAILURE(*it, "__bounded_iter::operator*: Attempt to dereference an out-of-range iterator");
-    }
-    {
-      auto it = str.crend();
-      TEST_LIBCPP_ASSERT_FAILURE(
-          it.operator->(), "__bounded_iter::operator->: Attempt to dereference an out-of-range iterator");
-    }
-    {
-      auto it = str.crbegin();
-      TEST_LIBCPP_ASSERT_FAILURE(it[99], "__bounded_iter::operator*: Attempt to dereference an out-of-range iterator");
-    }
+    const char* msg = reverse ? "__bounded_iter::operator+=: Attempt to advance an iterator past the end"
+                              : "__bounded_iter::operator-=: Attempt to rewind an iterator past the start";
+    auto it         = begin;
+    TEST_LIBCPP_ASSERT_FAILURE(it -= 1, msg);
+    TEST_LIBCPP_ASSERT_FAILURE(begin - 1, msg);
+    it = end;
+    TEST_LIBCPP_ASSERT_FAILURE(it -= (distance + 1), msg);
+    TEST_LIBCPP_ASSERT_FAILURE(end - (distance + 1), msg);
   }
 
+  // Out-of-bounds operator[].
+  {
+    const char* end_msg = reverse ? "__bounded_iter::operator--: Attempt to rewind an iterator past the start"
+                                  : "__bounded_iter::operator[]: Attempt to index an iterator past the end";
+    const char* past_end_msg =
+        reverse ? "__bounded_iter::operator-=: Attempt to rewind an iterator past the start"
+                : "__bounded_iter::operator[]: Attempt to index an iterator past the end";
+    const char* past_start_msg =
+        reverse ? "__bounded_iter::operator-=: Attempt to advance an iterator past the end"
+                : "__bounded_iter::operator[]: Attempt to index an iterator past the start";
+    TEST_LIBCPP_ASSERT_FAILURE(begin[distance], end_msg);
+    TEST_LIBCPP_ASSERT_FAILURE(begin[distance + 1], past_end_msg);
+    TEST_LIBCPP_ASSERT_FAILURE(begin[-1], past_start_msg);
+    TEST_LIBCPP_ASSERT_FAILURE(begin[-99], past_start_msg);
+
+    auto it = begin + 1;
+    TEST_LIBCPP_ASSERT_FAILURE(it[distance - 1], end_msg);
+    TEST_LIBCPP_ASSERT_FAILURE(it[distance], past_end_msg);
+    TEST_LIBCPP_ASSERT_FAILURE(it[-2], past_start_msg);
+    TEST_LIBCPP_ASSERT_FAILURE(it[-99], past_start_msg);
+  }
+}
+
+int main(int, char**) {
+  std::string_view const str("hello world");
+
+  // string_view::iterator
+  test_iterator(str.begin(), str.end(), /*reverse=*/false);
+
+  // string_view::const_iterator
+  test_iterator(str.cbegin(), str.cend(), /*reverse=*/false);
+
+  // string_view::reverse_iterator
+  test_iterator(str.rbegin(), str.rend(), /*reverse=*/true);
+
+  // string_view::const_reverse_iterator
+  test_iterator(str.crbegin(), str.crend(), /*reverse=*/true);
+
   return 0;
 }

>From 063bbf1432a1e2329d8e6138677e814c03635fe9 Mon Sep 17 00:00:00 2001
From: David Benjamin <davidben at google.com>
Date: Sat, 20 Jan 2024 23:38:38 -0500
Subject: [PATCH 2/4] Fix formatting

---
 libcxx/include/__iterator/bounded_iter.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/libcxx/include/__iterator/bounded_iter.h b/libcxx/include/__iterator/bounded_iter.h
index 3ea20734ac66cba..48f40ce778c252e 100644
--- a/libcxx/include/__iterator/bounded_iter.h
+++ b/libcxx/include/__iterator/bounded_iter.h
@@ -77,8 +77,10 @@ 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) {
-    _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");
+    _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");
   }
 
   template <class _It>

>From 09313ee8a767ce57ab12463ce98b3580ced61b53 Mon Sep 17 00:00:00 2001
From: David Benjamin <davidben at google.com>
Date: Sun, 21 Jan 2024 01:18:01 -0500
Subject: [PATCH 3/4] Add [[maybe_unused]] on error messages

They may be unused in __builtin_trap() builds.
---
 .../debug.iterator-indexing.pass.cpp          | 39 ++++++++-------
 .../debug.iterator-indexing.pass.cpp          | 47 +++++++++++--------
 2 files changed, 50 insertions(+), 36 deletions(-)

diff --git a/libcxx/test/libcxx/containers/views/views.span/debug.iterator-indexing.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/debug.iterator-indexing.pass.cpp
index 4a77da56e95e799..e196d4b2998ce46 100644
--- a/libcxx/test/libcxx/containers/views/views.span/debug.iterator-indexing.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/views.span/debug.iterator-indexing.pass.cpp
@@ -47,8 +47,9 @@ void test_iterator(Iter begin, Iter end, bool reverse) {
 
   // Incrementing an iterator past the end.
   {
-    const char* msg = reverse ? "__bounded_iter::operator--: Attempt to rewind an iterator past the start"
-                              : "__bounded_iter::operator++: Attempt to advance an iterator past the end";
+    [[maybe_unused]] const char* msg =
+        reverse ? "__bounded_iter::operator--: Attempt to rewind an iterator past the start"
+                : "__bounded_iter::operator++: Attempt to advance an iterator past the end";
     auto it         = end;
     TEST_LIBCPP_ASSERT_FAILURE(it++, msg);
     it = end;
@@ -57,8 +58,9 @@ void test_iterator(Iter begin, Iter end, bool reverse) {
 
   // Decrementing an iterator past the start.
   {
-    const char* msg = reverse ? "__bounded_iter::operator++: Attempt to advance an iterator past the end"
-                              : "__bounded_iter::operator--: Attempt to rewind an iterator past the start";
+    [[maybe_unused]] const char* msg =
+        reverse ? "__bounded_iter::operator++: Attempt to advance an iterator past the end"
+                : "__bounded_iter::operator--: Attempt to rewind an iterator past the start";
     auto it         = begin;
     TEST_LIBCPP_ASSERT_FAILURE(it--, msg);
     it = begin;
@@ -67,8 +69,9 @@ void test_iterator(Iter begin, Iter end, bool reverse) {
 
   // Advancing past the end with operator+= and operator+.
   {
-    const char* msg = reverse ? "__bounded_iter::operator-=: Attempt to rewind an iterator past the start"
-                              : "__bounded_iter::operator+=: Attempt to advance an iterator past the end";
+    [[maybe_unused]] const char* msg =
+        reverse ? "__bounded_iter::operator-=: Attempt to rewind an iterator past the start"
+                : "__bounded_iter::operator+=: Attempt to advance an iterator past the end";
     auto it         = end;
     TEST_LIBCPP_ASSERT_FAILURE(it += 1, msg);
     TEST_LIBCPP_ASSERT_FAILURE(end + 1, msg);
@@ -79,8 +82,9 @@ void test_iterator(Iter begin, Iter end, bool reverse) {
 
   // Advancing past the end with operator-= and operator-.
   {
-    const char* msg = reverse ? "__bounded_iter::operator+=: Attempt to rewind an iterator past the start"
-                              : "__bounded_iter::operator-=: Attempt to advance an iterator past the end";
+    [[maybe_unused]] const char* msg =
+        reverse ? "__bounded_iter::operator+=: Attempt to rewind an iterator past the start"
+                : "__bounded_iter::operator-=: Attempt to advance an iterator past the end";
     auto it         = end;
     TEST_LIBCPP_ASSERT_FAILURE(it -= (-1), msg);
     TEST_LIBCPP_ASSERT_FAILURE(end - (-1), msg);
@@ -91,8 +95,9 @@ void test_iterator(Iter begin, Iter end, bool reverse) {
 
   // Rewinding past the start with operator+= and operator+.
   {
-    const char* msg = reverse ? "__bounded_iter::operator-=: Attempt to advance an iterator past the end"
-                              : "__bounded_iter::operator+=: Attempt to rewind an iterator past the start";
+    [[maybe_unused]] const char* msg =
+        reverse ? "__bounded_iter::operator-=: Attempt to advance an iterator past the end"
+                : "__bounded_iter::operator+=: Attempt to rewind an iterator past the start";
     auto it         = begin;
     TEST_LIBCPP_ASSERT_FAILURE(it += (-1), msg);
     TEST_LIBCPP_ASSERT_FAILURE(begin + (-1), msg);
@@ -103,8 +108,9 @@ void test_iterator(Iter begin, Iter end, bool reverse) {
 
   // Rewinding past the start with operator-= and operator-.
   {
-    const char* msg = reverse ? "__bounded_iter::operator+=: Attempt to advance an iterator past the end"
-                              : "__bounded_iter::operator-=: Attempt to rewind an iterator past the start";
+    [[maybe_unused]] const char* msg =
+        reverse ? "__bounded_iter::operator+=: Attempt to advance an iterator past the end"
+                : "__bounded_iter::operator-=: Attempt to rewind an iterator past the start";
     auto it         = begin;
     TEST_LIBCPP_ASSERT_FAILURE(it -= 1, msg);
     TEST_LIBCPP_ASSERT_FAILURE(begin - 1, msg);
@@ -115,12 +121,13 @@ void test_iterator(Iter begin, Iter end, bool reverse) {
 
   // Out-of-bounds operator[].
   {
-    const char* end_msg = reverse ? "__bounded_iter::operator--: Attempt to rewind an iterator past the start"
-                                  : "__bounded_iter::operator[]: Attempt to index an iterator past the end";
-    const char* past_end_msg =
+    [[maybe_unused]] const char* end_msg =
+        reverse ? "__bounded_iter::operator--: Attempt to rewind an iterator past the start"
+                : "__bounded_iter::operator[]: Attempt to index an iterator past the end";
+    [[maybe_unused]] const char* past_end_msg =
         reverse ? "__bounded_iter::operator-=: Attempt to rewind an iterator past the start"
                 : "__bounded_iter::operator[]: Attempt to index an iterator past the end";
-    const char* past_start_msg =
+    [[maybe_unused]] const char* past_start_msg =
         reverse ? "__bounded_iter::operator-=: Attempt to advance an iterator past the end"
                 : "__bounded_iter::operator[]: Attempt to index an iterator past the start";
     TEST_LIBCPP_ASSERT_FAILURE(begin[distance], end_msg);
diff --git a/libcxx/test/libcxx/strings/string.view/string.view.iterators/debug.iterator-indexing.pass.cpp b/libcxx/test/libcxx/strings/string.view/string.view.iterators/debug.iterator-indexing.pass.cpp
index aa466d0b247cd35..ee67cbba0f4d95e 100644
--- a/libcxx/test/libcxx/strings/string.view/string.view.iterators/debug.iterator-indexing.pass.cpp
+++ b/libcxx/test/libcxx/strings/string.view/string.view.iterators/debug.iterator-indexing.pass.cpp
@@ -43,8 +43,9 @@ void test_iterator(Iter begin, Iter end, bool reverse) {
 
   // Incrementing an iterator past the end.
   {
-    const char* msg = reverse ? "__bounded_iter::operator--: Attempt to rewind an iterator past the start"
-                              : "__bounded_iter::operator++: Attempt to advance an iterator past the end";
+    [[maybe_unused]] const char* msg =
+        reverse ? "__bounded_iter::operator--: Attempt to rewind an iterator past the start"
+                : "__bounded_iter::operator++: Attempt to advance an iterator past the end";
     auto it         = end;
     TEST_LIBCPP_ASSERT_FAILURE(it++, msg);
     it = end;
@@ -53,8 +54,9 @@ void test_iterator(Iter begin, Iter end, bool reverse) {
 
   // Decrementing an iterator past the start.
   {
-    const char* msg = reverse ? "__bounded_iter::operator++: Attempt to advance an iterator past the end"
-                              : "__bounded_iter::operator--: Attempt to rewind an iterator past the start";
+    [[maybe_unused]] const char* msg =
+        reverse ? "__bounded_iter::operator++: Attempt to advance an iterator past the end"
+                : "__bounded_iter::operator--: Attempt to rewind an iterator past the start";
     auto it         = begin;
     TEST_LIBCPP_ASSERT_FAILURE(it--, msg);
     it = begin;
@@ -63,9 +65,10 @@ void test_iterator(Iter begin, Iter end, bool reverse) {
 
   // Advancing past the end with operator+= and operator+.
   {
-    const char* msg = reverse ? "__bounded_iter::operator-=: Attempt to rewind an iterator past the start"
-                              : "__bounded_iter::operator+=: Attempt to advance an iterator past the end";
-    auto it         = end;
+    [[maybe_unused]] const char* msg =
+        reverse ? "__bounded_iter::operator-=: Attempt to rewind an iterator past the start"
+                : "__bounded_iter::operator+=: Attempt to advance an iterator past the end";
+    auto it = end;
     TEST_LIBCPP_ASSERT_FAILURE(it += 1, msg);
     TEST_LIBCPP_ASSERT_FAILURE(end + 1, msg);
     it = begin;
@@ -75,9 +78,10 @@ void test_iterator(Iter begin, Iter end, bool reverse) {
 
   // Advancing past the end with operator-= and operator-.
   {
-    const char* msg = reverse ? "__bounded_iter::operator+=: Attempt to rewind an iterator past the start"
-                              : "__bounded_iter::operator-=: Attempt to advance an iterator past the end";
-    auto it         = end;
+    [[maybe_unused]] const char* msg =
+        reverse ? "__bounded_iter::operator+=: Attempt to rewind an iterator past the start"
+                : "__bounded_iter::operator-=: Attempt to advance an iterator past the end";
+    auto it = end;
     TEST_LIBCPP_ASSERT_FAILURE(it -= (-1), msg);
     TEST_LIBCPP_ASSERT_FAILURE(end - (-1), msg);
     it = begin;
@@ -87,9 +91,10 @@ void test_iterator(Iter begin, Iter end, bool reverse) {
 
   // Rewinding past the start with operator+= and operator+.
   {
-    const char* msg = reverse ? "__bounded_iter::operator-=: Attempt to advance an iterator past the end"
-                              : "__bounded_iter::operator+=: Attempt to rewind an iterator past the start";
-    auto it         = begin;
+    [[maybe_unused]] const char* msg =
+        reverse ? "__bounded_iter::operator-=: Attempt to advance an iterator past the end"
+                : "__bounded_iter::operator+=: Attempt to rewind an iterator past the start";
+    auto it = begin;
     TEST_LIBCPP_ASSERT_FAILURE(it += (-1), msg);
     TEST_LIBCPP_ASSERT_FAILURE(begin + (-1), msg);
     it = end;
@@ -99,9 +104,10 @@ void test_iterator(Iter begin, Iter end, bool reverse) {
 
   // Rewinding past the start with operator-= and operator-.
   {
-    const char* msg = reverse ? "__bounded_iter::operator+=: Attempt to advance an iterator past the end"
-                              : "__bounded_iter::operator-=: Attempt to rewind an iterator past the start";
-    auto it         = begin;
+    [[maybe_unused]] const char* msg =
+        reverse ? "__bounded_iter::operator+=: Attempt to advance an iterator past the end"
+                : "__bounded_iter::operator-=: Attempt to rewind an iterator past the start";
+    auto it = begin;
     TEST_LIBCPP_ASSERT_FAILURE(it -= 1, msg);
     TEST_LIBCPP_ASSERT_FAILURE(begin - 1, msg);
     it = end;
@@ -111,12 +117,13 @@ void test_iterator(Iter begin, Iter end, bool reverse) {
 
   // Out-of-bounds operator[].
   {
-    const char* end_msg = reverse ? "__bounded_iter::operator--: Attempt to rewind an iterator past the start"
-                                  : "__bounded_iter::operator[]: Attempt to index an iterator past the end";
-    const char* past_end_msg =
+    [[maybe_unused]] const char* end_msg =
+        reverse ? "__bounded_iter::operator--: Attempt to rewind an iterator past the start"
+                : "__bounded_iter::operator[]: Attempt to index an iterator past the end";
+    [[maybe_unused]] const char* past_end_msg =
         reverse ? "__bounded_iter::operator-=: Attempt to rewind an iterator past the start"
                 : "__bounded_iter::operator[]: Attempt to index an iterator past the end";
-    const char* past_start_msg =
+    [[maybe_unused]] const char* past_start_msg =
         reverse ? "__bounded_iter::operator-=: Attempt to advance an iterator past the end"
                 : "__bounded_iter::operator[]: Attempt to index an iterator past the start";
     TEST_LIBCPP_ASSERT_FAILURE(begin[distance], end_msg);

>From 5bae7a36998fe5c8ba6b394493aed472a9838266 Mon Sep 17 00:00:00 2001
From: David Benjamin <davidben at google.com>
Date: Sun, 21 Jan 2024 01:21:34 -0500
Subject: [PATCH 4/4] Fix bounded_iter tests

---
 libcxx/include/__iterator/bounded_iter.h           |  2 +-
 .../views.span/debug.iterator-indexing.pass.cpp    |  4 ++--
 .../iterators/bounded_iter/dereference.pass.cpp    | 14 +++++++-------
 .../debug.iterator-indexing.pass.cpp               |  4 ++--
 4 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/libcxx/include/__iterator/bounded_iter.h b/libcxx/include/__iterator/bounded_iter.h
index 48f40ce778c252e..2ffb6d86cfd9a48 100644
--- a/libcxx/include/__iterator/bounded_iter.h
+++ b/libcxx/include/__iterator/bounded_iter.h
@@ -108,7 +108,7 @@ struct __bounded_iter {
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
         __n >= __begin_ - __current_, "__bounded_iter::operator[]: Attempt to index an iterator past the start");
     _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(
-        __n < __end_ - __current_, "__bounded_iter::operator[]: Attempt to index an iterator past the end");
+        __n < __end_ - __current_, "__bounded_iter::operator[]: Attempt to index an iterator at or past the end");
     return __current_[__n];
   }
 
diff --git a/libcxx/test/libcxx/containers/views/views.span/debug.iterator-indexing.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/debug.iterator-indexing.pass.cpp
index e196d4b2998ce46..c800263c64c5a1d 100644
--- a/libcxx/test/libcxx/containers/views/views.span/debug.iterator-indexing.pass.cpp
+++ b/libcxx/test/libcxx/containers/views/views.span/debug.iterator-indexing.pass.cpp
@@ -123,10 +123,10 @@ void test_iterator(Iter begin, Iter end, bool reverse) {
   {
     [[maybe_unused]] const char* end_msg =
         reverse ? "__bounded_iter::operator--: Attempt to rewind an iterator past the start"
-                : "__bounded_iter::operator[]: Attempt to index an iterator past the end";
+                : "__bounded_iter::operator[]: Attempt to index an iterator at or past the end";
     [[maybe_unused]] const char* past_end_msg =
         reverse ? "__bounded_iter::operator-=: Attempt to rewind an iterator past the start"
-                : "__bounded_iter::operator[]: Attempt to index an iterator past the end";
+                : "__bounded_iter::operator[]: Attempt to index an iterator at or past the end";
     [[maybe_unused]] const char* past_start_msg =
         reverse ? "__bounded_iter::operator-=: Attempt to advance an iterator past the end"
                 : "__bounded_iter::operator[]: Attempt to index an iterator past the start";
diff --git a/libcxx/test/libcxx/iterators/bounded_iter/dereference.pass.cpp b/libcxx/test/libcxx/iterators/bounded_iter/dereference.pass.cpp
index 8eee4ad2f319a2c..bf723f14e80a94d 100644
--- a/libcxx/test/libcxx/iterators/bounded_iter/dereference.pass.cpp
+++ b/libcxx/test/libcxx/iterators/bounded_iter/dereference.pass.cpp
@@ -58,15 +58,15 @@ void test_death() {
   std::__bounded_iter<Iter> const oob  = std::__make_bounded_iter(Iter(e), Iter(b), Iter(e));
 
   // operator*
-  TEST_LIBCPP_ASSERT_FAILURE(*oob, "__bounded_iter::operator*: Attempt to dereference an out-of-range iterator");
+  TEST_LIBCPP_ASSERT_FAILURE(*oob, "__bounded_iter::operator*: Attempt to dereference an iterator at the end");
   // operator->
-  TEST_LIBCPP_ASSERT_FAILURE(oob->x, "__bounded_iter::operator->: Attempt to dereference an out-of-range iterator");
+  TEST_LIBCPP_ASSERT_FAILURE(oob->x, "__bounded_iter::operator->: Attempt to dereference an iterator at the end");
   // operator[]
-  TEST_LIBCPP_ASSERT_FAILURE(iter[-1], "__bounded_iter::operator[]: Attempt to index an iterator out-of-range");
-  TEST_LIBCPP_ASSERT_FAILURE(iter[5], "__bounded_iter::operator[]: Attempt to index an iterator out-of-range");
-  TEST_LIBCPP_ASSERT_FAILURE(oob[0], "__bounded_iter::operator[]: Attempt to index an iterator out-of-range");
-  TEST_LIBCPP_ASSERT_FAILURE(oob[1], "__bounded_iter::operator[]: Attempt to index an iterator out-of-range");
-  TEST_LIBCPP_ASSERT_FAILURE(oob[-6], "__bounded_iter::operator[]: Attempt to index an iterator out-of-range");
+  TEST_LIBCPP_ASSERT_FAILURE(iter[-1], "__bounded_iter::operator[]: Attempt to index an iterator past the start");
+  TEST_LIBCPP_ASSERT_FAILURE(iter[5], "__bounded_iter::operator[]: Attempt to index an iterator at or past the end");
+  TEST_LIBCPP_ASSERT_FAILURE(oob[0], "__bounded_iter::operator[]: Attempt to index an iterator at or past the end");
+  TEST_LIBCPP_ASSERT_FAILURE(oob[1], "__bounded_iter::operator[]: Attempt to index an iterator at or past the end");
+  TEST_LIBCPP_ASSERT_FAILURE(oob[-6], "__bounded_iter::operator[]: Attempt to index an iterator past the start");
 }
 
 int main(int, char**) {
diff --git a/libcxx/test/libcxx/strings/string.view/string.view.iterators/debug.iterator-indexing.pass.cpp b/libcxx/test/libcxx/strings/string.view/string.view.iterators/debug.iterator-indexing.pass.cpp
index ee67cbba0f4d95e..08a1d8338ad6eb9 100644
--- a/libcxx/test/libcxx/strings/string.view/string.view.iterators/debug.iterator-indexing.pass.cpp
+++ b/libcxx/test/libcxx/strings/string.view/string.view.iterators/debug.iterator-indexing.pass.cpp
@@ -119,10 +119,10 @@ void test_iterator(Iter begin, Iter end, bool reverse) {
   {
     [[maybe_unused]] const char* end_msg =
         reverse ? "__bounded_iter::operator--: Attempt to rewind an iterator past the start"
-                : "__bounded_iter::operator[]: Attempt to index an iterator past the end";
+                : "__bounded_iter::operator[]: Attempt to index an iterator at or past the end";
     [[maybe_unused]] const char* past_end_msg =
         reverse ? "__bounded_iter::operator-=: Attempt to rewind an iterator past the start"
-                : "__bounded_iter::operator[]: Attempt to index an iterator past the end";
+                : "__bounded_iter::operator[]: Attempt to index an iterator at or past the end";
     [[maybe_unused]] const char* past_start_msg =
         reverse ? "__bounded_iter::operator-=: Attempt to advance an iterator past the end"
                 : "__bounded_iter::operator[]: Attempt to index an iterator past the start";



More information about the libcxx-commits mailing list