diff options
-rw-r--r-- | regress/lib/libc/printf/Makefile | 4 | ||||
-rw-r--r-- | regress/lib/libc/printf/int.c | 376 |
2 files changed, 378 insertions, 2 deletions
diff --git a/regress/lib/libc/printf/Makefile b/regress/lib/libc/printf/Makefile index fba2bd105fc..5125fc64da5 100644 --- a/regress/lib/libc/printf/Makefile +++ b/regress/lib/libc/printf/Makefile @@ -1,6 +1,6 @@ -# $OpenBSD: Makefile,v 1.2 2020/07/08 01:18:04 schwarze Exp $ +# $OpenBSD: Makefile,v 1.3 2020/07/09 01:49:15 schwarze Exp $ -PROGS = fp string +PROGS = fp int string REGRESS_TARGETS = ${PROGS:S/^/run-regress-/} diff --git a/regress/lib/libc/printf/int.c b/regress/lib/libc/printf/int.c new file mode 100644 index 00000000000..d6ecb7a98de --- /dev/null +++ b/regress/lib/libc/printf/int.c @@ -0,0 +1,376 @@ +/* $OpenBSD: int.c,v 1.1 2020/07/09 01:49:15 schwarze Exp $ */ +/* + * Copyright (c) 2020 Ingo Schwarze <schwarze@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Test the %c, %lc, %s, and %ls conversion specifiers with all their + * modifiers, in particular with the minus flag, width, and maxbytes. + * Also verify that other flags do nothing useful. + */ +#include <err.h> +#include <stddef.h> +#include <stdint.h> +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +enum int_size { + S_CHAR, + S_SHORT, + S_INT, + S_LONG, + S_LL, + S_MAX, + S_PTR, + S_SIZE +}; + +void ti(const char *, enum int_size, long long, const char *); +void tu(const char *, enum int_size, unsigned long long, const char *); + +static int badret, badlen, badout; /* Error counters. */ +static int verbose; /* For debugging. */ + + +/* + * Print the signed integer i with the format fmt, + * check that the result matches what we want, + * and report and count the error on failure. + */ +void +ti(const char *fmt, enum int_size sz, long long i, const char *want) +{ + char buf[32]; + size_t len; + int irc, happy; + + happy = 1; + switch (sz) { + case S_CHAR: + irc = snprintf(buf, sizeof(buf), fmt, (signed char)i); + break; + case S_SHORT: + irc = snprintf(buf, sizeof(buf), fmt, (short)i); + break; + case S_INT: + irc = snprintf(buf, sizeof(buf), fmt, (int)i); + break; + case S_LONG: + irc = snprintf(buf, sizeof(buf), fmt, (long)i); + break; + case S_LL: + irc = snprintf(buf, sizeof(buf), fmt, (long long)i); + break; + case S_MAX: + irc = snprintf(buf, sizeof(buf), fmt, (intmax_t)i); + break; + case S_PTR: + irc = snprintf(buf, sizeof(buf), fmt, (ptrdiff_t)i); + break; + case S_SIZE: + irc = snprintf(buf, sizeof(buf), fmt, (ssize_t)i); + break; + default: + warnx("printf(\"%s\", %lld) unknown size code %d", + fmt, i, sz); + badret++; + return; + } + len = strlen(want); + if (irc < 0) { + warn("printf(\"%s\", %lld) returned %d", fmt, i, irc); + badret++; + return; + } + if ((unsigned long long)irc != len) { + warnx("printf(\"%s\", %lld) returned %d (expected %zu)", + fmt, i, irc, len); + badlen++; + happy = 0; + } + if (strcmp(buf, want) != 0) { + warnx("printf(\"%s\", %lld) wrote \"%s\" (expected \"%s\")", + fmt, i, buf, want); + badout++; + happy = 0; + } + if (verbose && happy) + warnx("printf(\"%s\", %lld) wrote \"%s\" length %d (OK)", + fmt, i, buf, irc); +} + +/* + * Print the unsigned integer i with the format fmt, + * check that the result matches what we want, + * and report and count the error on failure. + */ +void +tu(const char *fmt, enum int_size sz, unsigned long long i, const char *want) +{ + char buf[32]; + size_t len; + int irc, happy; + + happy = 1; + switch (sz) { + case S_CHAR: + irc = snprintf(buf, sizeof(buf), fmt, (unsigned char)i); + break; + case S_SHORT: + irc = snprintf(buf, sizeof(buf), fmt, (unsigned short)i); + break; + case S_INT: + irc = snprintf(buf, sizeof(buf), fmt, (unsigned int)i); + break; + case S_LONG: + irc = snprintf(buf, sizeof(buf), fmt, (unsigned long)i); + break; + case S_LL: + irc = snprintf(buf, sizeof(buf), fmt, (unsigned long long)i); + break; + case S_MAX: + irc = snprintf(buf, sizeof(buf), fmt, (uintmax_t)i); + break; + case S_SIZE: + irc = snprintf(buf, sizeof(buf), fmt, (size_t)i); + break; + default: + warnx("printf(\"%s\", %llu) unknown size code %d", + fmt, i, sz); + badret++; + return; + } + len = strlen(want); + if (irc < 0) { + warn("printf(\"%s\", %llu) returned %d", fmt, i, irc); + badret++; + return; + } + if ((unsigned long long)irc != len) { + warnx("printf(\"%s\", %llu) returned %d (expected %zu)", + fmt, i, irc, len); + badlen++; + happy = 0; + } + if (strcmp(buf, want) != 0) { + warnx("printf(\"%s\", %llu) wrote \"%s\" (expected \"%s\")", + fmt, i, buf, want); + badout++; + happy = 0; + } + if (verbose && happy) + warnx("printf(\"%s\", %llu) wrote \"%s\" length %d (OK)", + fmt, i, buf, irc); +} + +int +main(int argc, char *argv[]) +{ + int badarg, picky; + char ch; + + badarg = picky = 0; + while ((ch = getopt(argc, argv, "pv")) != -1) { + switch (ch) { + case 'p': + picky = 1; + break; + case 'v': + verbose = 1; + break; + default: + badarg = 1; + break; + } + } + argc -= optind; + argv += optind; + if (argc > 0) { + warnx("unexpected argument \"%s\"", *argv); + badarg = 1; + } + if (badarg) { + fputs("usage: int [-pv]\n", stderr); + return 1; + } + + /* + * Valid use cases of %d. + */ + + ti("<%d>", S_INT, 0, "<0>"); + ti("<%d>", S_INT, 1, "<1>"); + ti("<%d>", S_INT, -1, "<-1>"); + ti("<%d>", S_INT, 42, "<42>"); + ti("<%d>", S_INT, INT32_MAX, "<2147483647>"); + ti("<%d>", S_INT, INT32_MIN, "<-2147483648>"); + ti("<% d>", S_INT, 42, "< 42>"); + ti("<% d>", S_INT, -42, "<-42>"); + ti("<%+d>", S_INT, 42, "<+42>"); + ti("<%+d>", S_INT, -42, "<-42>"); + ti("<% +d>", S_INT, 42, "<+42>"); + ti("<% +d>", S_INT, -42, "<-42>"); + ti("<%-4d>", S_INT, 42, "<42 >"); + ti("<% -4d>", S_INT, 42, "< 42 >"); + ti("<%+-4d>", S_INT, 42, "<+42 >"); + ti("<%04d>", S_INT, 42, "<0042>"); + ti("<%-04d>", S_INT, 42, "<42 >"); + ti("<% 04d>", S_INT, 42, "< 042>"); + ti("<%+04d>", S_INT, 42, "<+042>"); + ti("<%4.3d>", S_INT, 42, "< 042>"); + ti("<% 5.3d>", S_INT, 42, "< 042>"); + ti("<%+5.3d>", S_INT, 42, "< +042>"); + ti("<%-4.3d>", S_INT, 42, "<042 >"); + ti("<%04.3d>", S_INT, 42, "< 042>"); + + ti("<%hhd>", S_CHAR, INT8_MIN, "<-128>"); + ti("<%hhd>", S_CHAR, -1, "<-1>"); + ti("<%hhd>", S_CHAR, 0, "<0>"); + ti("<%hhd>", S_CHAR, 1, "<1>"); + ti("<%hhd>", S_CHAR, INT8_MAX, "<127>"); + ti("<%+.4hhd>", S_CHAR, 42, "<+0042>"); + ti("<% 04hhd>", S_CHAR, 42, "< 042>"); + + ti("<%hd>", S_SHORT, INT16_MIN, "<-32768>"); + ti("<%hd>", S_SHORT, -1, "<-1>"); + ti("<%hd>", S_SHORT, 0, "<0>"); + ti("<%hd>", S_SHORT, 1, "<1>"); + ti("<%hd>", S_SHORT, INT16_MAX, "<32767>"); + + ti("<%hld>", S_LONG, INT32_MIN, "<-2147483648>"); + ti("<%hld>", S_LONG, -1, "<-1>"); + ti("<%hld>", S_LONG, 0, "<0>"); + ti("<%hld>", S_LONG, 1, "<1>"); + ti("<%hld>", S_LONG, INT32_MAX, "<2147483647>"); + + ti("<%hlld>", S_LL, INT64_MIN, "<-9223372036854775808>"); + ti("<%hlld>", S_LL, -1, "<-1>"); + ti("<%hlld>", S_LL, 0, "<0>"); + ti("<%hlld>", S_LL, 1, "<1>"); + ti("<%hlld>", S_LL, INT64_MAX, "<9223372036854775807>"); + ti("<%h-19lld>", S_LL, 123456789123456789LL, "<123456789123456789 >"); + + ti("<%hjd>", S_MAX, INT64_MIN, "<-9223372036854775808>"); + ti("<%hjd>", S_MAX, -1, "<-1>"); + ti("<%hjd>", S_MAX, 0, "<0>"); + ti("<%hjd>", S_MAX, 1, "<1>"); + ti("<%hjd>", S_MAX, INT64_MAX, "<9223372036854775807>"); + + ti("<%htd>", S_PTR, INT32_MIN, "<-2147483648>"); + ti("<%htd>", S_PTR, -1, "<-1>"); + ti("<%htd>", S_PTR, 0, "<0>"); + ti("<%htd>", S_PTR, 1, "<1>"); + ti("<%htd>", S_PTR, INT32_MAX, "<2147483647>"); + + ti("<%hzd>", S_SIZE, INT32_MIN, "<-2147483648>"); + ti("<%hzd>", S_SIZE, -1, "<-1>"); + ti("<%hzd>", S_SIZE, 0, "<0>"); + ti("<%hzd>", S_SIZE, 1, "<1>"); + ti("<%hzd>", S_SIZE, INT32_MAX, "<2147483647>"); + + /* + * Undefined behaviour of %d. + * Do not test by default to avoid noise. + * But provide the tests anyway to help track down + * unintended changes of behaviour when needed. + */ + + if (picky) { + ti("<%#d>", S_INT, 42, "<42>"); + ti("<%Ld>", S_INT, 42, "<42>"); + } + + /* + * Valid use cases of %u. + */ + + tu("<%u>", S_INT, 0, "<0>"); + tu("<%u>", S_INT, 1, "<1>"); + tu("<%u>", S_INT, 42, "<42>"); + tu("<%u>", S_INT, UINT32_MAX, "<4294967295>"); + tu("<%-4u>", S_INT, 42, "<42 >"); + tu("<%04u>", S_INT, 42, "<0042>"); + tu("<%-04u>", S_INT, 42, "<42 >"); + tu("<%4.3u>", S_INT, 42, "< 042>"); + tu("<%-4.3u>", S_INT, 42, "<042 >"); + tu("<%04.3u>", S_INT, 42, "< 042>"); + + tu("<%hhu>", S_CHAR, 0, "<0>"); + tu("<%hhu>", S_CHAR, UINT8_MAX, "<255>"); + tu("<%hhu>", S_CHAR, -1, "<255>"); + tu("<%-4hhu>", S_CHAR, 42, "<42 >"); + tu("<%04hhu>", S_CHAR, 42, "<0042>"); + + tu("<%hu>", S_SHORT, 0, "<0>"); + tu("<%hu>", S_SHORT, UINT16_MAX, "<65535>"); + tu("<%hlu>", S_LONG, 0, "<0>"); + tu("<%hlu>", S_LONG, UINT32_MAX, "<4294967295>"); + tu("<%hllu>", S_LL, 0, "<0>"); + tu("<%hllu>", S_LL, UINT64_MAX, "<18446744073709551615>"); + tu("<%h-19llu>", S_LL, 123456789123456789ULL, "<123456789123456789 >"); + tu("<%hju>", S_MAX, 0, "<0>"); + tu("<%hju>", S_MAX, UINT64_MAX, "<18446744073709551615>"); + tu("<%hzu>", S_SIZE, 0, "<0>"); + tu("<%hzu>", S_SIZE, UINT32_MAX, "<4294967295>"); + + tu("<%hho>", S_CHAR, 0, "<0>"); + tu("<%#hho>", S_CHAR, 0, "<0>"); + tu("<%hho>", S_CHAR, UINT8_MAX, "<377>"); + tu("<%#hho>", S_CHAR, UINT8_MAX, "<0377>"); + tu("<%hho>", S_CHAR, -1, "<377>"); + tu("<%#hho>", S_CHAR, -1, "<0377>"); + tu("<%-4hho>", S_CHAR, 42, "<52 >"); + tu("<%#-4hho>", S_CHAR, 42, "<052 >"); + tu("<%04hho>", S_CHAR, 42, "<0052>"); + tu("<%#04hho>", S_CHAR, 42, "<0052>"); + + tu("<%hx>", S_SHORT, 0, "<0>"); + tu("<%#hx>", S_SHORT, 0, "<0>"); + tu("<%hX>", S_SHORT, 0, "<0>"); + tu("<%#hX>", S_SHORT, 0, "<0>"); + tu("<%hx>", S_SHORT, 1, "<1>"); + tu("<%#hx>", S_SHORT, 1, "<0x1>"); + tu("<%hX>", S_SHORT, 1, "<1>"); + tu("<%#hX>", S_SHORT, 1, "<0X1>"); + tu("<%hx>", S_SHORT, 10, "<a>"); + tu("<%#hx>", S_SHORT, 10, "<0xa>"); + tu("<%hX>", S_SHORT, 10, "<A>"); + tu("<%#hX>", S_SHORT, 10, "<0XA>"); + tu("<%hx>", S_SHORT, UINT16_MAX, "<ffff>"); + tu("<%#hx>", S_SHORT, UINT16_MAX, "<0xffff>"); + tu("<%hX>", S_SHORT, UINT16_MAX, "<FFFF>"); + tu("<%#hX>", S_SHORT, UINT16_MAX, "<0XFFFF>"); + + /* + * Undefined behaviour of %u. + */ + + if (picky) { + tu("<%#u>", S_INT, 42, "<42>"); + tu("<% u>", S_INT, 42, "<42>"); + tu("<%+u>", S_INT, 42, "<42>"); + tu("<%Lu>", S_INT, 42, "<42>"); + } + + /* + * Summarize the results. + */ + + if (badret + badlen + badout) + errx(1, "ERRORS: %d fail + %d mismatch (incl. %d bad length)", + badret, badout, badlen); + else if (verbose) + warnx("SUCCESS"); + return 0; +} |