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

source code of libcxx/test/std/containers/sequences/array/assert.iterators.pass.cpp