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