1 /*
2 * Copyright (c) 2024 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /*
30 * Implementation and tests of thread test contexts.
31 */
32
33 #if !(DEBUG || DEVELOPMENT)
34 #error this file is not for release
35 #endif
36
37 #include <kern/thread_test_context.h>
38
39 /* For testing thread_test_context_t itself. */
40 DECLARE_TEST_IDENTITY(test_identity_thread_test_context);
41 DEFINE_TEST_IDENTITY(test_identity_thread_test_context);
42
43 void
thread_test_context_deinit(thread_test_context_t * ctx)44 thread_test_context_deinit(thread_test_context_t *ctx)
45 {
46 /*
47 * Deinitialize thread_text_context_t->ttc_* fields.
48 * Don't touch ttc->ttc_data.
49 */
50
51 /*
52 * for testing ttc itself: modify *ttc->ttc_data so the
53 * test can verify that this deinit was executed.
54 */
55 if (ctx->ttc_identity == test_identity_thread_test_context) {
56 int *data_p = (int *)ctx->ttc_data;
57 if (data_p) {
58 *data_p += 1;
59 }
60 }
61 }
62
63 /* Tests of thread test contexts */
64
65 #define FAIL \
66 ({ \
67 *out_value = __LINE__; \
68 return 0; \
69 })
70
71 static int
thread_test_context_tests(int64_t in_value __unused,int64_t * out_value)72 thread_test_context_tests(int64_t in_value __unused, int64_t *out_value)
73 {
74 *out_value = 0;
75
76 /*
77 * Tests of:
78 * thread_set_test_context
79 * thread_cleanup_test_context when thread's context is NULL
80 * thread_cleanup_test_context when thread's context is not NULL
81 * thread_test_context_deinit
82 */
83 {
84 /* no attribute(cleanup), we call cleanup manually */
85 int data;
86 thread_test_context_t ctx = {
87 .ttc_identity = test_identity_thread_test_context,
88 .ttc_data = &data,
89 };
90
91 data = 0;
92 /* cleanup called when thread's context is NULL */
93 if (current_thread()->th_test_ctx != NULL) {
94 FAIL;
95 }
96 if (thread_get_test_context() != NULL) {
97 FAIL;
98 }
99 thread_cleanup_test_context(&ctx);
100 /* thread_test_context_deinit increments *ttc_data */
101 if (data != 1) {
102 FAIL;
103 }
104 /* thread_cleanup_test_context clears thread's context */
105 if (current_thread()->th_test_ctx != NULL) {
106 FAIL;
107 }
108
109 data = 1;
110 /* cleanup called when thread's context is not NULL */
111 thread_set_test_context(&ctx);
112 if (current_thread()->th_test_ctx != &ctx) {
113 FAIL;
114 }
115 if (thread_get_test_context() != &ctx) {
116 FAIL;
117 }
118 thread_cleanup_test_context(&ctx);
119 /* thread_test_context_deinit increments *ttc_data */
120 if (data != 2) {
121 FAIL;
122 }
123 /* thread_cleanup_test_context clears thread's context */
124 if (current_thread()->th_test_ctx != NULL) {
125 FAIL;
126 }
127 }
128
129 /*
130 * Tests of:
131 * access test options with no test context set
132 * access test options when a context is installed but no options are set
133 * attribute(cleanup(thread_cleanup_test_context))
134 */
135 int data = 0;
136 {
137 thread_test_context_t ctx CLEANUP_THREAD_TEST_CONTEXT = {
138 .ttc_identity = test_identity_thread_test_context,
139 .ttc_data = &data,
140 .ttc_testing_ttc_int = 1,
141 .ttc_testing_ttc_struct = { 33, 44 }
142 };
143
144 /* access test options with no test context set */
145 if (thread_get_test_context() != NULL) {
146 FAIL;
147 }
148
149 if (thread_get_test_option(ttc_testing_ttc_int) != 0) {
150 FAIL;
151 }
152 /* setting an option with no context has no effect */
153 thread_set_test_option(ttc_testing_ttc_int, 1 + thread_get_test_option(ttc_testing_ttc_int));
154 if (thread_get_test_option(ttc_testing_ttc_int) != 0) {
155 FAIL;
156 }
157
158 if (thread_get_test_option(ttc_testing_ttc_struct).min_address != 0) {
159 FAIL;
160 }
161 /* setting an option with no context has no effect */
162 thread_set_test_option(ttc_testing_ttc_struct, (struct mach_vm_range){55, 66});
163 if (thread_get_test_option(ttc_testing_ttc_struct).min_address != 0) {
164 FAIL;
165 }
166
167 /* access test options with a test context set */
168 thread_set_test_context(&ctx);
169 if (thread_get_test_option(ttc_testing_ttc_int) != 1) {
170 FAIL;
171 }
172 thread_set_test_option(ttc_testing_ttc_int, 1 + thread_get_test_option(ttc_testing_ttc_int));
173 if (thread_get_test_option(ttc_testing_ttc_int) != 2) {
174 FAIL;
175 }
176 thread_set_test_option(ttc_testing_ttc_int, 0);
177 if (thread_get_test_option(ttc_testing_ttc_int) != 0) {
178 FAIL;
179 }
180
181 if (thread_get_test_option(ttc_testing_ttc_struct).min_address != 33) {
182 FAIL;
183 }
184 thread_set_test_option(ttc_testing_ttc_struct, (struct mach_vm_range){55, 66});
185 if (thread_get_test_option(ttc_testing_ttc_struct).min_address != 55) {
186 FAIL;
187 }
188
189 /* thread_cleanup_test_context runs at end of scope */
190 if (data != 0) {
191 FAIL;
192 }
193 }
194 /* thread_cleanup_test_context incremented data through ttc->ttc_data */
195 if (data != 1) {
196 FAIL;
197 }
198
199 if (current_thread()->th_test_ctx != NULL) {
200 FAIL;
201 }
202
203 /* success */
204 *out_value = 0;
205 return 0;
206 }
207
208 #undef FAIL
209
210 SYSCTL_TEST_REGISTER(thread_test_context, thread_test_context_tests);
211