[PATCH v2 08/13] test: self: port Linux printf kselftest

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Port over the Linux v5.11 selftest for printf sans the parts we don't
support. This can be used to catch regressions if changes affecting the
printf code are made.

Signed-off-by: Ahmad Fatoum <a.fatoum@xxxxxxxxxxxxxx>
---
 include/stdlib.h   |   5 +
 test/self/Kconfig  |   6 +
 test/self/Makefile |   1 +
 test/self/core.c   |   2 +-
 test/self/printf.c | 302 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 315 insertions(+), 1 deletion(-)
 create mode 100644 test/self/printf.c

diff --git a/include/stdlib.h b/include/stdlib.h
index d4056087243d..8eb419e111f0 100644
--- a/include/stdlib.h
+++ b/include/stdlib.h
@@ -25,4 +25,9 @@ static inline u32 random32(void)
 	return ret;
 }
 
+static inline u32 prandom_u32_max(u32 ep_ro)
+{
+	return (u32)(((u64) random32() * ep_ro) >> 32);
+}
+
 #endif /* __STDLIB_H */
diff --git a/test/self/Kconfig b/test/self/Kconfig
index 720abeffc51b..73dc6c7b4f03 100644
--- a/test/self/Kconfig
+++ b/test/self/Kconfig
@@ -27,7 +27,13 @@ config SELFTEST_AUTORUN
 
 config SELFTEST_ENABLE_ALL
 	bool "Enable all self-tests"
+	select SELFTEST_PRINTF
 	help
 	  Selects all self-tests compatible with current configuration
 
+config SELFTEST_PRINTF
+	bool "printf selftest"
+	help
+	  Tests barebox vsnprintf() functionality
+
 endif
diff --git a/test/self/Makefile b/test/self/Makefile
index 78f738c8e210..b4aa49d6f817 100644
--- a/test/self/Makefile
+++ b/test/self/Makefile
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0
 
 obj-$(CONFIG_SELFTEST) += core.o
+obj-$(CONFIG_SELFTEST_PRINTF) += printf.o
diff --git a/test/self/core.c b/test/self/core.c
index 5a309fc8f18d..caa4c27f6def 100644
--- a/test/self/core.c
+++ b/test/self/core.c
@@ -7,7 +7,7 @@
 
 LIST_HEAD(selftests);
 
