xref: /llvm-project/libcxx/test/std/containers/sequences/array/assert.iterators.pass.cpp (revision 427a5cf105c409993c812f4fb1868bac96fce0c5)
1*427a5cf1SLouis Dionne //===----------------------------------------------------------------------===//
2*427a5cf1SLouis Dionne //
3*427a5cf1SLouis Dionne // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*427a5cf1SLouis Dionne // See https://llvm.org/LICENSE.txt for license information.
5*427a5cf1SLouis Dionne // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*427a5cf1SLouis Dionne //
7*427a5cf1SLouis Dionne //===----------------------------------------------------------------------===//
8*427a5cf1SLouis Dionne 
9*427a5cf1SLouis Dionne // REQUIRES: has-unix-headers, libcpp-has-abi-bounded-iterators-in-std-array
10*427a5cf1SLouis Dionne // UNSUPPORTED: c++03
11*427a5cf1SLouis Dionne // UNSUPPORTED: libcpp-hardening-mode=none
12*427a5cf1SLouis Dionne // XFAIL: libcpp-hardening-mode=debug && availability-verbose_abort-missing
13*427a5cf1SLouis Dionne 
14*427a5cf1SLouis Dionne // <array>
15*427a5cf1SLouis Dionne 
16*427a5cf1SLouis Dionne // Make sure that std::array's iterators check for OOB accesses when the right hardening settings
17*427a5cf1SLouis Dionne // are enabled.
18*427a5cf1SLouis Dionne 
19*427a5cf1SLouis Dionne #include <array>
20*427a5cf1SLouis Dionne #include <cstddef>
21*427a5cf1SLouis Dionne #include <iterator>
22*427a5cf1SLouis Dionne 
23*427a5cf1SLouis Dionne #include "check_assertion.h"
24*427a5cf1SLouis Dionne 
25*427a5cf1SLouis Dionne template <typename Iter>
26*427a5cf1SLouis Dionne void test_iterator(Iter begin, Iter end) {
27*427a5cf1SLouis Dionne   std::ptrdiff_t distance = std::distance(begin, end);
28*427a5cf1SLouis Dionne 
29*427a5cf1SLouis Dionne   // Dereferencing an iterator at the end.
30*427a5cf1SLouis Dionne   {
31*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(*end, "__static_bounded_iter::operator*: Attempt to dereference an iterator at the end");
32*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(
33*427a5cf1SLouis Dionne         end.operator->(), "__static_bounded_iter::operator->: Attempt to dereference an iterator at the end");
34*427a5cf1SLouis Dionne   }
35*427a5cf1SLouis Dionne 
36*427a5cf1SLouis Dionne   // Incrementing an iterator past the end.
37*427a5cf1SLouis Dionne   {
38*427a5cf1SLouis Dionne     auto it = end;
39*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(it++, "__static_bounded_iter::operator++: Attempt to advance an iterator past the end");
40*427a5cf1SLouis Dionne     it = end;
41*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(++it, "__static_bounded_iter::operator++: Attempt to advance an iterator past the end");
42*427a5cf1SLouis Dionne   }
43*427a5cf1SLouis Dionne 
44*427a5cf1SLouis Dionne   // Decrementing an iterator past the start.
45*427a5cf1SLouis Dionne   {
46*427a5cf1SLouis Dionne     auto it = begin;
47*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(it--, "__static_bounded_iter::operator--: Attempt to rewind an iterator past the start");
48*427a5cf1SLouis Dionne     it = begin;
49*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(--it, "__static_bounded_iter::operator--: Attempt to rewind an iterator past the start");
50*427a5cf1SLouis Dionne   }
51*427a5cf1SLouis Dionne 
52*427a5cf1SLouis Dionne   // Advancing past the end with operator+= and operator+.
53*427a5cf1SLouis Dionne   {
54*427a5cf1SLouis Dionne     [[maybe_unused]] const char* msg = "__static_bounded_iter::operator+=: Attempt to advance an iterator past the end";
55*427a5cf1SLouis Dionne     auto it                          = end;
56*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(it += 1, msg);
57*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(end + 1, msg);
58*427a5cf1SLouis Dionne     it = begin;
59*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(it += (distance + 1), msg);
60*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(begin + (distance + 1), msg);
61*427a5cf1SLouis Dionne   }
62*427a5cf1SLouis Dionne 
63*427a5cf1SLouis Dionne   // Advancing past the end with operator-= and operator-.
64*427a5cf1SLouis Dionne   {
65*427a5cf1SLouis Dionne     [[maybe_unused]] const char* msg = "__static_bounded_iter::operator-=: Attempt to advance an iterator past the end";
66*427a5cf1SLouis Dionne     auto it                          = end;
67*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(it -= (-1), msg);
68*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(end - (-1), msg);
69*427a5cf1SLouis Dionne     it = begin;
70*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(it -= (-distance - 1), msg);
71*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(begin - (-distance - 1), msg);
72*427a5cf1SLouis Dionne   }
73*427a5cf1SLouis Dionne 
74*427a5cf1SLouis Dionne   // Rewinding past the start with operator+= and operator+.
75*427a5cf1SLouis Dionne   {
76*427a5cf1SLouis Dionne     [[maybe_unused]] const char* msg =
77*427a5cf1SLouis Dionne         "__static_bounded_iter::operator+=: Attempt to rewind an iterator past the start";
78*427a5cf1SLouis Dionne     auto it = begin;
79*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(it += (-1), msg);
80*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(begin + (-1), msg);
81*427a5cf1SLouis Dionne     it = end;
82*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(it += (-distance - 1), msg);
83*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(end + (-distance - 1), msg);
84*427a5cf1SLouis Dionne   }
85*427a5cf1SLouis Dionne 
86*427a5cf1SLouis Dionne   // Rewinding past the start with operator-= and operator-.
87*427a5cf1SLouis Dionne   {
88*427a5cf1SLouis Dionne     [[maybe_unused]] const char* msg =
89*427a5cf1SLouis Dionne         "__static_bounded_iter::operator-=: Attempt to rewind an iterator past the start";
90*427a5cf1SLouis Dionne     auto it = begin;
91*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(it -= 1, msg);
92*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(begin - 1, msg);
93*427a5cf1SLouis Dionne     it = end;
94*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(it -= (distance + 1), msg);
95*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(end - (distance + 1), msg);
96*427a5cf1SLouis Dionne   }
97*427a5cf1SLouis Dionne 
98*427a5cf1SLouis Dionne   // Out-of-bounds operator[].
99*427a5cf1SLouis Dionne   {
100*427a5cf1SLouis Dionne     [[maybe_unused]] const char* end_msg =
101*427a5cf1SLouis Dionne         "__static_bounded_iter::operator[]: Attempt to index an iterator at or past the end";
102*427a5cf1SLouis Dionne     [[maybe_unused]] const char* past_end_msg =
103*427a5cf1SLouis Dionne         "__static_bounded_iter::operator[]: Attempt to index an iterator at or past the end";
104*427a5cf1SLouis Dionne     [[maybe_unused]] const char* past_start_msg =
105*427a5cf1SLouis Dionne         "__static_bounded_iter::operator[]: Attempt to index an iterator past the start";
106*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(begin[distance], end_msg);
107*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(begin[distance + 1], past_end_msg);
108*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(begin[-1], past_start_msg);
109*427a5cf1SLouis Dionne     TEST_LIBCPP_ASSERT_FAILURE(begin[-99], past_start_msg);
110*427a5cf1SLouis Dionne 
111*427a5cf1SLouis Dionne     if (distance > 0) {
112*427a5cf1SLouis Dionne       auto it = begin + 1;
113*427a5cf1SLouis Dionne       TEST_LIBCPP_ASSERT_FAILURE(it[distance - 1], end_msg);
114*427a5cf1SLouis Dionne       TEST_LIBCPP_ASSERT_FAILURE(it[distance], past_end_msg);
115*427a5cf1SLouis Dionne       TEST_LIBCPP_ASSERT_FAILURE(it[-2], past_start_msg);
116*427a5cf1SLouis Dionne       TEST_LIBCPP_ASSERT_FAILURE(it[-99], past_start_msg);
117*427a5cf1SLouis Dionne     }
118*427a5cf1SLouis Dionne   }
119*427a5cf1SLouis Dionne }
120*427a5cf1SLouis Dionne 
121*427a5cf1SLouis Dionne int main(int, char**) {
122*427a5cf1SLouis Dionne   // Empty array
123*427a5cf1SLouis Dionne   {
124*427a5cf1SLouis Dionne     std::array<int, 0> array = {};
125*427a5cf1SLouis Dionne 
126*427a5cf1SLouis Dionne     // array::iterator
127*427a5cf1SLouis Dionne     test_iterator(array.begin(), array.end());
128*427a5cf1SLouis Dionne 
129*427a5cf1SLouis Dionne     // array::const_iterator
130*427a5cf1SLouis Dionne     test_iterator(array.cbegin(), array.cend());
131*427a5cf1SLouis Dionne   }
132*427a5cf1SLouis Dionne 
133*427a5cf1SLouis Dionne   // Non-empty array
134*427a5cf1SLouis Dionne   {
135*427a5cf1SLouis Dionne     std::array<int, 10> array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
136*427a5cf1SLouis Dionne 
137*427a5cf1SLouis Dionne     // array::iterator
138*427a5cf1SLouis Dionne     test_iterator(array.begin(), array.end());
139*427a5cf1SLouis Dionne 
140*427a5cf1SLouis Dionne     // array::const_iterator
141*427a5cf1SLouis Dionne     test_iterator(array.cbegin(), array.cend());
142*427a5cf1SLouis Dionne   }
143*427a5cf1SLouis Dionne 
144*427a5cf1SLouis Dionne   return 0;
145*427a5cf1SLouis Dionne }
146