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; 40 int pg = getpagesize(); 41 void *addr; 42 43 if (pg <= 0) { 44 err(EXIT_FAILURE, "failed to get system page size"); 45 } else { 46 pgsz = pg; 47 } 48 49 addr = mmap(NULL, 3 * pgsz, PROT_READ | PROT_WRITE, 50 MAP_PRIVATE | MAP_ANON, -1, 0); 51 if (addr == MAP_FAILED) { 52 err(EXIT_FAILURE, "failed to mmap %zu bytes", 3 * pgsz); 53 } 54 55 memchr_buf = (uint8_t *)addr + pgsz; 56 memchr_buflen = pgsz; 57 58 if (mprotect(addr, pgsz, PROT_NONE) != 0) { 59 err(EXIT_FAILURE, "failed to protect leading PROT_NONE guard " 60 "at %p", addr); 61 } 62 63 addr = (uint8_t *)addr + 2 * pgsz; 64 if (mprotect(addr, pgsz, PROT_NONE) != 0) { 65 err(EXIT_FAILURE, "failed to protect trailing PROT_NONE guard " 66 "at %p", addr); 67 } 68 } 69 70 static boolean_t 71 memchr_basic(void) 72 { 73 boolean_t ret = B_TRUE; 74 const void *targ; 75 const void *found; 76 77 (void) memset(memchr_buf, 0, memchr_buflen); 78 memchr_buf[0] = 'r'; 79 80 if ((found = memchr(memchr_buf, 'r', memchr_buflen)) != memchr_buf) { 81 warnx("TEST FAILED: memchr failed to find 'r' (1), found %p, " 82 "expected %p", found, memchr_buf); 83 ret = B_FALSE; 84 } 85 86 if ((found = memrchr(memchr_buf, 'r', memchr_buflen)) != memchr_buf) { 87 warnx("TEST FAILED: memrchr failed to find 'r' (1), found %p, " 88 "expected %p", found, memchr_buf); 89 ret = B_FALSE; 90 } 91 92 memchr_buf[memchr_buflen - 1] = 'r'; 93 targ = &memchr_buf[memchr_buflen - 1]; 94 95 if ((found = memchr(memchr_buf, 'r', memchr_buflen)) != memchr_buf) { 96 warnx("TEST FAILED: memchr failed to find 'r' (2), found %p, " 97 "expected %p", found, memchr_buf); 98 ret = B_FALSE; 99 } 100 101 if ((found = memrchr(memchr_buf, 'r', memchr_buflen)) != targ) { 102 warnx("TEST FAILED: memrchr failed to find 'r' (2), found %p, " 103 "expected %p", found, targ); 104 warnx("TEST FAILED: memchr failed to find 'r'"); 105 ret = B_FALSE; 106 } 107 108 memchr_buf[0] = 0; 109 110 if ((found = memchr(memchr_buf, 'r', memchr_buflen)) != targ) { 111 warnx("TEST FAILED: memchr failed to find 'r' (3), found %p, " 112 "expected %p", found, targ); 113 ret = B_FALSE; 114 } 115 116 if ((found = memrchr(memchr_buf, 'r', memchr_buflen)) != targ) { 117 warnx("TEST FAILED: memrchr failed to find 'r' (3), found %p, " 118 "expected %p", found, targ); 119 ret = B_FALSE; 120 } 121 122 if (ret) { 123 (void) printf("TEST PASSED: basic memchr() and memrchr()\n"); 124 } 125 return (ret); 126 } 127 128 static boolean_t 129 memchr_notfound(void) 130 { 131 boolean_t ret = B_TRUE; 132 const void *found; 133 134 (void) memset(memchr_buf, 0x23, memchr_buflen); 135 136 if ((found = memchr(memchr_buf, 0, memchr_buflen)) != NULL) { 137 warnx("TEST FAILED: memchr unexpectedly found value (1), " 138 "found %p, expected %p", found, NULL); 139 ret = B_FALSE; 140 } 141 142 if (memrchr(memchr_buf, 0, memchr_buflen) != NULL) { 143 warnx("TEST FAILED: memrchr unexpectedly found value (1), " 144 "found %p, expected %p", found, NULL); 145 ret = B_FALSE; 146 } 147 148 if (memchr(memchr_buf, 0x24, memchr_buflen) != NULL) { 149 warnx("TEST FAILED: memchr unexpectedly found value (2), " 150 "found %p, expected %p", found, NULL); 151 ret = B_FALSE; 152 } 153 154 if (memrchr(memchr_buf, 0x24, memchr_buflen) != NULL) { 155 warnx("TEST FAILED: memrchr unexpectedly found value (2), " 156 "found %p, expected %p", found, NULL); 157 ret = B_FALSE; 158 } 159 160 memchr_buf[1] = 0x24; 161 162 if (memchr(memchr_buf, 0x24, 1) != NULL) { 163 warnx("TEST FAILED: memchr unexpectedly found value (3), " 164 "found %p, expected %p", found, NULL); 165 ret = B_FALSE; 166 } 167 168 if (memrchr(memchr_buf, 0x24, 1) != NULL) { 169 warnx("TEST FAILED: memrchr unexpectedly found value (3), " 170 "found %p, expected %p", found, NULL); 171 ret = B_FALSE; 172 } 173 174 memchr_buf[1] = 0x24; 175 176 if (memchr(memchr_buf + 1, 0x23, 1) != NULL) { 177 warnx("TEST FAILED: memchr unexpectedly found value (4), " 178 "found %p, expected %p", found, NULL); 179 ret = B_FALSE; 180 } 181 182 if (memrchr(memchr_buf + 1, 0x23, 1) != NULL) { 183 warnx("TEST FAILED: memrchr unexpectedly found value (4), " 184 "found %p, expected %p", found, NULL); 185 ret = B_FALSE; 186 } 187 188 if (ret) { 189 (void) printf("TEST PASSED: memchr() and memrchr() on " 190 "missing values\n"); 191 } 192 193 return (ret); 194 } 195 196 static boolean_t 197 memchr_truncation(void) 198 { 199 boolean_t ret = B_TRUE; 200 const void *found; 201 const void *targ; 202 203 (void) memset(memchr_buf, 0x42, memchr_buflen); 204 205 if ((found = memchr(memchr_buf, 0x42, memchr_buflen)) != memchr_buf) { 206 warnx("TEST FAILED: memchr failed to find 0x42, found %p, " 207 "expected %p", found, memchr_buf); 208 ret = B_FALSE; 209 } 210 211 targ = &memchr_buf[memchr_buflen - 1]; 212 213 if ((found = memrchr(memchr_buf, 0x42, memchr_buflen)) != targ) { 214 warnx("TEST FAILED: memrchr failed to find 0x42, found %p, " 215 "expected %p", found, targ); 216 ret = B_FALSE; 217 } 218 219 if ((found = memchr(memchr_buf, 0x430042, memchr_buflen)) != 220 memchr_buf) { 221 warnx("TEST FAILED: memchr failed to find 0x42 with 0x430042, " 222 "found %p, expected %p", found, memchr_buf); 223 ret = B_FALSE; 224 } 225 226 if ((found = memrchr(memchr_buf, 0x430042, memchr_buflen)) != targ) { 227 warnx("TEST FAILED: memrchr failed to find 0x42 with 0x430042, " 228 "found %p, expected %p", found, targ); 229 ret = B_FALSE; 230 } 231 232 /* 233 * -190 is -0xbe, which when cast to an unsigned char will be 0x42. 234 */ 235 if ((found = memchr(memchr_buf, -190, memchr_buflen)) != memchr_buf) { 236 warnx("TEST FAILED: memchr failed to find 0x42 with -190, " 237 "found %p, expected %p", found, memchr_buf); 238 ret = B_FALSE; 239 } 240 241 if ((found = memrchr(memchr_buf, -190, memchr_buflen)) != targ) { 242 warnx("TEST FAILED: memrchr failed to find 0x42 with -190, " 243 "found %p, expected %p", found, targ); 244 ret = B_FALSE; 245 } 246 247 if ((found = memchr(memchr_buf, -190, memchr_buflen)) != memchr_buf) { 248 warnx("TEST FAILED: memchr failed to find 0x42 with -190, " 249 "found %p, expected %p", found, memchr_buf); 250 ret = B_FALSE; 251 } 252 253 if ((found = memrchr(memchr_buf, -190, memchr_buflen)) != targ) { 254 warnx("TEST FAILED: memrchr failed to find 0x42 with -190, " 255 "found %p, expected %p", found, targ); 256 ret = B_FALSE; 257 } 258 259 if ((found = memchr(memchr_buf, 0x42424200, memchr_buflen)) != NULL) { 260 warnx("TEST FAILED: memchr somehow found 0x42 with " 261 "0x42424200, found %p, expected NULL", found); 262 ret = B_FALSE; 263 } 264 265 if ((found = memrchr(memchr_buf, 0x42424200, memchr_buflen)) != NULL) { 266 warnx("TEST FAILED: memrchr somehow found 0x42 with " 267 "0x42424200, found %p, expected NULL", found); 268 ret = B_FALSE; 269 } 270 271 if (ret) { 272 (void) printf("TEST PASSED: truncated values\n"); 273 } 274 275 return (B_TRUE); 276 } 277 278 int 279 main(void) 280 { 281 int ret = EXIT_SUCCESS; 282 283 memchr_setup(); 284 285 if (!memchr_basic()) 286 ret = EXIT_FAILURE; 287 if (!memchr_notfound()) 288 ret = EXIT_FAILURE; 289 if (!memchr_truncation()) 290 ret = EXIT_FAILURE; 291 292 if (ret == EXIT_SUCCESS) { 293 (void) printf("All tests passed successfully\n"); 294 } 295 296 return (ret); 297 } 298