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 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 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 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 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 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