1 //
2 // Tests for
3 //  T* discard_bounds() const;
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 
14 struct T { int i; };
15 
16 namespace {
17 struct tracking_policy {
18 	static bool did_trap;
19 	static void
trap__anon855895ef0111::tracking_policy20 	trap(char const*)
21 	{
22 		did_trap = true;
23 	}
24 };
25 bool tracking_policy::did_trap = false;
26 }
27 
28 template <typename T, typename QualT>
29 static void
tests()30 tests()
31 {
32 	std::array<T, 5> array = {T{0}, T{1}, T{2}, T{3}, T{4}};
33 
34 	{
35 		// T{0}     T{1}     T{2}     T{3}     T{4}     <one-past-last>
36 		//   ^                                                ^
37 		//   |                                                |
38 		// begin, ptr                                        end
39 		test_bounded_ptr<QualT> const ptr(array.begin() + 0, array.begin(), array.end());
40 		QualT* raw = ptr.discard_bounds();
41 		_assert(raw == &array[0]);
42 	}
43 	{
44 		// T{0}     T{1}     T{2}     T{3}     T{4}     <one-past-last>
45 		//   ^        ^                                       ^
46 		//   |        |                                       |
47 		// begin     ptr                                     end
48 		test_bounded_ptr<QualT> const ptr(array.begin() + 1, array.begin(), array.end());
49 		QualT* raw = ptr.discard_bounds();
50 		_assert(raw == &array[1]);
51 	}
52 	{
53 		// T{0}     T{1}     T{2}     T{3}     T{4}     <one-past-last>
54 		//   ^                 ^                              ^
55 		//   |                 |                              |
56 		// begin              ptr                            end
57 		test_bounded_ptr<QualT> const ptr(array.begin() + 2, array.begin(), array.end());
58 		QualT* raw = ptr.discard_bounds();
59 		_assert(raw == &array[2]);
60 	}
61 	{
62 		// T{0}     T{1}     T{2}     T{3}     T{4}     <one-past-last>
63 		//   ^                                   ^            ^
64 		//   |                                   |            |
65 		// begin                                ptr          end
66 		test_bounded_ptr<QualT> const ptr(array.begin() + 4, array.begin(), array.end());
67 		QualT* raw = ptr.discard_bounds();
68 		_assert(raw == &array[4]);
69 	}
70 	// Make sure we don't trap when discarding the bounds of an in-bounds pointer
71 	{
72 		// T{0}     T{1}     T{2}     T{3}     T{4}     <one-past-last>
73 		//   ^        ^                                        ^
74 		//   |        |                                        |
75 		// begin     ptr                                      end
76 		libkern::bounded_ptr<QualT, tracking_policy> ptr(array.begin() + 1, array.begin(), array.end());
77 		tracking_policy::did_trap = false;
78 		(void)*ptr;
79 		(void)ptr->i;
80 		_assert(!tracking_policy::did_trap);
81 	}
82 
83 	// Make sure we trap when discarding the bounds of an out-of-bounds pointer
84 	{
85 		// T{0}     T{1}     T{2}     T{3}     T{4}     <one-past-last>
86 		//   ^                          ^        ^
87 		//   |                          |        |
88 		// begin                       end      ptr
89 		libkern::bounded_ptr<QualT, tracking_policy> ptr(array.end() - 1, array.begin(), array.end() - 2);
90 		tracking_policy::did_trap = false;
91 		(void)ptr.discard_bounds();
92 		_assert(tracking_policy::did_trap);
93 	}
94 	{
95 		// T{0}     T{1}     T{2}     T{3}     T{4}     <one-past-last>
96 		//   ^        ^                                        ^
97 		//   |        |                                        |
98 		//  ptr     begin                                     end
99 		libkern::bounded_ptr<QualT, tracking_policy> ptr(array.begin(), array.begin() + 1, array.end());
100 		tracking_policy::did_trap = false;
101 		(void)ptr.discard_bounds();
102 		_assert(tracking_policy::did_trap);
103 	}
104 	{
105 		// T{0}     T{1}     T{2}     T{3}     T{4}     <one-past-last>
106 		//   ^                             ^     ^
107 		//   |            (just a bit off) |     |
108 		// begin                          ptr   end
109 		T* t3 = const_cast<T*>(array.begin() + 3);
110 		char* just_off = reinterpret_cast<char*>(t3) + 1; // 1 byte off
111 		libkern::bounded_ptr<QualT, tracking_policy> ptr(reinterpret_cast<QualT*>(just_off), array.begin(), array.end() - 1);
112 
113 		tracking_policy::did_trap = false;
114 		(void)ptr.discard_bounds();
115 		_assert(tracking_policy::did_trap);
116 	}
117 }
118 
119 T_DECL(discard_bounds, "bounded_ptr.discard_bounds", T_META_TAG_VM_PREFERRED) {
120 	tests<T, T>();
121 	tests<T, T const>();
122 	tests<T, T volatile>();
123 	tests<T, T const volatile>();
124 }
125