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