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