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