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