summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--regress/lib/libc/printf/Makefile4
-rw-r--r--regress/lib/libc/printf/int.c376
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;
+}