1 // 2 // Tests for 3 // T* unsafe_discard_bounds() const; 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 namespace { 18 struct tracking_policy { 19 static bool did_trap; 20 static void 21 trap(char const*) 22 { 23 did_trap = true; 24 } 25 }; 26 bool tracking_policy::did_trap = false; 27 } 28 29 struct T { int i; }; 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 { 38 // T{0} T{1} T{2} T{3} T{4} <one-past-last> 39 // ^ ^ 40 // | | 41 // begin, ptr end 42 test_bounded_ptr<QualT> const ptr(array.begin() + 0, array.begin(), array.end()); 43 QualT* raw = ptr.unsafe_discard_bounds(); 44 _assert(raw == &array[0]); 45 } 46 { 47 // T{0} T{1} T{2} T{3} T{4} <one-past-last> 48 // ^ ^ ^ 49 // | | | 50 // begin ptr end 51 test_bounded_ptr<QualT> const ptr(array.begin() + 1, array.begin(), array.end()); 52 QualT* raw = ptr.unsafe_discard_bounds(); 53 _assert(raw == &array[1]); 54 } 55 { 56 // T{0} T{1} T{2} T{3} T{4} <one-past-last> 57 // ^ ^ ^ 58 // | | | 59 // begin ptr end 60 test_bounded_ptr<QualT> const ptr(array.begin() + 2, array.begin(), array.end()); 61 QualT* raw = ptr.unsafe_discard_bounds(); 62 _assert(raw == &array[2]); 63 } 64 { 65 // T{0} T{1} T{2} T{3} T{4} <one-past-last> 66 // ^ ^ ^ 67 // | | | 68 // begin ptr end 69 test_bounded_ptr<QualT> const ptr(array.begin() + 4, array.begin(), array.end()); 70 QualT* raw = ptr.unsafe_discard_bounds(); 71 _assert(raw == &array[4]); 72 } 73 { 74 // T{0} T{1} T{2} T{3} T{4} <one-past-last> 75 // ^ ^ 76 // | | 77 // begin end,ptr 78 test_bounded_ptr<QualT> const ptr(array.end(), array.begin(), array.end()); 79 QualT* raw = ptr.unsafe_discard_bounds(); 80 _assert(raw == array.end()); 81 } 82 { 83 // T{0} T{1} T{2} T{3} T{4} <one-past-last> 84 // ^ ^ ^ 85 // | | | 86 // begin end ptr 87 test_bounded_ptr<QualT> ptr(array.end() - 1, array.begin(), array.end() - 2); 88 QualT* raw = ptr.unsafe_discard_bounds(); 89 _assert(raw == &array[4]); 90 } 91 { 92 // T{0} T{1} T{2} T{3} T{4} <one-past-last> 93 // ^ ^ ^ 94 // | | | 95 // begin ptr end 96 test_bounded_ptr<QualT> ptr(array.begin() + 1, array.begin(), array.end()); 97 QualT* raw = ptr.unsafe_discard_bounds(); 98 _assert(raw == &array[1]); 99 } 100 { 101 // T{0} T{1} T{2} T{3} T{4} <one-past-last> 102 // ^ ^ ^ 103 // | | | 104 // ptr begin end 105 test_bounded_ptr<QualT> ptr(array.begin(), array.begin() + 1, array.end()); 106 QualT* raw = ptr.unsafe_discard_bounds(); 107 _assert(raw == &array[0]); 108 } 109 110 // Test discarding the bounds of a null pointer 111 { 112 test_bounded_ptr<QualT> const ptr(nullptr, nullptr, nullptr); 113 QualT* raw = ptr.unsafe_discard_bounds(); 114 _assert(raw == nullptr); 115 } 116 117 // Test discarding the bounds on a pointer outside of representable memory. 118 // Even `unsafe_discard_bounds()` will trap in such conditions. 119 // 120 // To do this, we setup an imaginary object with a very high address, and 121 // we add a large-ish offset to it, such that adding the base to the offset 122 // would fall outside of the representable memory. 123 { 124 tracking_policy::did_trap = false; 125 126 QualT* end_of_memory = reinterpret_cast<QualT*>(std::numeric_limits<std::uintptr_t>::max()); 127 QualT* base = end_of_memory - 500; // yeah, technically UB 128 std::ptrdiff_t offset = 501; 129 130 libkern::bounded_ptr<QualT, tracking_policy> ptr(base, base, base + 1); 131 ptr += offset; // now, `base_ + offset_` points outside of representable memory 132 133 _assert(!tracking_policy::did_trap); 134 (void)ptr.unsafe_discard_bounds(); 135 _assert(tracking_policy::did_trap); 136 } 137 } 138 139 T_DECL(unsafe_discard_bounds, "bounded_ptr.unsafe_discard_bounds", T_META_TAG_VM_PREFERRED) { 140 tests<T, T>(); 141 tests<T, T const>(); 142 tests<T, T volatile>(); 143 tests<T, T const volatile>(); 144 } 145