1 // 2 // Tests for 3 // bounded_ptr& operator+=(std::ptrdiff_t n); 4 // 5 6 #include <libkern/c++/bounded_ptr.h> 7 #include <array> 8 #include <cstddef> 9 #include <cstdint> 10 #include <limits> 11 #include <darwintest.h> 12 #include <darwintest_utils.h> 13 #include "test_utils.h" 14 15 #define _assert(...) T_ASSERT_TRUE((__VA_ARGS__), # __VA_ARGS__) 16 17 struct T { int i; }; 18 19 namespace { 20 struct tracking_policy { 21 static bool did_trap; 22 static void 23 trap(char const*) 24 { 25 did_trap = true; 26 } 27 }; 28 bool tracking_policy::did_trap = false; 29 } 30 31 template <typename T, typename QualT> 32 static void 33 tests() 34 { 35 std::array<T, 5> array = {T{0}, T{1}, T{2}, T{3}, T{4}}; 36 37 // Add-assign positive offsets 38 // T{0} T{1} T{2} T{3} T{4} <one-past-last> 39 // ^ ^ 40 // | | 41 // begin,ptr end 42 { 43 test_bounded_ptr<QualT> ptr(array.begin(), array.begin(), array.end()); 44 auto& ref = ptr += 0; 45 _assert(&ref == &ptr); 46 _assert(&*ptr == &array[0]); 47 } 48 { 49 test_bounded_ptr<QualT> ptr(array.begin(), array.begin(), array.end()); 50 auto& ref = ptr += 1; 51 _assert(&ref == &ptr); 52 _assert(&*ptr == &array[1]); 53 } 54 { 55 test_bounded_ptr<QualT> ptr(array.begin(), array.begin(), array.end()); 56 auto& ref = ptr += 2; 57 _assert(&ref == &ptr); 58 _assert(&*ptr == &array[2]); 59 } 60 { 61 test_bounded_ptr<QualT> ptr(array.begin(), array.begin(), array.end()); 62 auto& ref = ptr += 3; 63 _assert(&ref == &ptr); 64 _assert(&*ptr == &array[3]); 65 } 66 { 67 test_bounded_ptr<QualT> ptr(array.begin(), array.begin(), array.end()); 68 auto& ref = ptr += 4; 69 _assert(&ref == &ptr); 70 _assert(&*ptr == &array[4]); 71 } 72 { 73 test_bounded_ptr<QualT> ptr(array.begin(), array.begin(), array.end()); 74 auto& ref = ptr += 5; 75 _assert(&ref == &ptr); 76 _assert(ptr == array.end()); 77 } 78 79 // Add-assign negative offsets 80 // T{0} T{1} T{2} T{3} T{4} <one-past-last> 81 // ^ ^ 82 // | | 83 // begin end,ptr 84 { 85 test_bounded_ptr<QualT> ptr(array.end(), array.begin(), array.end()); 86 auto& ref = ptr += 0; 87 _assert(&ref == &ptr); 88 _assert(ptr == array.end()); 89 } 90 { 91 test_bounded_ptr<QualT> ptr(array.end(), array.begin(), array.end()); 92 auto& ref = ptr += -1; 93 _assert(&ref == &ptr); 94 _assert(&*ptr == &array[4]); 95 } 96 { 97 test_bounded_ptr<QualT> ptr(array.end(), array.begin(), array.end()); 98 auto& ref = ptr += -2; 99 _assert(&ref == &ptr); 100 _assert(&*ptr == &array[3]); 101 } 102 { 103 test_bounded_ptr<QualT> ptr(array.end(), array.begin(), array.end()); 104 auto& ref = ptr += -3; 105 _assert(&ref == &ptr); 106 _assert(&*ptr == &array[2]); 107 } 108 { 109 test_bounded_ptr<QualT> ptr(array.end(), array.begin(), array.end()); 110 auto& ref = ptr += -4; 111 _assert(&ref == &ptr); 112 _assert(&*ptr == &array[1]); 113 } 114 { 115 test_bounded_ptr<QualT> ptr(array.end(), array.begin(), array.end()); 116 auto& ref = ptr += -5; 117 _assert(&ref == &ptr); 118 _assert(&*ptr == &array[0]); 119 } 120 121 // Make sure we trap on arithmetic overflow in the number of bytes calculation 122 { 123 std::ptrdiff_t sizeof_T = sizeof(T); // avoid promotion to unsigned in calculations 124 125 // largest (most positive) n for the number of bytes `n * sizeof(T)` not to overflow ptrdiff_t 126 std::ptrdiff_t max_n = std::numeric_limits<std::ptrdiff_t>::max() / sizeof_T; 127 128 // smallest (most negative) n for the number of bytes `n * sizeof(T)` not to overflow ptrdiff_t 129 std::ptrdiff_t min_n = std::numeric_limits<std::ptrdiff_t>::min() / sizeof_T; 130 131 // Overflow with a positive offset 132 { 133 libkern::bounded_ptr<QualT, tracking_policy> ptr(array.begin(), array.begin(), array.end()); 134 tracking_policy::did_trap = false; 135 ptr += max_n + 1; 136 _assert(tracking_policy::did_trap); 137 } 138 139 // Overflow with a negative offset 140 { 141 libkern::bounded_ptr<QualT, tracking_policy> ptr(array.begin(), array.begin(), array.end()); 142 tracking_policy::did_trap = false; 143 ptr += min_n - 1; 144 _assert(tracking_policy::did_trap); 145 } 146 } 147 148 // Make sure we trap on arithmetic overflow in the offset calculation 149 // 150 // To avoid running into the overflow of `n * sizeof(T)` when ptrdiff_t 151 // is the same size as int32_t, we test the offset overflow check by 152 // successive addition of smaller offsets. 153 // 154 // We basically push the offset right to its limit, and then push it 155 // past its limit to watch it overflow. 156 { 157 std::int64_t sizeof_T = sizeof(T); // avoid promotion to unsigned in calculations 158 159 // largest (most positive) n for the number of bytes `n * sizeof(T)` not to overflow the int32_t offset 160 std::int64_t max_n = std::numeric_limits<std::int32_t>::max() / sizeof_T; 161 162 // smallest (most negative) n for the number of bytes `n * sizeof(T)` not to overflow the int32_t offset 163 std::int64_t min_n = std::numeric_limits<std::int32_t>::min() / sizeof_T; 164 165 // Add positive offsets 166 { 167 libkern::bounded_ptr<QualT, tracking_policy> ptr(array.begin(), array.begin(), array.end()); 168 tracking_policy::did_trap = false; 169 ptr += static_cast<ptrdiff_t>(max_n / 2); 170 _assert(!tracking_policy::did_trap); 171 ptr += static_cast<ptrdiff_t>(max_n / 2); 172 _assert(!tracking_policy::did_trap); 173 ptr += (max_n % 2); 174 _assert(!tracking_policy::did_trap); // offset is now right at its positive limit 175 ptr += 1; 176 _assert(tracking_policy::did_trap); 177 } 178 179 // Add negative offsets 180 { 181 libkern::bounded_ptr<QualT, tracking_policy> ptr(array.begin(), array.begin(), array.end()); 182 tracking_policy::did_trap = false; 183 ptr += static_cast<ptrdiff_t>(min_n / 2); 184 _assert(!tracking_policy::did_trap); 185 ptr += static_cast<ptrdiff_t>(min_n / 2); 186 _assert(!tracking_policy::did_trap); 187 ptr += (min_n % 2); 188 _assert(!tracking_policy::did_trap); // offset is now right at its negative limit 189 ptr += -1; 190 _assert(tracking_policy::did_trap); 191 } 192 } 193 } 194 195 T_DECL(arith_add_assign, "bounded_ptr.arith.add_assign") { 196 tests<T, T>(); 197 tests<T, T const>(); 198 tests<T, T volatile>(); 199 tests<T, T const volatile>(); 200 } 201