xref: /xnu-12377.41.6/tests/cxx_safe_buffers_src/reinterpret_span_cast.cpp (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
1 /*
2  * Tests for reinterpret_span_cast template in cxx_safe_buffers.h
3  */
4 #include <os/cxx_safe_buffers.h>
5 #include <vector>
6 #include <darwintest.h>
7 #include <darwintest_utils.h>
8 #define CHECK(...) T_ASSERT_TRUE((__VA_ARGS__), # __VA_ARGS__)
9 
10 struct A {
11 	int a[2];
12 };
13 
14 struct B {
15 	int b[3];
16 };
17 
18 struct C : B {
19 	int c[3];
20 };
21 
22 struct D {
23 	std::uint8_t a[2];
24 };
25 
26 struct NoPadding {
27 	char a;
28 	char b;
29 
30 	int c;
31 };
32 
33 struct WithPaddingMiddle {
34 	char a;
35 	int b;
36 
37 	char c;
38 };
39 
40 struct PaddingEnd {
41 	int a;
42 	char c;
43 };
44 
45 
46 static void
tests()47 tests()
48 {
49 	{
50 		// convert span<int> to span<byte>
51 		std::array<int, 3> a1{{1, 2, 3}};
52 		std::span<int> sp{a1}; // static-extent std::span
53 		std::span<std::byte> writable_sp = os::reinterpret_span_cast<std::byte>(sp);
54 		std::span<const std::byte> nonwritable_sp = os::reinterpret_span_cast<const std::byte>(sp);
55 		CHECK(writable_sp.size() == sp.size_bytes() && nonwritable_sp.size() == sp.size_bytes());
56 	}
57 
58 	{
59 		// convert span<byte> to span<A>
60 		std::vector<std::byte> vec {std::byte{0}, std::byte{1}, std::byte{2}, std::byte{3},
61 			                    std::byte{4}, std::byte{5}, std::byte{6}, std::byte{7}};
62 		std::span<std::byte> sp{vec}; // dynamic-extent std::span
63 		std::span<A> span_a = os::reinterpret_span_cast<A>(sp);
64 		CHECK(sp.size() == span_a.size_bytes());
65 	}
66 
67 	{
68 		// convert to a span of unrelated type
69 		std::array<A, 3> arr;
70 		std::span<A> span_a = arr;
71 		std::span<B> span_b = os::reinterpret_span_cast<B>(span_a);
72 		CHECK(span_b.size() == 2);
73 	}
74 
75 	{
76 		// convert to a span of extended type
77 		B array[4];
78 		std::span<B> span_b = array;
79 		std::span<C> span_c = os::reinterpret_span_cast<C>(span_b);
80 		CHECK(2 * span_c.size() == span_b.size());
81 	}
82 
83 	{
84 		//convert to a span of base type
85 		C array[4];
86 		std::span<C> span_c = array;
87 		std::span<B> span_b = os::reinterpret_span_cast<B>(span_c);
88 		CHECK(2 * span_c.size() == span_b.size());
89 	}
90 	{
91 		std::array<std::uint8_t, 12> buf;
92 		std::span<std::uint8_t> sp = buf;
93 		std::span<D> span_d = os::reinterpret_span_cast<D>(sp);
94 		CHECK(span_d.size() == 6);
95 	}
96 }
97 
98 static void
trapping_test()99 trapping_test()
100 {
101 	pid_t pid = fork(); // Fork a new process
102 	T_ASSERT_POSIX_SUCCESS(pid, "forked %d", pid);
103 
104 	if (pid == 0) {
105 		// convert to a span of unrelated type
106 		A array[2];
107 		std::span<A> span_a = {array, 2};
108 		// This invocation will cause a run time trap in child process.
109 		std::span<B> span_b = os::reinterpret_span_cast<B>(span_a);
110 
111 		exit(0); // Exit child process
112 	}
113 
114 	int status = 0, signal = 0;
115 
116 	// wait for the child process to finish
117 	T_ASSERT_FALSE(dt_waitpid(pid, &status, &signal, 0), "wait for child (%d) complete with signal %d", pid, signal);
118 	// child process must trigger an execution trap
119 	T_ASSERT_TRUE(WIFSIGNALED(signal), "Child process successfully triggered an execution trap");
120 }
121 
122 
123 T_DECL(reinterpret_span_cast, "cxx_safe_buffers.reinterpret_span_cast")
124 {
125 	tests();
126 	trapping_test();
127 }
128