-int selftests_run(void)
+void selftests_run(void)
 {
 	struct selftest *test;
 	int err = 0;
diff --git a/test/self/printf.c b/test/self/printf.c
new file mode 100644
index 000000000000..52fe6ac0faf9
--- /dev/null
+++ b/test/self/printf.c
@@ -0,0 +1,302 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Test cases for printf facility.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <common.h>
+#include <bselftest.h>
+#include <linux/kernel.h>
+#include <module.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <linux/string.h>
+#include <errno.h>
+
+#include <linux/bitmap.h>
+
+#define BUF_SIZE 256
+#define PAD_SIZE 16
+#define FILL_CHAR '$'
+
+BSELFTEST_GLOBALS();
+
+static char *test_buffer __initdata;
+static char *alloced_buffer __initdata;
+
+static int __printf(4, 0) __init
+do_test(int bufsize, const char *expect, int elen,
+	const char *fmt, va_list ap)
+{
+	va_list aq;
+	int ret, written;
+
+	total_tests++;
+
+	memset(alloced_buffer, FILL_CHAR, BUF_SIZE + 2*PAD_SIZE);
+	va_copy(aq, ap);
+	ret = vsnprintf(test_buffer, bufsize, fmt, aq);
+	va_end(aq);
+
+	if (ret != elen) {
+		pr_warn("vsnprintf(buf, %d, \"%s\", ...) returned %d, expected %d\n",
+			bufsize, fmt, ret, elen);
+		pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote '%s', expected '%.*s'\n",
+			bufsize, fmt, test_buffer, ret, expect);
+		return 1;
+	}
+
+	if (memchr_inv(alloced_buffer, FILL_CHAR, PAD_SIZE)) {
+		pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote before buffer\n", bufsize, fmt);
+		return 1;
+	}
+
+	if (!bufsize) {
+		if (memchr_inv(test_buffer, FILL_CHAR, BUF_SIZE + PAD_SIZE)) {
+			pr_warn("vsnprintf(buf, 0, \"%s\", ...) wrote to buffer\n",
+				fmt);
+			return 1;
+		}
+		return 0;
+	}
+
+	written = min(bufsize-1, elen);
+	if (test_buffer[written]) {
+		pr_warn("vsnprintf(buf, %d, \"%s\", ...) did not nul-terminate buffer\n",
+			bufsize, fmt);
+		return 1;
+	}
+
+	if (memchr_inv(test_buffer + written + 1, FILL_CHAR, BUF_SIZE + PAD_SIZE - (written + 1))) {
+		pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote beyond the nul-terminator\n",
+			bufsize, fmt);
+		return 1;
+	}
+
+	if (memcmp(test_buffer, expect, written)) {
+		pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote '%s', expected '%.*s'\n",
+			bufsize, fmt, test_buffer, written, expect);
+		return 1;
+	}
+	return 0;
+}
+
+static void __printf(3, 4) __init
+__test(const char *expect, int elen, const char *fmt, ...)
+{
+	va_list ap;
+	int rand;
+	char *p;
+
+	if (elen >= BUF_SIZE) {
+		pr_err("error in test suite: expected output length %d too long. Format was '%s'.\n",
+		       elen, fmt);
+		failed_tests++;
+		return;
+	}
+
+	va_start(ap, fmt);
+
+	/*
+	 * Every fmt+args is subjected to four tests: Three where we
+	 * tell vsnprintf varying buffer sizes (plenty, not quite
+	 * enough and 0), and then we also test that bvasprintf would
+	 * be able to print it as expected.
+	 */
+	failed_tests += do_test(BUF_SIZE, expect, elen, fmt, ap);
+	rand = 1 + prandom_u32_max(elen+1);
+	/* Since elen < BUF_SIZE, we have 1 <= rand <= BUF_SIZE. */
+	failed_tests += do_test(rand, expect, elen, fmt, ap);
+	failed_tests += do_test(0, expect, elen, fmt, ap);
+
+	p = bvasprintf(fmt, ap);
+	if (p) {
+		total_tests++;
+		if (memcmp(p, expect, elen+1)) {
+			pr_warn("bvasprintf(..., \"%s\", ...) returned '%s', expected '%s'\n",
+				fmt, p, expect);
+			failed_tests++;
+		}
+		kfree(p);
+	}
+	va_end(ap);
+}
+
+#define test(expect, fmt, ...)					\
+	__test(expect, strlen(expect), fmt, ##__VA_ARGS__)
+
+static void __init
+test_basic(void)
+{
+	/* Work around annoying "warning: zero-length gnu_printf format string". */
+	char nul = '\0';
+
+	test("", &nul);
+	test("100%", "100%%");
+	test("xxx%yyy", "xxx%cyyy", '%');
+	__test("xxx\0yyy", 7, "xxx%cyyy", '\0');
+}
+
+static void __init
+test_number(void)
+{
+	signed char val;
+
+	test("0x1234abcd  ", "%#-12x", 0x1234abcd);
+	test("  0x1234abcd", "%#12x", 0x1234abcd);
+	test("0|001| 12|+123| 1234|-123|-1234", "%d|%03d|%3d|%+d|% d|%+d|% d", 0, 1, 12, 123, 1234, -123, -1234);
+	test("0|1|1|32768|65535", "%hu|%hu|%hu|%hu|%hu", 0, 1, 65537, 32768, -1);
+	test("0|1|1|-32768|-1", "%hd|%hd|%hd|%hd|%hd", 0, 1, 65537, 32768, -1);
+	test("2015122420151225", "%ho%ho%#ho", 1037, 5282, -11627);
+
+	test("2015122420151225", "%ho%ho%#ho", 1037, 5282, -11627);
+
+	/*
+	 * POSIX/C99: »The result of converting zero with an explicit
+	 * precision of zero shall be no characters.« Hence the output
+	 * from the below test should really be "00|0||| ". However,
+	 * the kernel's printf also produces a single 0 in that
+	 * case. This test case simply documents the current
+	 * behaviour.
+	 */
+	test("00|0|0|0|0", "%.2d|%.1d|%.0d|%.*d|%1.0d", 0, 0, 0, 0, 0, 0);
+
+	val = -16;
+	test("0xfffffff0|0xf0|0xf0", "%#02x|%#02x|%#02x", val, val & 0xff, (u8)val);
+
+	/* On some platforms, test failure here indicates a misaligned stack */
+	test("0x0807060504030201", "0x%016llx", 0x0807060504030201ULL);
+}
+
+static void __init
+test_string(void)
+{
+	test("", "%s%.0s", "", "123");
+	test("ABCD|abc|123", "%s|%.3s|%.*s", "ABCD", "abcdef", 3, "123456");
+	test("1  |  2|3  |  4|5  ", "%-3s|%3s|%-*s|%*s|%*s", "1", "2", 3, "3", 3, "4", -3, "5");
+	test("1234      ", "%-10.4s", "123456");
+	test("      1234", "%10.4s", "123456");
+}
+
+#if BITS_PER_LONG == 64
+
+#define PTR_WIDTH 16
+#define PTR ((void *)0xffff0123456789abUL)
+#define PTR_STR "ffff0123456789ab"
+#define PTR_VAL_NO_CRNG "(____ptrval____)"
+#define ZEROS "00000000"	/* hex 32 zero bits */
+#define ONES "ffffffff"		/* hex 32 one bits */
+
+#else
+
+#define PTR_WIDTH 8
+#define PTR ((void *)0x456789ab)
+#define PTR_STR "456789ab"
+#define PTR_VAL_NO_CRNG "(ptrval)"
+#define ZEROS ""
+#define ONES ""
+
+#endif	/* BITS_PER_LONG == 64 */
+
+/*
+ * NULL pointers aren't hashed.
+ */
+static void __init
+null_pointer(void)
+{
+	test(ZEROS "00000000", "%p", NULL);
+	test(ZEROS "00000000", "%px", NULL);
+}
+
+/*
+ * Error pointers aren't hashed.
+ */
+static void __init
+error_pointer(void)
+{
+	test(ONES "fffffff5", "%p", ERR_PTR(-11));
+	test(ONES "fffffff5", "%px", ERR_PTR(-11));
+}
+
+#define PTR_INVALID ((void *)0x000000ab)
+
+static void __init
+invalid_pointer(void)
+{
+	test(ZEROS "000000ab", "%px", PTR_INVALID);
+}
+
+static void __init
+ip4(void)
+{
+	IPaddr_t ip = cpu_to_be32(0x7f000001);
+
+	test("127.0.0.1", "%pI4", &ip);
+}
+
+static void __init
+ip(void)
+{
+	ip4();
+}
+
+static void __init
+uuid(void)
+{
+	const char uuid[16] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
+			       0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+
+	if (!IS_ENABLED(CONFIG_PRINTF_UUID))
+		return;
+
+	test("00010203-0405-0607-0809-0a0b0c0d0e0f", "%pUb", uuid);
+	test("00010203-0405-0607-0809-0A0B0C0D0E0F", "%pUB", uuid);
+	test("03020100-0504-0706-0809-0a0b0c0d0e0f", "%pUl", uuid);
+	test("03020100-0504-0706-0809-0A0B0C0D0E0F", "%pUL", uuid);
+}
+
+static void __init
+errptr(void)
+{
+	test("error 1234", "%pe", ERR_PTR(-1234));
+	test(sizeof(void *) == 8 ? "00000000000004d2" : "000004d2", "%pe", ERR_PTR(1234));
+
+	/* Check that %pe with a non-ERR_PTR gets treated as ordinary %p. */
+	BUILD_BUG_ON(IS_ERR(PTR));
+
+	if (!IS_ENABLED(CONFIG_ERRNO_MESSAGES))
+		return;
+	test("(Operation not permitted)", "(%pe)", ERR_PTR(-EPERM));
+	test("Requested probe deferral", "%pe", ERR_PTR(-EPROBE_DEFER));
+}
+
+static void __init
+test_pointer(void)
+{
+	null_pointer();
+	error_pointer();
+	invalid_pointer();
+	ip();
+	uuid();
+	errptr();
+}
+
+static void __init test_printf(void)
+{
+	alloced_buffer = malloc(BUF_SIZE + 2*PAD_SIZE);
+	if (!alloced_buffer)
+		return;
+	test_buffer = alloced_buffer + PAD_SIZE;
+
+	test_basic();
+	test_number();
+	test_string();
+	test_pointer();
+
+	free(alloced_buffer);
+}
+
+bselftest(core, test_printf);
+MODULE_AUTHOR("Rasmus Villemoes <linux@xxxxxxxxxxxxxxxxxx>");
+MODULE_LICENSE("GPL");
-- 
2.29.2


_______________________________________________
barebox mailing list
barebox@xxxxxxxxxxxxxxxxxxx
http://lists.infradead.org/mailman/listinfo/barebox




[Index of Archives]     [Linux Embedded]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux