]> git.saurik.com Git - apple/xnu.git/blame - tests/bounded_ptr_src/arith.subtract_assign.cpp
xnu-7195.50.7.100.1.tar.gz
[apple/xnu.git] / tests / bounded_ptr_src / arith.subtract_assign.cpp
CommitLineData
f427ee49
A
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
14struct T { int i; };
15
16namespace {
17struct tracking_policy {
18 static bool did_trap;
19 static void
20 trap(char const* msg)
21 {
22 did_trap = true;
23 }
24};
25bool tracking_policy::did_trap = false;
26}
27
28template <typename T, typename QualT>
29static void
30tests()
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
192T_DECL(arith_subtract_assign, "bounded_ptr.arith.subtract_assign") {
193 tests<T, T>();
194 tests<T, T const>();
195 tests<T, T volatile>();
196 tests<T, T const volatile>();
197}