1 /* $OpenBSD: int.c,v 1.2 2020/07/14 16:40:04 kettenis Exp $ */ 2 /* 3 * Copyright (c) 2020 Ingo Schwarze <schwarze@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 * 17 * Test the %c, %lc, %s, and %ls conversion specifiers with all their 18 * modifiers, in particular with the minus flag, width, and maxbytes. 19 * Also verify that other flags do nothing useful. 20 */ 21 #include <err.h> 22 #include <stddef.h> 23 #include <stdint.h> 24 #include <stdio.h> 25 #include <string.h> 26 #include <unistd.h> 27 28 enum int_size { 29 S_CHAR, 30 S_SHORT, 31 S_INT, 32 S_LONG, 33 S_LL, 34 S_MAX, 35 S_PTR, 36 S_SIZE 37 }; 38 39 void ti(const char *, enum int_size, long long, const char *); 40 void tu(const char *, enum int_size, unsigned long long, const char *); 41 42 static int badret, badlen, badout; /* Error counters. */ 43 static int verbose; /* For debugging. */ 44 45 46 /* 47 * Print the signed integer i with the format fmt, 48 * check that the result matches what we want, 49 * and report and count the error on failure. 50 */ 51 void 52 ti(const char *fmt, enum int_size sz, long long i, const char *want) 53 { 54 char buf[32]; 55 size_t len; 56 int irc, happy; 57 58 happy = 1; 59 switch (sz) { 60 case S_CHAR: 61 irc = snprintf(buf, sizeof(buf), fmt, (signed char)i); 62 break; 63 case S_SHORT: 64 irc = snprintf(buf, sizeof(buf), fmt, (short)i); 65 break; 66 case S_INT: 67 irc = snprintf(buf, sizeof(buf), fmt, (int)i); 68 break; 69 case S_LONG: 70 irc = snprintf(buf, sizeof(buf), fmt, (long)i); 71 break; 72 case S_LL: 73 irc = snprintf(buf, sizeof(buf), fmt, (long long)i); 74 break; 75 case S_MAX: 76 irc = snprintf(buf, sizeof(buf), fmt, (intmax_t)i); 77 break; 78 case S_PTR: 79 irc = snprintf(buf, sizeof(buf), fmt, (ptrdiff_t)i); 80 break; 81 case S_SIZE: 82 irc = snprintf(buf, sizeof(buf), fmt, (ssize_t)i); 83 break; 84 default: 85 warnx("printf(\"%s\", %lld) unknown size code %d", 86 fmt, i, sz); 87 badret++; 88 return; 89 } 90 len = strlen(want); 91 if (irc < 0) { 92 warn("printf(\"%s\", %lld) returned %d", fmt, i, irc); 93 badret++; 94 return; 95 } 96 if ((unsigned long long)irc != len) { 97 warnx("printf(\"%s\", %lld) returned %d (expected %zu)", 98 fmt, i, irc, len); 99 badlen++; 100 happy = 0; 101 } 102 if (strcmp(buf, want) != 0) { 103 warnx("printf(\"%s\", %lld) wrote \"%s\" (expected \"%s\")", 104 fmt, i, buf, want); 105 badout++; 106 happy = 0; 107 } 108 if (verbose && happy) 109 warnx("printf(\"%s\", %lld) wrote \"%s\" length %d (OK)", 110 fmt, i, buf, irc); 111 } 112 113 /* 114 * Print the unsigned integer i with the format fmt, 115 * check that the result matches what we want, 116 * and report and count the error on failure. 117 */ 118 void 119 tu(const char *fmt, enum int_size sz, unsigned long long i, const char *want) 120 { 121 char buf[32]; 122 size_t len; 123 int irc, happy; 124 125 happy = 1; 126 switch (sz) { 127 case S_CHAR: 128 irc = snprintf(buf, sizeof(buf), fmt, (unsigned char)i); 129 break; 130 case S_SHORT: 131 irc = snprintf(buf, sizeof(buf), fmt, (unsigned short)i); 132 break; 133 case S_INT: 134 irc = snprintf(buf, sizeof(buf), fmt, (unsigned int)i); 135 break; 136 case S_LONG: 137 irc = snprintf(buf, sizeof(buf), fmt, (unsigned long)i); 138 break; 139 case S_LL: 140 irc = snprintf(buf, sizeof(buf), fmt, (unsigned long long)i); 141 break; 142 case S_MAX: 143 irc = snprintf(buf, sizeof(buf), fmt, (uintmax_t)i); 144 break; 145 case S_SIZE: 146 irc = snprintf(buf, sizeof(buf), fmt, (size_t)i); 147 break; 148 default: 149 warnx("printf(\"%s\", %llu) unknown size code %d", 150 fmt, i, sz); 151 badret++; 152 return; 153 } 154 len = strlen(want); 155 if (irc < 0) { 156 warn("printf(\"%s\", %llu) returned %d", fmt, i, irc); 157 badret++; 158 return; 159 } 160 if ((unsigned long long)irc != len) { 161 warnx("printf(\"%s\", %llu) returned %d (expected %zu)", 162 fmt, i, irc, len); 163 badlen++; 164 happy = 0; 165 } 166 if (strcmp(buf, want) != 0) { 167 warnx("printf(\"%s\", %llu) wrote \"%s\" (expected \"%s\")", 168 fmt, i, buf, want); 169 badout++; 170 happy = 0; 171 } 172 if (verbose && happy) 173 warnx("printf(\"%s\", %llu) wrote \"%s\" length %d (OK)", 174 fmt, i, buf, irc); 175 } 176 177 int 178 main(int argc, char *argv[]) 179 { 180 int badarg, picky; 181 int ch; 182 183 badarg = picky = 0; 184 while ((ch = getopt(argc, argv, "pv")) != -1) { 185 switch (ch) { 186 case 'p': 187 picky = 1; 188 break; 189 case 'v': 190 verbose = 1; 191 break; 192 default: 193 badarg = 1; 194 break; 195 } 196 } 197 argc -= optind; 198 argv += optind; 199 if (argc > 0) { 200 warnx("unexpected argument \"%s\"", *argv); 201 badarg = 1; 202 } 203 if (badarg) { 204 fputs("usage: int [-pv]\n", stderr); 205 return 1; 206 } 207 208 /* 209 * Valid use cases of %d. 210 */ 211 212 ti("<%d>", S_INT, 0, "<0>"); 213 ti("<%d>", S_INT, 1, "<1>"); 214 ti("<%d>", S_INT, -1, "<-1>"); 215 ti("<%d>", S_INT, 42, "<42>"); 216 ti("<%d>", S_INT, INT32_MAX, "<2147483647>"); 217 ti("<%d>", S_INT, INT32_MIN, "<-2147483648>"); 218 ti("<% d>", S_INT, 42, "< 42>"); 219 ti("<% d>", S_INT, -42, "<-42>"); 220 ti("<%+d>", S_INT, 42, "<+42>"); 221 ti("<%+d>", S_INT, -42, "<-42>"); 222 ti("<% +d>", S_INT, 42, "<+42>"); 223 ti("<% +d>", S_INT, -42, "<-42>"); 224 ti("<%-4d>", S_INT, 42, "<42 >"); 225 ti("<% -4d>", S_INT, 42, "< 42 >"); 226 ti("<%+-4d>", S_INT, 42, "<+42 >"); 227 ti("<%04d>", S_INT, 42, "<0042>"); 228 ti("<%-04d>", S_INT, 42, "<42 >"); 229 ti("<% 04d>", S_INT, 42, "< 042>"); 230 ti("<%+04d>", S_INT, 42, "<+042>"); 231 ti("<%4.3d>", S_INT, 42, "< 042>"); 232 ti("<% 5.3d>", S_INT, 42, "< 042>"); 233 ti("<%+5.3d>", S_INT, 42, "< +042>"); 234 ti("<%-4.3d>", S_INT, 42, "<042 >"); 235 ti("<%04.3d>", S_INT, 42, "< 042>"); 236 237 ti("<%hhd>", S_CHAR, INT8_MIN, "<-128>"); 238 ti("<%hhd>", S_CHAR, -1, "<-1>"); 239 ti("<%hhd>", S_CHAR, 0, "<0>"); 240 ti("<%hhd>", S_CHAR, 1, "<1>"); 241 ti("<%hhd>", S_CHAR, INT8_MAX, "<127>"); 242 ti("<%+.4hhd>", S_CHAR, 42, "<+0042>"); 243 ti("<% 04hhd>", S_CHAR, 42, "< 042>"); 244 245 ti("<%hd>", S_SHORT, INT16_MIN, "<-32768>"); 246 ti("<%hd>", S_SHORT, -1, "<-1>"); 247 ti("<%hd>", S_SHORT, 0, "<0>"); 248 ti("<%hd>", S_SHORT, 1, "<1>"); 249 ti("<%hd>", S_SHORT, INT16_MAX, "<32767>"); 250 251 ti("<%hld>", S_LONG, INT32_MIN, "<-2147483648>"); 252 ti("<%hld>", S_LONG, -1, "<-1>"); 253 ti("<%hld>", S_LONG, 0, "<0>"); 254 ti("<%hld>", S_LONG, 1, "<1>"); 255 ti("<%hld>", S_LONG, INT32_MAX, "<2147483647>"); 256 257 ti("<%hlld>", S_LL, INT64_MIN, "<-9223372036854775808>"); 258 ti("<%hlld>", S_LL, -1, "<-1>"); 259 ti("<%hlld>", S_LL, 0, "<0>"); 260 ti("<%hlld>", S_LL, 1, "<1>"); 261 ti("<%hlld>", S_LL, INT64_MAX, "<9223372036854775807>"); 262 ti("<%h-19lld>", S_LL, 123456789123456789LL, "<123456789123456789 >"); 263 264 ti("<%hjd>", S_MAX, INT64_MIN, "<-9223372036854775808>"); 265 ti("<%hjd>", S_MAX, -1, "<-1>"); 266 ti("<%hjd>", S_MAX, 0, "<0>"); 267 ti("<%hjd>", S_MAX, 1, "<1>"); 268 ti("<%hjd>", S_MAX, INT64_MAX, "<9223372036854775807>"); 269 270 ti("<%htd>", S_PTR, INT32_MIN, "<-2147483648>"); 271 ti("<%htd>", S_PTR, -1, "<-1>"); 272 ti("<%htd>", S_PTR, 0, "<0>"); 273 ti("<%htd>", S_PTR, 1, "<1>"); 274 ti("<%htd>", S_PTR, INT32_MAX, "<2147483647>"); 275 276 ti("<%hzd>", S_SIZE, INT32_MIN, "<-2147483648>"); 277 ti("<%hzd>", S_SIZE, -1, "<-1>"); 278 ti("<%hzd>", S_SIZE, 0, "<0>"); 279 ti("<%hzd>", S_SIZE, 1, "<1>"); 280 ti("<%hzd>", S_SIZE, INT32_MAX, "<2147483647>"); 281 282 /* 283 * Undefined behaviour of %d. 284 * Do not test by default to avoid noise. 285 * But provide the tests anyway to help track down 286 * unintended changes of behaviour when needed. 287 */ 288 289 if (picky) { 290 ti("<%#d>", S_INT, 42, "<42>"); 291 ti("<%Ld>", S_INT, 42, "<42>"); 292 } 293 294 /* 295 * Valid use cases of %u. 296 */ 297 298 tu("<%u>", S_INT, 0, "<0>"); 299 tu("<%u>", S_INT, 1, "<1>"); 300 tu("<%u>", S_INT, 42, "<42>"); 301 tu("<%u>", S_INT, UINT32_MAX, "<4294967295>"); 302 tu("<%-4u>", S_INT, 42, "<42 >"); 303 tu("<%04u>", S_INT, 42, "<0042>"); 304 tu("<%-04u>", S_INT, 42, "<42 >"); 305 tu("<%4.3u>", S_INT, 42, "< 042>"); 306 tu("<%-4.3u>", S_INT, 42, "<042 >"); 307 tu("<%04.3u>", S_INT, 42, "< 042>"); 308 309 tu("<%hhu>", S_CHAR, 0, "<0>"); 310 tu("<%hhu>", S_CHAR, UINT8_MAX, "<255>"); 311 tu("<%hhu>", S_CHAR, -1, "<255>"); 312 tu("<%-4hhu>", S_CHAR, 42, "<42 >"); 313 tu("<%04hhu>", S_CHAR, 42, "<0042>"); 314 315 tu("<%hu>", S_SHORT, 0, "<0>"); 316 tu("<%hu>", S_SHORT, UINT16_MAX, "<65535>"); 317 tu("<%hlu>", S_LONG, 0, "<0>"); 318 tu("<%hlu>", S_LONG, UINT32_MAX, "<4294967295>"); 319 tu("<%hllu>", S_LL, 0, "<0>"); 320 tu("<%hllu>", S_LL, UINT64_MAX, "<18446744073709551615>"); 321 tu("<%h-19llu>", S_LL, 123456789123456789ULL, "<123456789123456789 >"); 322 tu("<%hju>", S_MAX, 0, "<0>"); 323 tu("<%hju>", S_MAX, UINT64_MAX, "<18446744073709551615>"); 324 tu("<%hzu>", S_SIZE, 0, "<0>"); 325 tu("<%hzu>", S_SIZE, UINT32_MAX, "<4294967295>"); 326 327 tu("<%hho>", S_CHAR, 0, "<0>"); 328 tu("<%#hho>", S_CHAR, 0, "<0>"); 329 tu("<%hho>", S_CHAR, UINT8_MAX, "<377>"); 330 tu("<%#hho>", S_CHAR, UINT8_MAX, "<0377>"); 331 tu("<%hho>", S_CHAR, -1, "<377>"); 332 tu("<%#hho>", S_CHAR, -1, "<0377>"); 333 tu("<%-4hho>", S_CHAR, 42, "<52 >"); 334 tu("<%#-4hho>", S_CHAR, 42, "<052 >"); 335 tu("<%04hho>", S_CHAR, 42, "<0052>"); 336 tu("<%#04hho>", S_CHAR, 42, "<0052>"); 337 338 tu("<%hx>", S_SHORT, 0, "<0>"); 339 tu("<%#hx>", S_SHORT, 0, "<0>"); 340 tu("<%hX>", S_SHORT, 0, "<0>"); 341 tu("<%#hX>", S_SHORT, 0, "<0>"); 342 tu("<%hx>", S_SHORT, 1, "<1>"); 343 tu("<%#hx>", S_SHORT, 1, "<0x1>"); 344 tu("<%hX>", S_SHORT, 1, "<1>"); 345 tu("<%#hX>", S_SHORT, 1, "<0X1>"); 346 tu("<%hx>", S_SHORT, 10, "<a>"); 347 tu("<%#hx>", S_SHORT, 10, "<0xa>"); 348 tu("<%hX>", S_SHORT, 10, "<A>"); 349 tu("<%#hX>", S_SHORT, 10, "<0XA>"); 350 tu("<%hx>", S_SHORT, UINT16_MAX, "<ffff>"); 351 tu("<%#hx>", S_SHORT, UINT16_MAX, "<0xffff>"); 352 tu("<%hX>", S_SHORT, UINT16_MAX, "<FFFF>"); 353 tu("<%#hX>", S_SHORT, UINT16_MAX, "<0XFFFF>"); 354 355 /* 356 * Undefined behaviour of %u. 357 */ 358 359 if (picky) { 360 tu("<%#u>", S_INT, 42, "<42>"); 361 tu("<% u>", S_INT, 42, "<42>"); 362 tu("<%+u>", S_INT, 42, "<42>"); 363 tu("<%Lu>", S_INT, 42, "<42>"); 364 } 365 366 /* 367 * Summarize the results. 368 */ 369 370 if (badret + badlen + badout) 371 errx(1, "ERRORS: %d fail + %d mismatch (incl. %d bad length)", 372 badret, badout, badlen); 373 else if (verbose) 374 warnx("SUCCESS"); 375 return 0; 376 } 377