1 // 2 // Tests for 3 // T& operator*() const; 4 // T* operator->() const; 5 // 6 7 #include <libkern/c++/bounded_ptr.h> 8 #include <array> 9 #include <darwintest.h> 10 #include <darwintest_utils.h> 11 #include "test_utils.h" 12 13 #define _assert(...) T_ASSERT_TRUE((__VA_ARGS__), # __VA_ARGS__) 14 15 struct T { 16 int i; 17 friend constexpr bool 18 operator==(T const volatile& a, T const& b) 19 { 20 return a.i == b.i; 21 } 22 }; 23 24 namespace { 25 struct tracking_policy { 26 static bool did_trap; 27 static void 28 trap(char const*) 29 { 30 did_trap = true; 31 } 32 }; 33 bool tracking_policy::did_trap = false; 34 } 35 36 template <typename T, typename QualT> 37 static void 38 tests() 39 { 40 std::array<T, 5> array = {T{0}, T{1}, T{2}, T{3}, T{4}}; 41 42 { 43 // T{0} T{1} T{2} T{3} T{4} <one-past-last> 44 // ^ ^ 45 // | | 46 // begin, ptr end 47 test_bounded_ptr<QualT> ptr(array.begin() + 0, array.begin(), array.end()); 48 QualT& ref = *ptr; 49 _assert(ref == T{0}); 50 _assert(&ref == &array[0]); 51 52 _assert(ptr->i == 0); 53 _assert(&ptr->i == &array[0].i); 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> ptr(array.begin() + 1, array.begin(), array.end()); 61 QualT& ref = *ptr; 62 _assert(ref == T{1}); 63 _assert(&ref == &array[1]); 64 65 _assert(ptr->i == 1); 66 _assert(&ptr->i == &array[1].i); 67 } 68 { 69 // T{0} T{1} T{2} T{3} T{4} <one-past-last> 70 // ^ ^ ^ 71 // | | | 72 // begin ptr end 73 test_bounded_ptr<QualT> ptr(array.begin() + 2, array.begin(), array.end()); 74 QualT& ref = *ptr; 75 _assert(ref == T{2}); 76 _assert(&ref == &array[2]); 77 78 _assert(ptr->i == 2); 79 _assert(&ptr->i == &array[2].i); 80 } 81 { 82 // T{0} T{1} T{2} T{3} T{4} <one-past-last> 83 // ^ ^ ^ 84 // | | | 85 // begin ptr end 86 test_bounded_ptr<QualT> ptr(array.begin() + 4, array.begin(), array.end()); 87 QualT& ref = *ptr; 88 _assert(ref == T{4}); 89 _assert(&ref == &array[4]); 90 91 _assert(ptr->i == 4); 92 _assert(&ptr->i == &array[4].i); 93 } 94 95 // Make sure we don't trap when dereferencing an in-bounds pointer 96 { 97 // T{0} T{1} T{2} T{3} T{4} <one-past-last> 98 // ^ ^ ^ 99 // | | | 100 // begin ptr end 101 libkern::bounded_ptr<QualT, tracking_policy> ptr(array.begin() + 1, array.begin(), array.end()); 102 103 tracking_policy::did_trap = false; 104 (void)*ptr; 105 (void)ptr->i; 106 _assert(!tracking_policy::did_trap); 107 } 108 109 // Make sure we trap when dereferencing an out-of-bounds pointer 110 { 111 // T{0} T{1} T{2} T{3} T{4} <one-past-last> 112 // ^ ^ ^ 113 // | | | 114 // begin end ptr 115 libkern::bounded_ptr<QualT, tracking_policy> ptr(array.end() - 1, array.begin(), array.end() - 2); 116 117 tracking_policy::did_trap = false; 118 (void)*ptr; 119 _assert(tracking_policy::did_trap); 120 121 tracking_policy::did_trap = false; 122 (void)ptr->i; 123 _assert(tracking_policy::did_trap); 124 } 125 { 126 // T{0} T{1} T{2} T{3} T{4} <one-past-last> 127 // ^ ^ ^ 128 // | | | 129 // ptr begin end 130 libkern::bounded_ptr<QualT, tracking_policy> ptr(array.begin(), array.begin() + 1, array.end()); 131 132 tracking_policy::did_trap = false; 133 (void)*ptr; 134 _assert(tracking_policy::did_trap); 135 136 tracking_policy::did_trap = false; 137 (void)ptr->i; 138 _assert(tracking_policy::did_trap); 139 } 140 { 141 // T{0} T{1} T{2} T{3} T{4} <one-past-last> 142 // ^ ^ ^ 143 // | (just a bit off) | | 144 // begin ptr end 145 T* t3 = const_cast<T*>(array.begin() + 3); 146 char* just_off = reinterpret_cast<char*>(t3) + 1; // 1 byte off 147 libkern::bounded_ptr<QualT, tracking_policy> ptr(reinterpret_cast<QualT*>(just_off), array.begin(), array.end() - 1); 148 149 tracking_policy::did_trap = false; 150 (void)*ptr; 151 _assert(tracking_policy::did_trap); 152 153 tracking_policy::did_trap = false; 154 (void)ptr->i; 155 _assert(tracking_policy::did_trap); 156 } 157 } 158 159 T_DECL(deref, "bounded_ptr.deref") { 160 tests<T, T>(); 161 tests<T, T const>(); 162 tests<T, T volatile>(); 163 tests<T, T const volatile>(); 164 165 // Make sure that we don't hard-error in the definition of operator* 166 // when instantiating a `bounded_ptr<cv-void>` 167 test_bounded_ptr<void> p1; 168 test_bounded_ptr<void const> p2; 169 test_bounded_ptr<void volatile> p3; 170 test_bounded_ptr<void const volatile> p4; 171 } 172