]>
git.saurik.com Git - apple/xnu.git/blob - tests/bounded_ptr_src/arith.subtract_assign.cpp
3 // bounded_ptr& operator-=(std::ptrdiff_t n);
6 #include <libkern/c++/bounded_ptr.h>
8 #include <darwintest.h>
9 #include <darwintest_utils.h>
10 #include "test_utils.h"
12 #define _assert(...) T_ASSERT_TRUE((__VA_ARGS__), # __VA_ARGS__)
17 struct tracking_policy
{
25 bool tracking_policy::did_trap
= false;
28 template <typename T
, typename QualT
>
32 std::array
<T
, 5> array
= {T
{0}, T
{1}, T
{2}, T
{3}, T
{4}};
34 // Subtract-assign positive offsets
35 // T{0} T{1} T{2} T{3} T{4} <one-past-last>
40 test_bounded_ptr
<QualT
> ptr(array
.end(), array
.begin(), array
.end());
42 _assert(&ref
== &ptr
);
43 _assert(ptr
== array
.end());
46 test_bounded_ptr
<QualT
> ptr(array
.end(), array
.begin(), array
.end());
48 _assert(&ref
== &ptr
);
49 _assert(&*ptr
== &array
[4]);
52 test_bounded_ptr
<QualT
> ptr(array
.end(), array
.begin(), array
.end());
54 _assert(&ref
== &ptr
);
55 _assert(&*ptr
== &array
[3]);
58 test_bounded_ptr
<QualT
> ptr(array
.end(), array
.begin(), array
.end());
60 _assert(&ref
== &ptr
);
61 _assert(&*ptr
== &array
[2]);
64 test_bounded_ptr
<QualT
> ptr(array
.end(), array
.begin(), array
.end());
66 _assert(&ref
== &ptr
);
67 _assert(&*ptr
== &array
[1]);
70 test_bounded_ptr
<QualT
> ptr(array
.end(), array
.begin(), array
.end());
72 _assert(&ref
== &ptr
);
73 _assert(&*ptr
== &array
[0]);
76 // Subtract-assign negative offsets
77 // T{0} T{1} T{2} T{3} T{4} <one-past-last>
82 test_bounded_ptr
<QualT
> ptr(array
.begin(), array
.begin(), array
.end());
84 _assert(&ref
== &ptr
);
85 _assert(&*ptr
== &array
[0]);
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]);
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]);
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]);
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]);
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());
118 // Make sure we trap on arithmetic overflow in the number of bytes calculation
120 std::ptrdiff_t sizeof_T
= sizeof(T
); // avoid promotion to unsigned in calculations
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
;
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
;
128 // Overflow with a positive offset
130 libkern::bounded_ptr
<QualT
, tracking_policy
> ptr(array
.begin(), array
.begin(), array
.end());
131 tracking_policy::did_trap
= false;
133 _assert(tracking_policy::did_trap
);
136 // Overflow with a negative offset
138 libkern::bounded_ptr
<QualT
, tracking_policy
> ptr(array
.begin(), array
.begin(), array
.end());
139 tracking_policy::did_trap
= false;
141 _assert(tracking_policy::did_trap
);
145 // Make sure we trap on arithmetic overflow in the offset calculation
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.
151 // We basically push the offset right to its limit, and then push it
152 // past its limit to watch it overflow.
154 std::int64_t sizeof_T
= sizeof(T
); // avoid promotion to unsigned in calculations
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
;
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
;
162 // Subtract positive offsets
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
);
171 _assert(!tracking_policy::did_trap
); // offset is now right at its negative limit
173 _assert(tracking_policy::did_trap
);
176 // Subtract negative offsets
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
);
185 _assert(!tracking_policy::did_trap
); // offset is now right at its positive limit
187 _assert(tracking_policy::did_trap
);
192 T_DECL(arith_subtract_assign
, "bounded_ptr.arith.subtract_assign") {
195 tests
<T
, T
volatile>();
196 tests
<T
, T
const volatile>();