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 2023 Oxide Computer Company 14 */ 15 16 /* 17 * Basic tests for the ilstr string handling routines. 18 */ 19 20 #include <stdlib.h> 21 #include <stdio.h> 22 #include <string.h> 23 #include <strings.h> 24 #include <errno.h> 25 #include <upanic.h> 26 #include <sys/ilstr.h> 27 #include <sys/sysmacros.h> 28 #include <sys/debug.h> 29 30 typedef enum ilstr_test_types { 31 ITT_STD = 0x01, 32 ITT_PRE = 0x02, 33 } ilstr_test_types_t; 34 35 #define ITT_ALL (ITT_STD | ITT_PRE) 36 37 typedef struct ilstr_test { 38 char *ist_name; 39 int (*ist_func)(ilstr_t *ils); 40 uint_t ist_trials; 41 ilstr_test_types_t ist_types; 42 } ilstr_test_t; 43 44 #define PREALLOC_SZ 1024 45 static char ilsbuf[PREALLOC_SZ]; 46 47 const char * 48 _umem_debug_init(void) 49 { 50 return ("default,verbose"); 51 } 52 53 const char * 54 _umem_logging_init(void) 55 { 56 return ("transaction,contents,fail"); 57 } 58 59 int 60 ist_empty(ilstr_t *ils) 61 { 62 VERIFY3U(ilstr_len(ils), ==, 0); 63 VERIFY(ilstr_cstr(ils) != NULL); 64 VERIFY3U(ilstr_cstr(ils)[0], ==, '\0'); 65 VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK); 66 67 return (0); 68 } 69 70 int 71 ist_prealloc_toobig(ilstr_t *ils) 72 { 73 for (uint_t n = 0; n < PREALLOC_SZ - 1; n++) { 74 ilstr_append_str(ils, "A"); 75 } 76 VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK); 77 78 ilstr_append_str(ils, "A"); 79 VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_NOMEM); 80 81 ilstr_append_str(ils, "A"); 82 VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_NOMEM); 83 84 ilstr_reset(ils); 85 86 ilstr_append_str(ils, "B"); 87 VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK); 88 VERIFY(strcmp(ilstr_cstr(ils), "B") == 0); 89 90 return (0); 91 } 92 93 int 94 ist_huge(ilstr_t *ils) 95 { 96 /* 97 * Build a 26MB string by repeating the alphabet over and over: 98 */ 99 uint_t target = 26 * 1024 * 1024; 100 101 for (uint_t n = 0; n < target / 26; n++) { 102 ilstr_append_str(ils, "abcdefghijklmnopqrstuvwxyz"); 103 104 if (ilstr_errno(ils) == ILSTR_ERROR_NOMEM) { 105 return (ENOMEM); 106 } 107 VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK); 108 } 109 110 VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK); 111 VERIFY3U(ilstr_len(ils), ==, target); 112 113 return (0); 114 } 115 116 int 117 ist_printf_1(ilstr_t *ils) 118 { 119 const char *want = "a\nb\n1000\ntest string\n"; 120 121 ilstr_aprintf(ils, "a\nb\n%u\n%s\n", 1000, "test string"); 122 VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK); 123 VERIFY(strcmp(ilstr_cstr(ils), want) == 0); 124 125 return (0); 126 } 127 128 int 129 ist_printf_2(ilstr_t *ils) 130 { 131 int r = 0; 132 133 const char *lorem = "Lorem ipsum dolor sit amet, consectetur " 134 "adipiscing elit, sed do eiusmod tempor incididunt ut labore " 135 "et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud " 136 "exercitation ullamco laboris nisi ut aliquip ex ea commodo " 137 "consequat."; 138 char *want; 139 140 if (asprintf(&want, "%s\n\tnumber 1\n%s\n\n%s\n number 100000000\n", 141 lorem, lorem, lorem) < 0) { 142 return (errno); 143 } 144 145 ilstr_aprintf(ils, "%s\n\t", lorem); 146 ilstr_append_str(ils, "number"); 147 ilstr_aprintf(ils, " %u\n%s\n\n", 1, lorem); 148 ilstr_append_str(ils, lorem); 149 ilstr_aprintf(ils, "\n number %lld\n", (long long)100000000); 150 151 VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK); 152 if (strcmp(ilstr_cstr(ils), want) != 0) { 153 printf("want: %s\n", want); 154 printf("got: %s\n", ilstr_cstr(ils)); 155 r = ENOENT; 156 } 157 158 free(want); 159 160 return (r); 161 } 162 163 int 164 ist_resets(ilstr_t *ils) 165 { 166 VERIFY(strcmp(ilstr_cstr(ils), "") == 0); 167 168 ilstr_reset(ils); 169 VERIFY(strcmp(ilstr_cstr(ils), "") == 0); 170 171 ilstr_append_str(ils, "abc"); 172 VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK); 173 VERIFY(strcmp(ilstr_cstr(ils), "abc") == 0); 174 175 ilstr_append_str(ils, "def"); 176 VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK); 177 VERIFY(strcmp(ilstr_cstr(ils), "abcdef") == 0); 178 179 ilstr_reset(ils); 180 VERIFY(strcmp(ilstr_cstr(ils), "") == 0); 181 182 ilstr_append_str(ils, "xyz"); 183 VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK); 184 VERIFY(strcmp(ilstr_cstr(ils), "xyz") == 0); 185 186 ilstr_reset(ils); 187 VERIFY(strcmp(ilstr_cstr(ils), "") == 0); 188 189 return (0); 190 } 191 192 int 193 ist_random(ilstr_t *ils) 194 { 195 char *work; 196 uint_t target = 256 + arc4random_uniform(1024 - 256); 197 198 printf(" - target string length %u\n", target); 199 if ((work = calloc(1, 1024 + 1)) == NULL) { 200 return (errno); 201 } 202 203 VERIFY3U(ilstr_len(ils), ==, 0); 204 VERIFY3U(ilstr_cstr(ils)[0], ==, '\0'); 205 VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK); 206 207 for (uint_t n = 0; n < target; n++) { 208 char c[2] = { arc4random_uniform('Z' - 'A') + 'A', '\0' }; 209 210 work[n] = c[0]; 211 ilstr_append_str(ils, c); 212 213 VERIFY3U(ilstr_errno(ils), ==, ILSTR_ERROR_OK); 214 VERIFY3U(ilstr_len(ils), ==, n + 1); 215 VERIFY(strcmp(ilstr_cstr(ils), work) == 0); 216 } 217 218 VERIFY3U(ilstr_len(ils), ==, target); 219 VERIFY(strcmp(ilstr_cstr(ils), work) == 0); 220 printf(" - final string: %s\n", work); 221 222 free(work); 223 return (0); 224 } 225 226 uint_t 227 ist_drive_test(const ilstr_test_t *ist) 228 { 229 uint_t nfails = 0; 230 int r; 231 ilstr_t ils; 232 233 for (uint_t n = 0; n < ist->ist_trials; n++) { 234 if (ist->ist_types & ITT_STD) { 235 ilstr_init(&ils, 0); 236 printf("STD[%s]... run %d\n", ist->ist_name, n); 237 if ((r = ist->ist_func(&ils)) != 0) { 238 (void) fprintf(stderr, 239 "TEST FAILED: STD[%s]: %s\n", 240 ist->ist_name, strerror(r)); 241 nfails += 1; 242 } else { 243 printf("TEST PASSED: STD[%s]\n", 244 ist->ist_name); 245 } 246 ilstr_fini(&ils); 247 printf("\n"); 248 } 249 250 if (ist->ist_types & ITT_PRE) { 251 ilstr_init_prealloc(&ils, ilsbuf, sizeof (ilsbuf)); 252 printf("PRE[%s]... run %d\n", ist->ist_name, n); 253 if ((r = ist->ist_func(&ils)) != 0) { 254 (void) fprintf(stderr, 255 "TEST FAILED: PRE[%s]: %s\n", 256 ist->ist_name, strerror(r)); 257 nfails += 1; 258 } else { 259 printf("TEST PASSED: PRE[%s]\n", 260 ist->ist_name); 261 } 262 ilstr_fini(&ils); 263 printf("\n"); 264 } 265 } 266 267 return (nfails); 268 } 269 270 static const ilstr_test_t ilstr_tests[] = { 271 { "empty", ist_empty, 1, ITT_ALL }, 272 { "resets", ist_resets, 1, ITT_ALL }, 273 { "printf-1", ist_printf_1, 1, ITT_ALL }, 274 { "printf-2", ist_printf_2, 1, ITT_ALL }, 275 { "prealloc_toobig", ist_prealloc_toobig, 1, ITT_PRE }, 276 /* 277 * Run the random generation test many times, as an attempt at fuzzing: 278 */ 279 { "random", ist_random, 1000, ITT_ALL }, 280 /* 281 * Run the huge allocation test some number of times to try to make 282 * sure we exercise allocation and free of different buffer sizes, and 283 * to increase the likelihood of detecting any heap corruption: 284 */ 285 { "huge", ist_huge, 100, ITT_STD }, 286 }; 287 288 int 289 main(void) 290 { 291 uint_t nfails = 0; 292 293 for (uint_t i = 0; i < ARRAY_SIZE(ilstr_tests); i++) { 294 nfails += ist_drive_test(&ilstr_tests[i]); 295 } 296 297 char *aoe; 298 if ((aoe = getenv("PANIC_ON_EXIT")) != NULL && strcmp(aoe, "1") == 0) { 299 const char *msg = "PANIC_ON_EXIT set; panicking for findleaks"; 300 upanic(msg, strlen(msg)); 301 } 302 303 return (nfails == 0 ? 0 : 1); 304 } 305