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