1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2021 Oxide Computer Company
14  */
15 
16 /*
17  * Various tests for memchr() and memrchr(). Note, this test assumes that the
18  * system is either ILP32 or LP64 with an 8-bit unsigned char due to the tests
19  * that are explicitly looking at making sure memchr() and memrchr() truncate
20  * correctly.
21  */
22 
23 #include <string.h>
24 #include <unistd.h>
25 #include <sys/mman.h>
26 #include <err.h>
27 #include <stdlib.h>
28 
29 /*
30  * memchr_buf is a page sized buffer surrounded by two PROT_NONE pages which are
31  * meant to try and catch us walking over the edge of the buffer.
32  */
33 static uint8_t *memchr_buf;
34 static size_t memchr_buflen;
35 
36 static void
memchr_setup(void)37 memchr_setup(void)
38 {
39 	size_t pgsz = getpagesize();
40 	void *addr;
41 
42 	if (pgsz <= 0) {
43 		err(EXIT_FAILURE, "failed to get system page size");
44 	}
45 
46 	addr = mmap(NULL, 3 * pgsz, PROT_READ | PROT_WRITE,
47 	    MAP_PRIVATE | MAP_ANON, -1, 0);
48 	if (addr == MAP_FAILED) {
49 		err(EXIT_FAILURE, "failed to mmap %zu bytes", 3 * pgsz);
50 	}
51 
52 	memchr_buf = (uint8_t *)addr + pgsz;
53 	memchr_buflen = pgsz;
54 
55 	if (mprotect(addr, pgsz, PROT_NONE) != 0) {
56 		err(EXIT_FAILURE, "failed to protect leading PROT_NONE guard "
57 		    "at %p", addr);
58 	}
59 
60 	addr = (uint8_t *)addr + 2 * pgsz;
61 	if (mprotect(addr, pgsz, PROT_NONE) != 0) {
62 		err(EXIT_FAILURE, "failed to protect trailing PROT_NONE guard "
63 		    "at %p", addr);
64 	}
65 }
66 
67 static boolean_t
memchr_basic(void)68 memchr_basic(void)
69 {
70 	boolean_t ret = B_TRUE;
71 	const void *targ;
72 	const void *found;
73 
74 	(void) memset(memchr_buf, 0, memchr_buflen);
75 	memchr_buf[0] = 'r';
76 
77 	if ((found = memchr(memchr_buf, 'r', memchr_buflen)) != memchr_buf) {
78 		warnx("TEST FAILED: memchr failed to find 'r' (1), found %p, "
79 		    "expected %p", found, memchr_buf);
80 		ret = B_FALSE;
81 	}
82 
83 	if ((found = memrchr(memchr_buf, 'r', memchr_buflen)) != memchr_buf) {
84 		warnx("TEST FAILED: memrchr failed to find 'r' (1), found %p, "
85 		    "expected %p", found, memchr_buf);
86 		ret = B_FALSE;
87 	}
88 
89 	memchr_buf[memchr_buflen - 1] = 'r';
90 	targ = &memchr_buf[memchr_buflen - 1];
91 
92 	if ((found = memchr(memchr_buf, 'r', memchr_buflen)) != memchr_buf) {
93 		warnx("TEST FAILED: memchr failed to find 'r' (2), found %p, "
94 		    "expected %p", found, memchr_buf);
95 		ret = B_FALSE;
96 	}
97 
98 	if ((found = memrchr(memchr_buf, 'r', memchr_buflen)) != targ) {
99 		warnx("TEST FAILED: memrchr failed to find 'r' (2), found %p, "
100 		    "expected %p", found, targ);
101 		warnx("TEST FAILED: memchr failed to find 'r'");
102 		ret = B_FALSE;
103 	}
104 
105 	memchr_buf[0] = 0;
106 
107 	if ((found = memchr(memchr_buf, 'r', memchr_buflen)) != targ) {
108 		warnx("TEST FAILED: memchr failed to find 'r' (3), found %p, "
109 		    "expected %p", found, targ);
110 		ret = B_FALSE;
111 	}
112 
113 	if ((found = memrchr(memchr_buf, 'r', memchr_buflen)) != targ) {
114 		warnx("TEST FAILED: memrchr failed to find 'r' (3), found %p, "
115 		    "expected %p", found, targ);
116 		ret = B_FALSE;
117 	}
118 
119 	if (ret) {
120 		(void) printf("TEST PASSED: basic memchr() and memrchr()\n");
121 	}
122 	return (ret);
123 }
124 
125 static boolean_t
memchr_notfound(void)126 memchr_notfound(void)
127 {
128 	boolean_t ret = B_TRUE;
129 	const void *found;
130 
131 	(void) memset(memchr_buf, 0x23, memchr_buflen);
132 
133 	if ((found = memchr(memchr_buf, 0, memchr_buflen)) != NULL) {
134 		warnx("TEST FAILED: memchr unexpectedly found value (1), "
135 		    "found %p, expected %p", found, NULL);
136 		ret = B_FALSE;
137 	}
138 
139 	if (memrchr(memchr_buf, 0, memchr_buflen) != NULL) {
140 		warnx("TEST FAILED: memrchr unexpectedly found value (1), "
141 		    "found %p, expected %p", found, NULL);
142 		ret = B_FALSE;
143 	}
144 
145 	if (memchr(memchr_buf, 0x24, memchr_buflen) != NULL) {
146 		warnx("TEST FAILED: memchr unexpectedly found value (2), "
147 		    "found %p, expected %p", found, NULL);
148 		ret = B_FALSE;
149 	}
150 
151 	if (memrchr(memchr_buf, 0x24, memchr_buflen) != NULL) {
152 		warnx("TEST FAILED: memrchr unexpectedly found value (2), "
153 		    "found %p, expected %p", found, NULL);
154 		ret = B_FALSE;
155 	}
156 
157 	memchr_buf[1] = 0x24;
158 
159 	if (memchr(memchr_buf, 0x24, 1) != NULL) {
160 		warnx("TEST FAILED: memchr unexpectedly found value (3), "
161 		    "found %p, expected %p", found, NULL);
162 		ret = B_FALSE;
163 	}
164 
165 	if (memrchr(memchr_buf, 0x24, 1) != NULL) {
166 		warnx("TEST FAILED: memrchr unexpectedly found value (3), "
167 		    "found %p, expected %p", found, NULL);
168 		ret = B_FALSE;
169 	}
170 
171 	memchr_buf[1] = 0x24;
172 
173 	if (memchr(memchr_buf + 1, 0x23, 1) != NULL) {
174 		warnx("TEST FAILED: memchr unexpectedly found value (4), "
175 		    "found %p, expected %p", found, NULL);
176 		ret = B_FALSE;
177 	}
178 
179 	if (memrchr(memchr_buf + 1, 0x23, 1) != NULL) {
180 		warnx("TEST FAILED: memrchr unexpectedly found value (4), "
181 		    "found %p, expected %p", found, NULL);
182 		ret = B_FALSE;
183 	}
184 
185 	if (ret) {
186 		(void) printf("TEST PASSED: memchr() and memrchr() on "
187 		    "missing values\n");
188 	}
189 
190 	return (ret);
191 }
192 
193 static boolean_t
memchr_truncation(void)194 memchr_truncation(void)
195 {
196 	boolean_t ret = B_TRUE;
197 	const void *found;
198 	const void *targ;
199 
200 	(void) memset(memchr_buf, 0x42, memchr_buflen);
201 
202 	if ((found = memchr(memchr_buf, 0x42, memchr_buflen)) != memchr_buf) {
203 		warnx("TEST FAILED: memchr failed to find 0x42, found %p, "
204 		    "expected %p", found, memchr_buf);
205 		ret = B_FALSE;
206 	}
207 
208 	targ = &memchr_buf[memchr_buflen - 1];
209 
210 	if ((found = memrchr(memchr_buf, 0x42, memchr_buflen)) != targ) {
211 		warnx("TEST FAILED: memrchr failed to find 0x42, found %p, "
212 		    "expected %p", found, targ);
213 		ret = B_FALSE;
214 	}
215 
216 	if ((found = memchr(memchr_buf, 0x430042, memchr_buflen)) !=
217 	    memchr_buf) {
218 		warnx("TEST FAILED: memchr failed to find 0x42 with 0x430042, "
219 		    "found %p, expected %p", found, memchr_buf);
220 		ret = B_FALSE;
221 	}
222 
223 	if ((found = memrchr(memchr_buf, 0x430042, memchr_buflen)) != targ) {
224 		warnx("TEST FAILED: memrchr failed to find 0x42 with 0x430042, "
225 		    "found %p, expected %p", found, targ);
226 		ret = B_FALSE;
227 	}
228 
229 	/*
230 	 * -190 is -0xbe, which when cast to an unsigned char will be 0x42.
231 	 */
232 	if ((found = memchr(memchr_buf, -190, memchr_buflen)) != memchr_buf) {
233 		warnx("TEST FAILED: memchr failed to find 0x42 with -190, "
234 		    "found %p, expected %p", found, memchr_buf);
235 		ret = B_FALSE;
236 	}
237 
238 	if ((found = memrchr(memchr_buf, -190, memchr_buflen)) != targ) {
239 		warnx("TEST FAILED: memrchr failed to find 0x42 with -190, "
240 		    "found %p, expected %p", found, targ);
241 		ret = B_FALSE;
242 	}
243 
244 	if ((found = memchr(memchr_buf, -190, memchr_buflen)) != memchr_buf) {
245 		warnx("TEST FAILED: memchr failed to find 0x42 with -190, "
246 		    "found %p, expected %p", found, memchr_buf);
247 		ret = B_FALSE;
248 	}
249 
250 	if ((found = memrchr(memchr_buf, -190, memchr_buflen)) != targ) {
251 		warnx("TEST FAILED: memrchr failed to find 0x42 with -190, "
252 		    "found %p, expected %p", found, targ);
253 		ret = B_FALSE;
254 	}
255 
256 	if ((found = memchr(memchr_buf, 0x42424200, memchr_buflen)) != NULL) {
257 		warnx("TEST FAILED: memchr somehow found 0x42 with "
258 		    "0x42424200, found %p, expected NULL", found);
259 		ret = B_FALSE;
260 	}
261 
262 	if ((found = memrchr(memchr_buf, 0x42424200, memchr_buflen)) != NULL) {
263 		warnx("TEST FAILED: memrchr somehow found 0x42 with "
264 		    "0x42424200, found %p, expected NULL", found);
265 		ret = B_FALSE;
266 	}
267 
268 	if (ret) {
269 		(void) printf("TEST PASSED: truncated values\n");
270 	}
271 
272 	return (B_TRUE);
273 }
274 
275 int
main(void)276 main(void)
277 {
278 	int ret = EXIT_SUCCESS;
279 
280 	memchr_setup();
281 
282 	if (!memchr_basic())
283 		ret = EXIT_FAILURE;
284 	if (!memchr_notfound())
285 		ret = EXIT_FAILURE;
286 	if (!memchr_truncation())
287 		ret = EXIT_FAILURE;
288 
289 	if (ret == EXIT_SUCCESS) {
290 		(void) printf("All tests passed successfully\n");
291 	}
292 
293 	return (ret);
294 }
295