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