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