xref: /linux/lib/test_scanf.c (revision 53b0fe36ab7c6eb3ce8ca711e636806649273463)
150f530e1SRichard Fitzgerald // SPDX-License-Identifier: GPL-2.0-only
250f530e1SRichard Fitzgerald /*
350f530e1SRichard Fitzgerald  * Test cases for sscanf facility.
450f530e1SRichard Fitzgerald  */
550f530e1SRichard Fitzgerald 
650f530e1SRichard Fitzgerald #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
750f530e1SRichard Fitzgerald 
850f530e1SRichard Fitzgerald #include <linux/bitops.h>
950f530e1SRichard Fitzgerald #include <linux/init.h>
1050f530e1SRichard Fitzgerald #include <linux/kernel.h>
1150f530e1SRichard Fitzgerald #include <linux/module.h>
1250f530e1SRichard Fitzgerald #include <linux/overflow.h>
1350f530e1SRichard Fitzgerald #include <linux/printk.h>
1450f530e1SRichard Fitzgerald #include <linux/random.h>
1550f530e1SRichard Fitzgerald #include <linux/slab.h>
1650f530e1SRichard Fitzgerald #include <linux/string.h>
1750f530e1SRichard Fitzgerald 
1850f530e1SRichard Fitzgerald #include "../tools/testing/selftests/kselftest_module.h"
1950f530e1SRichard Fitzgerald 
2050f530e1SRichard Fitzgerald #define BUF_SIZE 1024
2150f530e1SRichard Fitzgerald 
2250f530e1SRichard Fitzgerald KSTM_MODULE_GLOBALS();
2350f530e1SRichard Fitzgerald static char *test_buffer __initdata;
2450f530e1SRichard Fitzgerald static char *fmt_buffer __initdata;
2550f530e1SRichard Fitzgerald static struct rnd_state rnd_state __initdata;
2650f530e1SRichard Fitzgerald 
2750f530e1SRichard Fitzgerald typedef int (*check_fn)(const void *check_data, const char *string,
2850f530e1SRichard Fitzgerald 			const char *fmt, int n_args, va_list ap);
2950f530e1SRichard Fitzgerald 
3050f530e1SRichard Fitzgerald static void __scanf(4, 6) __init
3150f530e1SRichard Fitzgerald _test(check_fn fn, const void *check_data, const char *string, const char *fmt,
3250f530e1SRichard Fitzgerald 	int n_args, ...)
3350f530e1SRichard Fitzgerald {
3450f530e1SRichard Fitzgerald 	va_list ap, ap_copy;
3550f530e1SRichard Fitzgerald 	int ret;
3650f530e1SRichard Fitzgerald 
3750f530e1SRichard Fitzgerald 	total_tests++;
3850f530e1SRichard Fitzgerald 
3950f530e1SRichard Fitzgerald 	va_start(ap, n_args);
4050f530e1SRichard Fitzgerald 	va_copy(ap_copy, ap);
4150f530e1SRichard Fitzgerald 	ret = vsscanf(string, fmt, ap_copy);
4250f530e1SRichard Fitzgerald 	va_end(ap_copy);
4350f530e1SRichard Fitzgerald 
4450f530e1SRichard Fitzgerald 	if (ret != n_args) {
4550f530e1SRichard Fitzgerald 		pr_warn("vsscanf(\"%s\", \"%s\", ...) returned %d expected %d\n",
4650f530e1SRichard Fitzgerald 			string, fmt, ret, n_args);
4750f530e1SRichard Fitzgerald 		goto fail;
4850f530e1SRichard Fitzgerald 	}
4950f530e1SRichard Fitzgerald 
5050f530e1SRichard Fitzgerald 	ret = (*fn)(check_data, string, fmt, n_args, ap);
5150f530e1SRichard Fitzgerald 	if (ret)
5250f530e1SRichard Fitzgerald 		goto fail;
5350f530e1SRichard Fitzgerald 
5450f530e1SRichard Fitzgerald 	va_end(ap);
5550f530e1SRichard Fitzgerald 
5650f530e1SRichard Fitzgerald 	return;
5750f530e1SRichard Fitzgerald 
5850f530e1SRichard Fitzgerald fail:
5950f530e1SRichard Fitzgerald 	failed_tests++;
6050f530e1SRichard Fitzgerald 	va_end(ap);
6150f530e1SRichard Fitzgerald }
6250f530e1SRichard Fitzgerald 
6350f530e1SRichard Fitzgerald #define _check_numbers_template(arg_fmt, expect, str, fmt, n_args, ap)		\
6450f530e1SRichard Fitzgerald do {										\
6550f530e1SRichard Fitzgerald 	pr_debug("\"%s\", \"%s\" ->\n", str, fmt);				\
6650f530e1SRichard Fitzgerald 	for (; n_args > 0; n_args--, expect++) {				\
6750f530e1SRichard Fitzgerald 		typeof(*expect) got = *va_arg(ap, typeof(expect));		\
6850f530e1SRichard Fitzgerald 		pr_debug("\t" arg_fmt "\n", got);				\
6950f530e1SRichard Fitzgerald 		if (got != *expect) {						\
7050f530e1SRichard Fitzgerald 			pr_warn("vsscanf(\"%s\", \"%s\", ...) expected " arg_fmt " got " arg_fmt "\n", \
7150f530e1SRichard Fitzgerald 				str, fmt, *expect, got);			\
7250f530e1SRichard Fitzgerald 			return 1;						\
7350f530e1SRichard Fitzgerald 		}								\
7450f530e1SRichard Fitzgerald 	}									\
7550f530e1SRichard Fitzgerald 	return 0;								\
7650f530e1SRichard Fitzgerald } while (0)
7750f530e1SRichard Fitzgerald 
7850f530e1SRichard Fitzgerald static int __init check_ull(const void *check_data, const char *string,
7950f530e1SRichard Fitzgerald 			    const char *fmt, int n_args, va_list ap)
8050f530e1SRichard Fitzgerald {
8150f530e1SRichard Fitzgerald 	const unsigned long long *pval = check_data;
8250f530e1SRichard Fitzgerald 
8350f530e1SRichard Fitzgerald 	_check_numbers_template("%llu", pval, string, fmt, n_args, ap);
8450f530e1SRichard Fitzgerald }
8550f530e1SRichard Fitzgerald 
8650f530e1SRichard Fitzgerald static int __init check_ll(const void *check_data, const char *string,
8750f530e1SRichard Fitzgerald 			   const char *fmt, int n_args, va_list ap)
8850f530e1SRichard Fitzgerald {
8950f530e1SRichard Fitzgerald 	const long long *pval = check_data;
9050f530e1SRichard Fitzgerald 
9150f530e1SRichard Fitzgerald 	_check_numbers_template("%lld", pval, string, fmt, n_args, ap);
9250f530e1SRichard Fitzgerald }
9350f530e1SRichard Fitzgerald 
9450f530e1SRichard Fitzgerald static int __init check_ulong(const void *check_data, const char *string,
9550f530e1SRichard Fitzgerald 			   const char *fmt, int n_args, va_list ap)
9650f530e1SRichard Fitzgerald {
9750f530e1SRichard Fitzgerald 	const unsigned long *pval = check_data;
9850f530e1SRichard Fitzgerald 
9950f530e1SRichard Fitzgerald 	_check_numbers_template("%lu", pval, string, fmt, n_args, ap);
10050f530e1SRichard Fitzgerald }
10150f530e1SRichard Fitzgerald 
10250f530e1SRichard Fitzgerald static int __init check_long(const void *check_data, const char *string,
10350f530e1SRichard Fitzgerald 			  const char *fmt, int n_args, va_list ap)
10450f530e1SRichard Fitzgerald {
10550f530e1SRichard Fitzgerald 	const long *pval = check_data;
10650f530e1SRichard Fitzgerald 
10750f530e1SRichard Fitzgerald 	_check_numbers_template("%ld", pval, string, fmt, n_args, ap);
10850f530e1SRichard Fitzgerald }
10950f530e1SRichard Fitzgerald 
11050f530e1SRichard Fitzgerald static int __init check_uint(const void *check_data, const char *string,
11150f530e1SRichard Fitzgerald 			     const char *fmt, int n_args, va_list ap)
11250f530e1SRichard Fitzgerald {
11350f530e1SRichard Fitzgerald 	const unsigned int *pval = check_data;
11450f530e1SRichard Fitzgerald 
11550f530e1SRichard Fitzgerald 	_check_numbers_template("%u", pval, string, fmt, n_args, ap);
11650f530e1SRichard Fitzgerald }
11750f530e1SRichard Fitzgerald 
11850f530e1SRichard Fitzgerald static int __init check_int(const void *check_data, const char *string,
11950f530e1SRichard Fitzgerald 			    const char *fmt, int n_args, va_list ap)
12050f530e1SRichard Fitzgerald {
12150f530e1SRichard Fitzgerald 	const int *pval = check_data;
12250f530e1SRichard Fitzgerald 
12350f530e1SRichard Fitzgerald 	_check_numbers_template("%d", pval, string, fmt, n_args, ap);
12450f530e1SRichard Fitzgerald }
12550f530e1SRichard Fitzgerald 
12650f530e1SRichard Fitzgerald static int __init check_ushort(const void *check_data, const char *string,
12750f530e1SRichard Fitzgerald 			       const char *fmt, int n_args, va_list ap)
12850f530e1SRichard Fitzgerald {
12950f530e1SRichard Fitzgerald 	const unsigned short *pval = check_data;
13050f530e1SRichard Fitzgerald 
13150f530e1SRichard Fitzgerald 	_check_numbers_template("%hu", pval, string, fmt, n_args, ap);
13250f530e1SRichard Fitzgerald }
13350f530e1SRichard Fitzgerald 
13450f530e1SRichard Fitzgerald static int __init check_short(const void *check_data, const char *string,
13550f530e1SRichard Fitzgerald 			       const char *fmt, int n_args, va_list ap)
13650f530e1SRichard Fitzgerald {
13750f530e1SRichard Fitzgerald 	const short *pval = check_data;
13850f530e1SRichard Fitzgerald 
13950f530e1SRichard Fitzgerald 	_check_numbers_template("%hd", pval, string, fmt, n_args, ap);
14050f530e1SRichard Fitzgerald }
14150f530e1SRichard Fitzgerald 
14250f530e1SRichard Fitzgerald static int __init check_uchar(const void *check_data, const char *string,
14350f530e1SRichard Fitzgerald 			       const char *fmt, int n_args, va_list ap)
14450f530e1SRichard Fitzgerald {
14550f530e1SRichard Fitzgerald 	const unsigned char *pval = check_data;
14650f530e1SRichard Fitzgerald 
14750f530e1SRichard Fitzgerald 	_check_numbers_template("%hhu", pval, string, fmt, n_args, ap);
14850f530e1SRichard Fitzgerald }
14950f530e1SRichard Fitzgerald 
15050f530e1SRichard Fitzgerald static int __init check_char(const void *check_data, const char *string,
15150f530e1SRichard Fitzgerald 			       const char *fmt, int n_args, va_list ap)
15250f530e1SRichard Fitzgerald {
15350f530e1SRichard Fitzgerald 	const signed char *pval = check_data;
15450f530e1SRichard Fitzgerald 
15550f530e1SRichard Fitzgerald 	_check_numbers_template("%hhd", pval, string, fmt, n_args, ap);
15650f530e1SRichard Fitzgerald }
15750f530e1SRichard Fitzgerald 
15850f530e1SRichard Fitzgerald /* Selection of interesting numbers to test, copied from test-kstrtox.c */
15950f530e1SRichard Fitzgerald static const unsigned long long numbers[] __initconst = {
16050f530e1SRichard Fitzgerald 	0x0ULL,
16150f530e1SRichard Fitzgerald 	0x1ULL,
16250f530e1SRichard Fitzgerald 	0x7fULL,
16350f530e1SRichard Fitzgerald 	0x80ULL,
16450f530e1SRichard Fitzgerald 	0x81ULL,
16550f530e1SRichard Fitzgerald 	0xffULL,
16650f530e1SRichard Fitzgerald 	0x100ULL,
16750f530e1SRichard Fitzgerald 	0x101ULL,
16850f530e1SRichard Fitzgerald 	0x7fffULL,
16950f530e1SRichard Fitzgerald 	0x8000ULL,
17050f530e1SRichard Fitzgerald 	0x8001ULL,
17150f530e1SRichard Fitzgerald 	0xffffULL,
17250f530e1SRichard Fitzgerald 	0x10000ULL,
17350f530e1SRichard Fitzgerald 	0x10001ULL,
17450f530e1SRichard Fitzgerald 	0x7fffffffULL,
17550f530e1SRichard Fitzgerald 	0x80000000ULL,
17650f530e1SRichard Fitzgerald 	0x80000001ULL,
17750f530e1SRichard Fitzgerald 	0xffffffffULL,
17850f530e1SRichard Fitzgerald 	0x100000000ULL,
17950f530e1SRichard Fitzgerald 	0x100000001ULL,
18050f530e1SRichard Fitzgerald 	0x7fffffffffffffffULL,
18150f530e1SRichard Fitzgerald 	0x8000000000000000ULL,
18250f530e1SRichard Fitzgerald 	0x8000000000000001ULL,
18350f530e1SRichard Fitzgerald 	0xfffffffffffffffeULL,
18450f530e1SRichard Fitzgerald 	0xffffffffffffffffULL,
18550f530e1SRichard Fitzgerald };
18650f530e1SRichard Fitzgerald 
18750f530e1SRichard Fitzgerald #define value_representable_in_type(T, val)					 \
18850f530e1SRichard Fitzgerald (is_signed_type(T)								 \
18950f530e1SRichard Fitzgerald 	? ((long long)(val) >= type_min(T)) && ((long long)(val) <= type_max(T)) \
1901b932689SRichard Fitzgerald 	: ((unsigned long long)(val) <= type_max(T)))
1911b932689SRichard Fitzgerald 
19250f530e1SRichard Fitzgerald 
19350f530e1SRichard Fitzgerald #define test_one_number(T, gen_fmt, scan_fmt, val, fn)			\
19450f530e1SRichard Fitzgerald do {									\
19550f530e1SRichard Fitzgerald 	const T expect_val = (T)(val);					\
19650f530e1SRichard Fitzgerald 	T result = ~expect_val; /* should be overwritten */		\
19750f530e1SRichard Fitzgerald 									\
19850f530e1SRichard Fitzgerald 	snprintf(test_buffer, BUF_SIZE, gen_fmt, expect_val);		\
19950f530e1SRichard Fitzgerald 	_test(fn, &expect_val, test_buffer, "%" scan_fmt, 1, &result);	\
20050f530e1SRichard Fitzgerald } while (0)
20150f530e1SRichard Fitzgerald 
20250f530e1SRichard Fitzgerald #define simple_numbers_loop(T, gen_fmt, scan_fmt, fn)			\
20350f530e1SRichard Fitzgerald do {									\
20450f530e1SRichard Fitzgerald 	int i;								\
20550f530e1SRichard Fitzgerald 									\
20650f530e1SRichard Fitzgerald 	for (i = 0; i < ARRAY_SIZE(numbers); i++) {			\
2071b932689SRichard Fitzgerald 		if (value_representable_in_type(T, numbers[i]))		\
2081b932689SRichard Fitzgerald 			test_one_number(T, gen_fmt, scan_fmt,		\
2091b932689SRichard Fitzgerald 					numbers[i], fn);		\
21050f530e1SRichard Fitzgerald 									\
2111b932689SRichard Fitzgerald 		if (value_representable_in_type(T, -numbers[i]))	\
21250f530e1SRichard Fitzgerald 			test_one_number(T, gen_fmt, scan_fmt,		\
21350f530e1SRichard Fitzgerald 					-numbers[i], fn);		\
21450f530e1SRichard Fitzgerald 	}								\
21550f530e1SRichard Fitzgerald } while (0)
21650f530e1SRichard Fitzgerald 
21750f530e1SRichard Fitzgerald static void __init numbers_simple(void)
21850f530e1SRichard Fitzgerald {
21950f530e1SRichard Fitzgerald 	simple_numbers_loop(unsigned long long,	"%llu",	  "llu", check_ull);
22050f530e1SRichard Fitzgerald 	simple_numbers_loop(long long,		"%lld",	  "lld", check_ll);
22150f530e1SRichard Fitzgerald 	simple_numbers_loop(long long,		"%lld",	  "lli", check_ll);
22250f530e1SRichard Fitzgerald 	simple_numbers_loop(unsigned long long,	"%llx",	  "llx", check_ull);
22350f530e1SRichard Fitzgerald 	simple_numbers_loop(long long,		"%llx",	  "llx", check_ll);
22450f530e1SRichard Fitzgerald 	simple_numbers_loop(long long,		"0x%llx", "lli", check_ll);
22550f530e1SRichard Fitzgerald 	simple_numbers_loop(unsigned long long, "0x%llx", "llx", check_ull);
22650f530e1SRichard Fitzgerald 	simple_numbers_loop(long long,		"0x%llx", "llx", check_ll);
22750f530e1SRichard Fitzgerald 
22850f530e1SRichard Fitzgerald 	simple_numbers_loop(unsigned long,	"%lu",	  "lu", check_ulong);
22950f530e1SRichard Fitzgerald 	simple_numbers_loop(long,		"%ld",	  "ld", check_long);
23050f530e1SRichard Fitzgerald 	simple_numbers_loop(long,		"%ld",	  "li", check_long);
23150f530e1SRichard Fitzgerald 	simple_numbers_loop(unsigned long,	"%lx",	  "lx", check_ulong);
23250f530e1SRichard Fitzgerald 	simple_numbers_loop(long,		"%lx",	  "lx", check_long);
23350f530e1SRichard Fitzgerald 	simple_numbers_loop(long,		"0x%lx",  "li", check_long);
23450f530e1SRichard Fitzgerald 	simple_numbers_loop(unsigned long,	"0x%lx",  "lx", check_ulong);
23550f530e1SRichard Fitzgerald 	simple_numbers_loop(long,		"0x%lx",  "lx", check_long);
23650f530e1SRichard Fitzgerald 
23750f530e1SRichard Fitzgerald 	simple_numbers_loop(unsigned int,	"%u",	  "u", check_uint);
23850f530e1SRichard Fitzgerald 	simple_numbers_loop(int,		"%d",	  "d", check_int);
23950f530e1SRichard Fitzgerald 	simple_numbers_loop(int,		"%d",	  "i", check_int);
24050f530e1SRichard Fitzgerald 	simple_numbers_loop(unsigned int,	"%x",	  "x", check_uint);
24150f530e1SRichard Fitzgerald 	simple_numbers_loop(int,		"%x",	  "x", check_int);
24250f530e1SRichard Fitzgerald 	simple_numbers_loop(int,		"0x%x",   "i", check_int);
24350f530e1SRichard Fitzgerald 	simple_numbers_loop(unsigned int,	"0x%x",   "x", check_uint);
24450f530e1SRichard Fitzgerald 	simple_numbers_loop(int,		"0x%x",   "x", check_int);
24550f530e1SRichard Fitzgerald 
24650f530e1SRichard Fitzgerald 	simple_numbers_loop(unsigned short,	"%hu",	  "hu", check_ushort);
24750f530e1SRichard Fitzgerald 	simple_numbers_loop(short,		"%hd",	  "hd", check_short);
24850f530e1SRichard Fitzgerald 	simple_numbers_loop(short,		"%hd",	  "hi", check_short);
24950f530e1SRichard Fitzgerald 	simple_numbers_loop(unsigned short,	"%hx",	  "hx", check_ushort);
25050f530e1SRichard Fitzgerald 	simple_numbers_loop(short,		"%hx",	  "hx", check_short);
25150f530e1SRichard Fitzgerald 	simple_numbers_loop(short,		"0x%hx",  "hi", check_short);
25250f530e1SRichard Fitzgerald 	simple_numbers_loop(unsigned short,	"0x%hx",  "hx", check_ushort);
25350f530e1SRichard Fitzgerald 	simple_numbers_loop(short,		"0x%hx",  "hx", check_short);
25450f530e1SRichard Fitzgerald 
25550f530e1SRichard Fitzgerald 	simple_numbers_loop(unsigned char,	"%hhu",	  "hhu", check_uchar);
25650f530e1SRichard Fitzgerald 	simple_numbers_loop(signed char,	"%hhd",	  "hhd", check_char);
25750f530e1SRichard Fitzgerald 	simple_numbers_loop(signed char,	"%hhd",	  "hhi", check_char);
25850f530e1SRichard Fitzgerald 	simple_numbers_loop(unsigned char,	"%hhx",	  "hhx", check_uchar);
25950f530e1SRichard Fitzgerald 	simple_numbers_loop(signed char,	"%hhx",	  "hhx", check_char);
26050f530e1SRichard Fitzgerald 	simple_numbers_loop(signed char,	"0x%hhx", "hhi", check_char);
26150f530e1SRichard Fitzgerald 	simple_numbers_loop(unsigned char,	"0x%hhx", "hhx", check_uchar);
26250f530e1SRichard Fitzgerald 	simple_numbers_loop(signed char,	"0x%hhx", "hhx", check_char);
26350f530e1SRichard Fitzgerald }
26450f530e1SRichard Fitzgerald 
26550f530e1SRichard Fitzgerald /*
26650f530e1SRichard Fitzgerald  * This gives a better variety of number "lengths" in a small sample than
26750f530e1SRichard Fitzgerald  * the raw prandom*() functions (Not mathematically rigorous!!).
26850f530e1SRichard Fitzgerald  * Variabilty of length and value is more important than perfect randomness.
26950f530e1SRichard Fitzgerald  */
27050f530e1SRichard Fitzgerald static u32 __init next_test_random(u32 max_bits)
27150f530e1SRichard Fitzgerald {
27250f530e1SRichard Fitzgerald 	u32 n_bits = hweight32(prandom_u32_state(&rnd_state)) % (max_bits + 1);
27350f530e1SRichard Fitzgerald 
27450f530e1SRichard Fitzgerald 	return prandom_u32_state(&rnd_state) & (UINT_MAX >> (32 - n_bits));
27550f530e1SRichard Fitzgerald }
27650f530e1SRichard Fitzgerald 
27750f530e1SRichard Fitzgerald static unsigned long long __init next_test_random_ull(void)
27850f530e1SRichard Fitzgerald {
27950f530e1SRichard Fitzgerald 	u32 rand1 = prandom_u32_state(&rnd_state);
28050f530e1SRichard Fitzgerald 	u32 n_bits = (hweight32(rand1) * 3) % 64;
28150f530e1SRichard Fitzgerald 	u64 val = (u64)prandom_u32_state(&rnd_state) * rand1;
28250f530e1SRichard Fitzgerald 
28350f530e1SRichard Fitzgerald 	return val & (ULLONG_MAX >> (64 - n_bits));
28450f530e1SRichard Fitzgerald }
28550f530e1SRichard Fitzgerald 
28650f530e1SRichard Fitzgerald #define random_for_type(T)				\
28750f530e1SRichard Fitzgerald 	((T)(sizeof(T) <= sizeof(u32)			\
28850f530e1SRichard Fitzgerald 		? next_test_random(BITS_PER_TYPE(T))	\
28950f530e1SRichard Fitzgerald 		: next_test_random_ull()))
29050f530e1SRichard Fitzgerald 
29150f530e1SRichard Fitzgerald /*
29250f530e1SRichard Fitzgerald  * Define a pattern of negative and positive numbers to ensure we get
29350f530e1SRichard Fitzgerald  * some of both within the small number of samples in a test string.
29450f530e1SRichard Fitzgerald  */
29550f530e1SRichard Fitzgerald #define NEGATIVES_PATTERN 0x3246	/* 00110010 01000110 */
29650f530e1SRichard Fitzgerald 
29750f530e1SRichard Fitzgerald #define fill_random_array(arr)							\
29850f530e1SRichard Fitzgerald do {										\
29950f530e1SRichard Fitzgerald 	unsigned int neg_pattern = NEGATIVES_PATTERN;				\
30050f530e1SRichard Fitzgerald 	int i;									\
30150f530e1SRichard Fitzgerald 										\
30250f530e1SRichard Fitzgerald 	for (i = 0; i < ARRAY_SIZE(arr); i++, neg_pattern >>= 1) {		\
30350f530e1SRichard Fitzgerald 		(arr)[i] = random_for_type(typeof((arr)[0]));			\
30450f530e1SRichard Fitzgerald 		if (is_signed_type(typeof((arr)[0])) && (neg_pattern & 1))	\
30550f530e1SRichard Fitzgerald 			(arr)[i] = -(arr)[i];					\
30650f530e1SRichard Fitzgerald 	}									\
30750f530e1SRichard Fitzgerald } while (0)
30850f530e1SRichard Fitzgerald 
30950f530e1SRichard Fitzgerald /*
31050f530e1SRichard Fitzgerald  * Convenience wrapper around snprintf() to append at buf_pos in buf,
31150f530e1SRichard Fitzgerald  * updating buf_pos and returning the number of characters appended.
31250f530e1SRichard Fitzgerald  * On error buf_pos is not changed and return value is 0.
31350f530e1SRichard Fitzgerald  */
31450f530e1SRichard Fitzgerald static int __init __printf(4, 5)
31550f530e1SRichard Fitzgerald append_fmt(char *buf, int *buf_pos, int buf_len, const char *val_fmt, ...)
31650f530e1SRichard Fitzgerald {
31750f530e1SRichard Fitzgerald 	va_list ap;
31850f530e1SRichard Fitzgerald 	int field_len;
31950f530e1SRichard Fitzgerald 
32050f530e1SRichard Fitzgerald 	va_start(ap, val_fmt);
32150f530e1SRichard Fitzgerald 	field_len = vsnprintf(buf + *buf_pos, buf_len - *buf_pos, val_fmt, ap);
32250f530e1SRichard Fitzgerald 	va_end(ap);
32350f530e1SRichard Fitzgerald 
32450f530e1SRichard Fitzgerald 	if (field_len < 0)
32550f530e1SRichard Fitzgerald 		field_len = 0;
32650f530e1SRichard Fitzgerald 
32750f530e1SRichard Fitzgerald 	*buf_pos += field_len;
32850f530e1SRichard Fitzgerald 
32950f530e1SRichard Fitzgerald 	return field_len;
33050f530e1SRichard Fitzgerald }
33150f530e1SRichard Fitzgerald 
33250f530e1SRichard Fitzgerald /*
33350f530e1SRichard Fitzgerald  * Convenience function to append the field delimiter string
33450f530e1SRichard Fitzgerald  * to both the value string and format string buffers.
33550f530e1SRichard Fitzgerald  */
33650f530e1SRichard Fitzgerald static void __init append_delim(char *str_buf, int *str_buf_pos, int str_buf_len,
33750f530e1SRichard Fitzgerald 				char *fmt_buf, int *fmt_buf_pos, int fmt_buf_len,
33850f530e1SRichard Fitzgerald 				const char *delim_str)
33950f530e1SRichard Fitzgerald {
34050f530e1SRichard Fitzgerald 	append_fmt(str_buf, str_buf_pos, str_buf_len, delim_str);
34150f530e1SRichard Fitzgerald 	append_fmt(fmt_buf, fmt_buf_pos, fmt_buf_len, delim_str);
34250f530e1SRichard Fitzgerald }
34350f530e1SRichard Fitzgerald 
34450f530e1SRichard Fitzgerald #define test_array_8(fn, check_data, string, fmt, arr)				\
34550f530e1SRichard Fitzgerald do {										\
34650f530e1SRichard Fitzgerald 	BUILD_BUG_ON(ARRAY_SIZE(arr) != 8);					\
34750f530e1SRichard Fitzgerald 	_test(fn, check_data, string, fmt, 8,					\
34850f530e1SRichard Fitzgerald 		&(arr)[0], &(arr)[1], &(arr)[2], &(arr)[3],			\
34950f530e1SRichard Fitzgerald 		&(arr)[4], &(arr)[5], &(arr)[6], &(arr)[7]);			\
35050f530e1SRichard Fitzgerald } while (0)
35150f530e1SRichard Fitzgerald 
35250f530e1SRichard Fitzgerald #define numbers_list_8(T, gen_fmt, field_sep, scan_fmt, fn)			\
35350f530e1SRichard Fitzgerald do {										\
35450f530e1SRichard Fitzgerald 	int i, pos = 0, fmt_pos = 0;						\
35550f530e1SRichard Fitzgerald 	T expect[8], result[8];							\
35650f530e1SRichard Fitzgerald 										\
35750f530e1SRichard Fitzgerald 	fill_random_array(expect);						\
35850f530e1SRichard Fitzgerald 										\
35950f530e1SRichard Fitzgerald 	for (i = 0; i < ARRAY_SIZE(expect); i++) {				\
36050f530e1SRichard Fitzgerald 		if (i != 0)							\
36150f530e1SRichard Fitzgerald 			append_delim(test_buffer, &pos, BUF_SIZE,		\
36250f530e1SRichard Fitzgerald 				     fmt_buffer, &fmt_pos, BUF_SIZE,		\
36350f530e1SRichard Fitzgerald 				     field_sep);				\
36450f530e1SRichard Fitzgerald 										\
36550f530e1SRichard Fitzgerald 		append_fmt(test_buffer, &pos, BUF_SIZE, gen_fmt, expect[i]);	\
36650f530e1SRichard Fitzgerald 		append_fmt(fmt_buffer, &fmt_pos, BUF_SIZE, "%%%s", scan_fmt);	\
36750f530e1SRichard Fitzgerald 	}									\
36850f530e1SRichard Fitzgerald 										\
36950f530e1SRichard Fitzgerald 	test_array_8(fn, expect, test_buffer, fmt_buffer, result);		\
37050f530e1SRichard Fitzgerald } while (0)
37150f530e1SRichard Fitzgerald 
37250f530e1SRichard Fitzgerald #define numbers_list_fix_width(T, gen_fmt, field_sep, width, scan_fmt, fn)	\
37350f530e1SRichard Fitzgerald do {										\
37450f530e1SRichard Fitzgerald 	char full_fmt[16];							\
37550f530e1SRichard Fitzgerald 										\
37650f530e1SRichard Fitzgerald 	snprintf(full_fmt, sizeof(full_fmt), "%u%s", width, scan_fmt);		\
37750f530e1SRichard Fitzgerald 	numbers_list_8(T, gen_fmt, field_sep, full_fmt, fn);			\
37850f530e1SRichard Fitzgerald } while (0)
37950f530e1SRichard Fitzgerald 
38050f530e1SRichard Fitzgerald #define numbers_list_val_width(T, gen_fmt, field_sep, scan_fmt, fn)		\
38150f530e1SRichard Fitzgerald do {										\
38250f530e1SRichard Fitzgerald 	int i, val_len, pos = 0, fmt_pos = 0;					\
38350f530e1SRichard Fitzgerald 	T expect[8], result[8];							\
38450f530e1SRichard Fitzgerald 										\
38550f530e1SRichard Fitzgerald 	fill_random_array(expect);						\
38650f530e1SRichard Fitzgerald 										\
38750f530e1SRichard Fitzgerald 	for (i = 0; i < ARRAY_SIZE(expect); i++) {				\
38850f530e1SRichard Fitzgerald 		if (i != 0)							\
38950f530e1SRichard Fitzgerald 			append_delim(test_buffer, &pos, BUF_SIZE,		\
39050f530e1SRichard Fitzgerald 				     fmt_buffer, &fmt_pos, BUF_SIZE, field_sep);\
39150f530e1SRichard Fitzgerald 										\
39250f530e1SRichard Fitzgerald 		val_len = append_fmt(test_buffer, &pos, BUF_SIZE, gen_fmt,	\
39350f530e1SRichard Fitzgerald 				     expect[i]);				\
39450f530e1SRichard Fitzgerald 		append_fmt(fmt_buffer, &fmt_pos, BUF_SIZE,			\
39550f530e1SRichard Fitzgerald 			   "%%%u%s", val_len, scan_fmt);			\
39650f530e1SRichard Fitzgerald 	}									\
39750f530e1SRichard Fitzgerald 										\
39850f530e1SRichard Fitzgerald 	test_array_8(fn, expect, test_buffer, fmt_buffer, result);		\
39950f530e1SRichard Fitzgerald } while (0)
40050f530e1SRichard Fitzgerald 
40150f530e1SRichard Fitzgerald static void __init numbers_list(const char *delim)
40250f530e1SRichard Fitzgerald {
40350f530e1SRichard Fitzgerald 	numbers_list_8(unsigned long long, "%llu",   delim, "llu", check_ull);
40450f530e1SRichard Fitzgerald 	numbers_list_8(long long,	   "%lld",   delim, "lld", check_ll);
40550f530e1SRichard Fitzgerald 	numbers_list_8(long long,	   "%lld",   delim, "lli", check_ll);
40650f530e1SRichard Fitzgerald 	numbers_list_8(unsigned long long, "%llx",   delim, "llx", check_ull);
40750f530e1SRichard Fitzgerald 	numbers_list_8(unsigned long long, "0x%llx", delim, "llx", check_ull);
40850f530e1SRichard Fitzgerald 	numbers_list_8(long long,	   "0x%llx", delim, "lli", check_ll);
40950f530e1SRichard Fitzgerald 
41050f530e1SRichard Fitzgerald 	numbers_list_8(unsigned long,	   "%lu",    delim, "lu", check_ulong);
41150f530e1SRichard Fitzgerald 	numbers_list_8(long,		   "%ld",    delim, "ld", check_long);
41250f530e1SRichard Fitzgerald 	numbers_list_8(long,		   "%ld",    delim, "li", check_long);
41350f530e1SRichard Fitzgerald 	numbers_list_8(unsigned long,	   "%lx",    delim, "lx", check_ulong);
41450f530e1SRichard Fitzgerald 	numbers_list_8(unsigned long,	   "0x%lx",  delim, "lx", check_ulong);
41550f530e1SRichard Fitzgerald 	numbers_list_8(long,		   "0x%lx",  delim, "li", check_long);
41650f530e1SRichard Fitzgerald 
41750f530e1SRichard Fitzgerald 	numbers_list_8(unsigned int,	   "%u",     delim, "u", check_uint);
41850f530e1SRichard Fitzgerald 	numbers_list_8(int,		   "%d",     delim, "d", check_int);
41950f530e1SRichard Fitzgerald 	numbers_list_8(int,		   "%d",     delim, "i", check_int);
42050f530e1SRichard Fitzgerald 	numbers_list_8(unsigned int,	   "%x",     delim, "x", check_uint);
42150f530e1SRichard Fitzgerald 	numbers_list_8(unsigned int,	   "0x%x",   delim, "x", check_uint);
42250f530e1SRichard Fitzgerald 	numbers_list_8(int,		   "0x%x",   delim, "i", check_int);
42350f530e1SRichard Fitzgerald 
42450f530e1SRichard Fitzgerald 	numbers_list_8(unsigned short,	   "%hu",    delim, "hu", check_ushort);
42550f530e1SRichard Fitzgerald 	numbers_list_8(short,		   "%hd",    delim, "hd", check_short);
42650f530e1SRichard Fitzgerald 	numbers_list_8(short,		   "%hd",    delim, "hi", check_short);
42750f530e1SRichard Fitzgerald 	numbers_list_8(unsigned short,	   "%hx",    delim, "hx", check_ushort);
42850f530e1SRichard Fitzgerald 	numbers_list_8(unsigned short,	   "0x%hx",  delim, "hx", check_ushort);
42950f530e1SRichard Fitzgerald 	numbers_list_8(short,		   "0x%hx",  delim, "hi", check_short);
43050f530e1SRichard Fitzgerald 
43150f530e1SRichard Fitzgerald 	numbers_list_8(unsigned char,	   "%hhu",   delim, "hhu", check_uchar);
43250f530e1SRichard Fitzgerald 	numbers_list_8(signed char,	   "%hhd",   delim, "hhd", check_char);
43350f530e1SRichard Fitzgerald 	numbers_list_8(signed char,	   "%hhd",   delim, "hhi", check_char);
43450f530e1SRichard Fitzgerald 	numbers_list_8(unsigned char,	   "%hhx",   delim, "hhx", check_uchar);
43550f530e1SRichard Fitzgerald 	numbers_list_8(unsigned char,	   "0x%hhx", delim, "hhx", check_uchar);
43650f530e1SRichard Fitzgerald 	numbers_list_8(signed char,	   "0x%hhx", delim, "hhi", check_char);
43750f530e1SRichard Fitzgerald }
43850f530e1SRichard Fitzgerald 
43950f530e1SRichard Fitzgerald /*
44050f530e1SRichard Fitzgerald  * List of numbers separated by delim. Each field width specifier is the
44150f530e1SRichard Fitzgerald  * maximum possible digits for the given type and base.
44250f530e1SRichard Fitzgerald  */
44350f530e1SRichard Fitzgerald static void __init numbers_list_field_width_typemax(const char *delim)
44450f530e1SRichard Fitzgerald {
44550f530e1SRichard Fitzgerald 	numbers_list_fix_width(unsigned long long, "%llu",   delim, 20, "llu", check_ull);
44650f530e1SRichard Fitzgerald 	numbers_list_fix_width(long long,	   "%lld",   delim, 20, "lld", check_ll);
44750f530e1SRichard Fitzgerald 	numbers_list_fix_width(long long,	   "%lld",   delim, 20, "lli", check_ll);
44850f530e1SRichard Fitzgerald 	numbers_list_fix_width(unsigned long long, "%llx",   delim, 16, "llx", check_ull);
44950f530e1SRichard Fitzgerald 	numbers_list_fix_width(unsigned long long, "0x%llx", delim, 18, "llx", check_ull);
45050f530e1SRichard Fitzgerald 	numbers_list_fix_width(long long,	   "0x%llx", delim, 18, "lli", check_ll);
45150f530e1SRichard Fitzgerald 
45250f530e1SRichard Fitzgerald #if BITS_PER_LONG == 64
45350f530e1SRichard Fitzgerald 	numbers_list_fix_width(unsigned long,	"%lu",	     delim, 20, "lu", check_ulong);
45450f530e1SRichard Fitzgerald 	numbers_list_fix_width(long,		"%ld",	     delim, 20, "ld", check_long);
45550f530e1SRichard Fitzgerald 	numbers_list_fix_width(long,		"%ld",	     delim, 20, "li", check_long);
45650f530e1SRichard Fitzgerald 	numbers_list_fix_width(unsigned long,	"%lx",	     delim, 16, "lx", check_ulong);
45750f530e1SRichard Fitzgerald 	numbers_list_fix_width(unsigned long,	"0x%lx",     delim, 18, "lx", check_ulong);
45850f530e1SRichard Fitzgerald 	numbers_list_fix_width(long,		"0x%lx",     delim, 18, "li", check_long);
45950f530e1SRichard Fitzgerald #else
46050f530e1SRichard Fitzgerald 	numbers_list_fix_width(unsigned long,	"%lu",	     delim, 10, "lu", check_ulong);
46150f530e1SRichard Fitzgerald 	numbers_list_fix_width(long,		"%ld",	     delim, 11, "ld", check_long);
46250f530e1SRichard Fitzgerald 	numbers_list_fix_width(long,		"%ld",	     delim, 11, "li", check_long);
46350f530e1SRichard Fitzgerald 	numbers_list_fix_width(unsigned long,	"%lx",	     delim, 8,  "lx", check_ulong);
46450f530e1SRichard Fitzgerald 	numbers_list_fix_width(unsigned long,	"0x%lx",     delim, 10, "lx", check_ulong);
46550f530e1SRichard Fitzgerald 	numbers_list_fix_width(long,		"0x%lx",     delim, 10, "li", check_long);
46650f530e1SRichard Fitzgerald #endif
46750f530e1SRichard Fitzgerald 
46850f530e1SRichard Fitzgerald 	numbers_list_fix_width(unsigned int,	"%u",	     delim, 10, "u", check_uint);
46950f530e1SRichard Fitzgerald 	numbers_list_fix_width(int,		"%d",	     delim, 11, "d", check_int);
47050f530e1SRichard Fitzgerald 	numbers_list_fix_width(int,		"%d",	     delim, 11, "i", check_int);
47150f530e1SRichard Fitzgerald 	numbers_list_fix_width(unsigned int,	"%x",	     delim, 8,  "x", check_uint);
47250f530e1SRichard Fitzgerald 	numbers_list_fix_width(unsigned int,	"0x%x",	     delim, 10, "x", check_uint);
47350f530e1SRichard Fitzgerald 	numbers_list_fix_width(int,		"0x%x",	     delim, 10, "i", check_int);
47450f530e1SRichard Fitzgerald 
47550f530e1SRichard Fitzgerald 	numbers_list_fix_width(unsigned short,	"%hu",	     delim, 5, "hu", check_ushort);
47650f530e1SRichard Fitzgerald 	numbers_list_fix_width(short,		"%hd",	     delim, 6, "hd", check_short);
47750f530e1SRichard Fitzgerald 	numbers_list_fix_width(short,		"%hd",	     delim, 6, "hi", check_short);
47850f530e1SRichard Fitzgerald 	numbers_list_fix_width(unsigned short,	"%hx",	     delim, 4, "hx", check_ushort);
47950f530e1SRichard Fitzgerald 	numbers_list_fix_width(unsigned short,	"0x%hx",     delim, 6, "hx", check_ushort);
48050f530e1SRichard Fitzgerald 	numbers_list_fix_width(short,		"0x%hx",     delim, 6, "hi", check_short);
48150f530e1SRichard Fitzgerald 
48250f530e1SRichard Fitzgerald 	numbers_list_fix_width(unsigned char,	"%hhu",	     delim, 3, "hhu", check_uchar);
48350f530e1SRichard Fitzgerald 	numbers_list_fix_width(signed char,	"%hhd",	     delim, 4, "hhd", check_char);
48450f530e1SRichard Fitzgerald 	numbers_list_fix_width(signed char,	"%hhd",	     delim, 4, "hhi", check_char);
48550f530e1SRichard Fitzgerald 	numbers_list_fix_width(unsigned char,	"%hhx",	     delim, 2, "hhx", check_uchar);
48650f530e1SRichard Fitzgerald 	numbers_list_fix_width(unsigned char,	"0x%hhx",    delim, 4, "hhx", check_uchar);
48750f530e1SRichard Fitzgerald 	numbers_list_fix_width(signed char,	"0x%hhx",    delim, 4, "hhi", check_char);
48850f530e1SRichard Fitzgerald }
48950f530e1SRichard Fitzgerald 
49050f530e1SRichard Fitzgerald /*
49150f530e1SRichard Fitzgerald  * List of numbers separated by delim. Each field width specifier is the
49250f530e1SRichard Fitzgerald  * exact length of the corresponding value digits in the string being scanned.
49350f530e1SRichard Fitzgerald  */
49450f530e1SRichard Fitzgerald static void __init numbers_list_field_width_val_width(const char *delim)
49550f530e1SRichard Fitzgerald {
49650f530e1SRichard Fitzgerald 	numbers_list_val_width(unsigned long long, "%llu",   delim, "llu", check_ull);
49750f530e1SRichard Fitzgerald 	numbers_list_val_width(long long,	   "%lld",   delim, "lld", check_ll);
49850f530e1SRichard Fitzgerald 	numbers_list_val_width(long long,	   "%lld",   delim, "lli", check_ll);
49950f530e1SRichard Fitzgerald 	numbers_list_val_width(unsigned long long, "%llx",   delim, "llx", check_ull);
50050f530e1SRichard Fitzgerald 	numbers_list_val_width(unsigned long long, "0x%llx", delim, "llx", check_ull);
50150f530e1SRichard Fitzgerald 	numbers_list_val_width(long long,	   "0x%llx", delim, "lli", check_ll);
50250f530e1SRichard Fitzgerald 
50350f530e1SRichard Fitzgerald 	numbers_list_val_width(unsigned long,	"%lu",	     delim, "lu", check_ulong);
50450f530e1SRichard Fitzgerald 	numbers_list_val_width(long,		"%ld",	     delim, "ld", check_long);
50550f530e1SRichard Fitzgerald 	numbers_list_val_width(long,		"%ld",	     delim, "li", check_long);
50650f530e1SRichard Fitzgerald 	numbers_list_val_width(unsigned long,	"%lx",	     delim, "lx", check_ulong);
50750f530e1SRichard Fitzgerald 	numbers_list_val_width(unsigned long,	"0x%lx",     delim, "lx", check_ulong);
50850f530e1SRichard Fitzgerald 	numbers_list_val_width(long,		"0x%lx",     delim, "li", check_long);
50950f530e1SRichard Fitzgerald 
51050f530e1SRichard Fitzgerald 	numbers_list_val_width(unsigned int,	"%u",	     delim, "u", check_uint);
51150f530e1SRichard Fitzgerald 	numbers_list_val_width(int,		"%d",	     delim, "d", check_int);
51250f530e1SRichard Fitzgerald 	numbers_list_val_width(int,		"%d",	     delim, "i", check_int);
51350f530e1SRichard Fitzgerald 	numbers_list_val_width(unsigned int,	"%x",	     delim, "x", check_uint);
51450f530e1SRichard Fitzgerald 	numbers_list_val_width(unsigned int,	"0x%x",	     delim, "x", check_uint);
51550f530e1SRichard Fitzgerald 	numbers_list_val_width(int,		"0x%x",	     delim, "i", check_int);
51650f530e1SRichard Fitzgerald 
51750f530e1SRichard Fitzgerald 	numbers_list_val_width(unsigned short,	"%hu",	     delim, "hu", check_ushort);
51850f530e1SRichard Fitzgerald 	numbers_list_val_width(short,		"%hd",	     delim, "hd", check_short);
51950f530e1SRichard Fitzgerald 	numbers_list_val_width(short,		"%hd",	     delim, "hi", check_short);
52050f530e1SRichard Fitzgerald 	numbers_list_val_width(unsigned short,	"%hx",	     delim, "hx", check_ushort);
52150f530e1SRichard Fitzgerald 	numbers_list_val_width(unsigned short,	"0x%hx",     delim, "hx", check_ushort);
52250f530e1SRichard Fitzgerald 	numbers_list_val_width(short,		"0x%hx",     delim, "hi", check_short);
52350f530e1SRichard Fitzgerald 
52450f530e1SRichard Fitzgerald 	numbers_list_val_width(unsigned char,	"%hhu",	     delim, "hhu", check_uchar);
52550f530e1SRichard Fitzgerald 	numbers_list_val_width(signed char,	"%hhd",	     delim, "hhd", check_char);
52650f530e1SRichard Fitzgerald 	numbers_list_val_width(signed char,	"%hhd",	     delim, "hhi", check_char);
52750f530e1SRichard Fitzgerald 	numbers_list_val_width(unsigned char,	"%hhx",	     delim, "hhx", check_uchar);
52850f530e1SRichard Fitzgerald 	numbers_list_val_width(unsigned char,	"0x%hhx",    delim, "hhx", check_uchar);
52950f530e1SRichard Fitzgerald 	numbers_list_val_width(signed char,	"0x%hhx",    delim, "hhi", check_char);
53050f530e1SRichard Fitzgerald }
53150f530e1SRichard Fitzgerald 
53250f530e1SRichard Fitzgerald /*
53350f530e1SRichard Fitzgerald  * Slice a continuous string of digits without field delimiters, containing
53450f530e1SRichard Fitzgerald  * numbers of varying length, using the field width to extract each group
53550f530e1SRichard Fitzgerald  * of digits. For example the hex values c0,3,bf01,303 would have a
53650f530e1SRichard Fitzgerald  * string representation of "c03bf01303" and extracted with "%2x%1x%4x%3x".
53750f530e1SRichard Fitzgerald  */
53850f530e1SRichard Fitzgerald static void __init numbers_slice(void)
53950f530e1SRichard Fitzgerald {
54050f530e1SRichard Fitzgerald 	numbers_list_field_width_val_width("");
54150f530e1SRichard Fitzgerald }
54250f530e1SRichard Fitzgerald 
54350f530e1SRichard Fitzgerald #define test_number_prefix(T, str, scan_fmt, expect0, expect1, n_args, fn)	\
54450f530e1SRichard Fitzgerald do {										\
54550f530e1SRichard Fitzgerald 	const T expect[2] = { expect0, expect1 };				\
54650f530e1SRichard Fitzgerald 	T result[2] = {~expect[0], ~expect[1]};					\
54750f530e1SRichard Fitzgerald 										\
54850f530e1SRichard Fitzgerald 	_test(fn, &expect, str, scan_fmt, n_args, &result[0], &result[1]);	\
54950f530e1SRichard Fitzgerald } while (0)
55050f530e1SRichard Fitzgerald 
55150f530e1SRichard Fitzgerald /*
55250f530e1SRichard Fitzgerald  * Number prefix is >= field width.
55350f530e1SRichard Fitzgerald  * Expected behaviour is derived from testing userland sscanf.
55450f530e1SRichard Fitzgerald  */
55550f530e1SRichard Fitzgerald static void __init numbers_prefix_overflow(void)
55650f530e1SRichard Fitzgerald {
55750f530e1SRichard Fitzgerald 	/*
55850f530e1SRichard Fitzgerald 	 * Negative decimal with a field of width 1, should quit scanning
55950f530e1SRichard Fitzgerald 	 * and return 0.
56050f530e1SRichard Fitzgerald 	 */
56150f530e1SRichard Fitzgerald 	test_number_prefix(long long,	"-1 1", "%1lld %lld",	0, 0, 0, check_ll);
56250f530e1SRichard Fitzgerald 	test_number_prefix(long,	"-1 1", "%1ld %ld",	0, 0, 0, check_long);
56350f530e1SRichard Fitzgerald 	test_number_prefix(int,		"-1 1", "%1d %d",	0, 0, 0, check_int);
56450f530e1SRichard Fitzgerald 	test_number_prefix(short,	"-1 1", "%1hd %hd",	0, 0, 0, check_short);
56550f530e1SRichard Fitzgerald 	test_number_prefix(signed char,	"-1 1", "%1hhd %hhd",	0, 0, 0, check_char);
56650f530e1SRichard Fitzgerald 
56750f530e1SRichard Fitzgerald 	test_number_prefix(long long,	"-1 1", "%1lli %lli",	0, 0, 0, check_ll);
56850f530e1SRichard Fitzgerald 	test_number_prefix(long,	"-1 1", "%1li %li",	0, 0, 0, check_long);
56950f530e1SRichard Fitzgerald 	test_number_prefix(int,		"-1 1", "%1i %i",	0, 0, 0, check_int);
57050f530e1SRichard Fitzgerald 	test_number_prefix(short,	"-1 1", "%1hi %hi",	0, 0, 0, check_short);
57150f530e1SRichard Fitzgerald 	test_number_prefix(signed char,	"-1 1", "%1hhi %hhi",	0, 0, 0, check_char);
57250f530e1SRichard Fitzgerald 
57350f530e1SRichard Fitzgerald 	/*
57450f530e1SRichard Fitzgerald 	 * 0x prefix in a field of width 1: 0 is a valid digit so should
57550f530e1SRichard Fitzgerald 	 * convert. Next field scan starts at the 'x' which isn't a digit so
57650f530e1SRichard Fitzgerald 	 * scan quits with one field converted.
57750f530e1SRichard Fitzgerald 	 */
57850f530e1SRichard Fitzgerald 	test_number_prefix(unsigned long long,	"0xA7", "%1llx%llx", 0, 0, 1, check_ull);
57950f530e1SRichard Fitzgerald 	test_number_prefix(unsigned long,	"0xA7", "%1lx%lx",   0, 0, 1, check_ulong);
58050f530e1SRichard Fitzgerald 	test_number_prefix(unsigned int,	"0xA7", "%1x%x",     0, 0, 1, check_uint);
58150f530e1SRichard Fitzgerald 	test_number_prefix(unsigned short,	"0xA7", "%1hx%hx",   0, 0, 1, check_ushort);
58250f530e1SRichard Fitzgerald 	test_number_prefix(unsigned char,	"0xA7", "%1hhx%hhx", 0, 0, 1, check_uchar);
58350f530e1SRichard Fitzgerald 	test_number_prefix(long long,		"0xA7", "%1lli%llx", 0, 0, 1, check_ll);
58450f530e1SRichard Fitzgerald 	test_number_prefix(long,		"0xA7", "%1li%lx",   0, 0, 1, check_long);
58550f530e1SRichard Fitzgerald 	test_number_prefix(int,			"0xA7", "%1i%x",     0, 0, 1, check_int);
58650f530e1SRichard Fitzgerald 	test_number_prefix(short,		"0xA7", "%1hi%hx",   0, 0, 1, check_short);
58750f530e1SRichard Fitzgerald 	test_number_prefix(char,		"0xA7", "%1hhi%hhx", 0, 0, 1, check_char);
58850f530e1SRichard Fitzgerald 
58950f530e1SRichard Fitzgerald 	/*
59050f530e1SRichard Fitzgerald 	 * 0x prefix in a field of width 2 using %x conversion: first field
59150f530e1SRichard Fitzgerald 	 * converts to 0. Next field scan starts at the character after "0x".
59250f530e1SRichard Fitzgerald 	 * Both fields will convert.
59350f530e1SRichard Fitzgerald 	 */
59450f530e1SRichard Fitzgerald 	test_number_prefix(unsigned long long,	"0xA7", "%2llx%llx", 0, 0xa7, 2, check_ull);
59550f530e1SRichard Fitzgerald 	test_number_prefix(unsigned long,	"0xA7", "%2lx%lx",   0, 0xa7, 2, check_ulong);
59650f530e1SRichard Fitzgerald 	test_number_prefix(unsigned int,	"0xA7", "%2x%x",     0, 0xa7, 2, check_uint);
59750f530e1SRichard Fitzgerald 	test_number_prefix(unsigned short,	"0xA7", "%2hx%hx",   0, 0xa7, 2, check_ushort);
59850f530e1SRichard Fitzgerald 	test_number_prefix(unsigned char,	"0xA7", "%2hhx%hhx", 0, 0xa7, 2, check_uchar);
59950f530e1SRichard Fitzgerald 
60050f530e1SRichard Fitzgerald 	/*
60150f530e1SRichard Fitzgerald 	 * 0x prefix in a field of width 2 using %i conversion: first field
60250f530e1SRichard Fitzgerald 	 * converts to 0. Next field scan starts at the character after "0x",
603*53b0fe36SZhen Lei 	 * which will convert if can be interpreted as decimal but will fail
60450f530e1SRichard Fitzgerald 	 * if it contains any hex digits (since no 0x prefix).
60550f530e1SRichard Fitzgerald 	 */
60650f530e1SRichard Fitzgerald 	test_number_prefix(long long,	"0x67", "%2lli%lli", 0, 67, 2, check_ll);
60750f530e1SRichard Fitzgerald 	test_number_prefix(long,	"0x67", "%2li%li",   0, 67, 2, check_long);
60850f530e1SRichard Fitzgerald 	test_number_prefix(int,		"0x67", "%2i%i",     0, 67, 2, check_int);
60950f530e1SRichard Fitzgerald 	test_number_prefix(short,	"0x67", "%2hi%hi",   0, 67, 2, check_short);
61050f530e1SRichard Fitzgerald 	test_number_prefix(char,	"0x67", "%2hhi%hhi", 0, 67, 2, check_char);
61150f530e1SRichard Fitzgerald 
61250f530e1SRichard Fitzgerald 	test_number_prefix(long long,	"0xA7", "%2lli%lli", 0, 0,  1, check_ll);
61350f530e1SRichard Fitzgerald 	test_number_prefix(long,	"0xA7", "%2li%li",   0, 0,  1, check_long);
61450f530e1SRichard Fitzgerald 	test_number_prefix(int,		"0xA7", "%2i%i",     0, 0,  1, check_int);
61550f530e1SRichard Fitzgerald 	test_number_prefix(short,	"0xA7", "%2hi%hi",   0, 0,  1, check_short);
61650f530e1SRichard Fitzgerald 	test_number_prefix(char,	"0xA7", "%2hhi%hhi", 0, 0,  1, check_char);
61750f530e1SRichard Fitzgerald }
61850f530e1SRichard Fitzgerald 
61950f530e1SRichard Fitzgerald #define _test_simple_strtoxx(T, fn, gen_fmt, expect, base)			\
62050f530e1SRichard Fitzgerald do {										\
62150f530e1SRichard Fitzgerald 	T got;									\
62250f530e1SRichard Fitzgerald 	char *endp;								\
62350f530e1SRichard Fitzgerald 	int len;								\
62450f530e1SRichard Fitzgerald 	bool fail = false;							\
62550f530e1SRichard Fitzgerald 										\
62650f530e1SRichard Fitzgerald 	total_tests++;								\
62750f530e1SRichard Fitzgerald 	len = snprintf(test_buffer, BUF_SIZE, gen_fmt, expect);			\
62850f530e1SRichard Fitzgerald 	got = (fn)(test_buffer, &endp, base);					\
62950f530e1SRichard Fitzgerald 	pr_debug(#fn "(\"%s\", %d) -> " gen_fmt "\n", test_buffer, base, got);	\
63050f530e1SRichard Fitzgerald 	if (got != (expect)) {							\
63150f530e1SRichard Fitzgerald 		fail = true;							\
63250f530e1SRichard Fitzgerald 		pr_warn(#fn "(\"%s\", %d): got " gen_fmt " expected " gen_fmt "\n", \
63350f530e1SRichard Fitzgerald 			test_buffer, base, got, expect);			\
63450f530e1SRichard Fitzgerald 	} else if (endp != test_buffer + len) {					\
63550f530e1SRichard Fitzgerald 		fail = true;							\
63650f530e1SRichard Fitzgerald 		pr_warn(#fn "(\"%s\", %d) startp=0x%px got endp=0x%px expected 0x%px\n", \
63750f530e1SRichard Fitzgerald 			test_buffer, base, test_buffer,				\
63850f530e1SRichard Fitzgerald 			test_buffer + len, endp);				\
63950f530e1SRichard Fitzgerald 	}									\
64050f530e1SRichard Fitzgerald 										\
64150f530e1SRichard Fitzgerald 	if (fail)								\
64250f530e1SRichard Fitzgerald 		failed_tests++;							\
64350f530e1SRichard Fitzgerald } while (0)
64450f530e1SRichard Fitzgerald 
64550f530e1SRichard Fitzgerald #define test_simple_strtoxx(T, fn, gen_fmt, base)				\
64650f530e1SRichard Fitzgerald do {										\
64750f530e1SRichard Fitzgerald 	int i;									\
64850f530e1SRichard Fitzgerald 										\
64950f530e1SRichard Fitzgerald 	for (i = 0; i < ARRAY_SIZE(numbers); i++) {				\
65050f530e1SRichard Fitzgerald 		_test_simple_strtoxx(T, fn, gen_fmt, (T)numbers[i], base);	\
65150f530e1SRichard Fitzgerald 										\
65250f530e1SRichard Fitzgerald 		if (is_signed_type(T))						\
65350f530e1SRichard Fitzgerald 			_test_simple_strtoxx(T, fn, gen_fmt,			\
65450f530e1SRichard Fitzgerald 					      -(T)numbers[i], base);		\
65550f530e1SRichard Fitzgerald 	}									\
65650f530e1SRichard Fitzgerald } while (0)
65750f530e1SRichard Fitzgerald 
65850f530e1SRichard Fitzgerald static void __init test_simple_strtoull(void)
65950f530e1SRichard Fitzgerald {
66050f530e1SRichard Fitzgerald 	test_simple_strtoxx(unsigned long long, simple_strtoull, "%llu",   10);
66150f530e1SRichard Fitzgerald 	test_simple_strtoxx(unsigned long long, simple_strtoull, "%llu",   0);
66250f530e1SRichard Fitzgerald 	test_simple_strtoxx(unsigned long long, simple_strtoull, "%llx",   16);
66350f530e1SRichard Fitzgerald 	test_simple_strtoxx(unsigned long long, simple_strtoull, "0x%llx", 16);
66450f530e1SRichard Fitzgerald 	test_simple_strtoxx(unsigned long long, simple_strtoull, "0x%llx", 0);
66550f530e1SRichard Fitzgerald }
66650f530e1SRichard Fitzgerald 
66750f530e1SRichard Fitzgerald static void __init test_simple_strtoll(void)
66850f530e1SRichard Fitzgerald {
66950f530e1SRichard Fitzgerald 	test_simple_strtoxx(long long, simple_strtoll, "%lld",	 10);
67050f530e1SRichard Fitzgerald 	test_simple_strtoxx(long long, simple_strtoll, "%lld",	 0);
67150f530e1SRichard Fitzgerald 	test_simple_strtoxx(long long, simple_strtoll, "%llx",	 16);
67250f530e1SRichard Fitzgerald 	test_simple_strtoxx(long long, simple_strtoll, "0x%llx", 16);
67350f530e1SRichard Fitzgerald 	test_simple_strtoxx(long long, simple_strtoll, "0x%llx", 0);
67450f530e1SRichard Fitzgerald }
67550f530e1SRichard Fitzgerald 
67650f530e1SRichard Fitzgerald static void __init test_simple_strtoul(void)
67750f530e1SRichard Fitzgerald {
67850f530e1SRichard Fitzgerald 	test_simple_strtoxx(unsigned long, simple_strtoul, "%lu",   10);
67950f530e1SRichard Fitzgerald 	test_simple_strtoxx(unsigned long, simple_strtoul, "%lu",   0);
68050f530e1SRichard Fitzgerald 	test_simple_strtoxx(unsigned long, simple_strtoul, "%lx",   16);
68150f530e1SRichard Fitzgerald 	test_simple_strtoxx(unsigned long, simple_strtoul, "0x%lx", 16);
68250f530e1SRichard Fitzgerald 	test_simple_strtoxx(unsigned long, simple_strtoul, "0x%lx", 0);
68350f530e1SRichard Fitzgerald }
68450f530e1SRichard Fitzgerald 
68550f530e1SRichard Fitzgerald static void __init test_simple_strtol(void)
68650f530e1SRichard Fitzgerald {
68750f530e1SRichard Fitzgerald 	test_simple_strtoxx(long, simple_strtol, "%ld",   10);
68850f530e1SRichard Fitzgerald 	test_simple_strtoxx(long, simple_strtol, "%ld",   0);
68950f530e1SRichard Fitzgerald 	test_simple_strtoxx(long, simple_strtol, "%lx",   16);
69050f530e1SRichard Fitzgerald 	test_simple_strtoxx(long, simple_strtol, "0x%lx", 16);
69150f530e1SRichard Fitzgerald 	test_simple_strtoxx(long, simple_strtol, "0x%lx", 0);
69250f530e1SRichard Fitzgerald }
69350f530e1SRichard Fitzgerald 
69450f530e1SRichard Fitzgerald /* Selection of common delimiters/separators between numbers in a string. */
69550f530e1SRichard Fitzgerald static const char * const number_delimiters[] __initconst = {
69650f530e1SRichard Fitzgerald 	" ", ":", ",", "-", "/",
69750f530e1SRichard Fitzgerald };
69850f530e1SRichard Fitzgerald 
69950f530e1SRichard Fitzgerald static void __init test_numbers(void)
70050f530e1SRichard Fitzgerald {
70150f530e1SRichard Fitzgerald 	int i;
70250f530e1SRichard Fitzgerald 
70350f530e1SRichard Fitzgerald 	/* String containing only one number. */
70450f530e1SRichard Fitzgerald 	numbers_simple();
70550f530e1SRichard Fitzgerald 
70650f530e1SRichard Fitzgerald 	/* String with multiple numbers separated by delimiter. */
70750f530e1SRichard Fitzgerald 	for (i = 0; i < ARRAY_SIZE(number_delimiters); i++) {
70850f530e1SRichard Fitzgerald 		numbers_list(number_delimiters[i]);
70950f530e1SRichard Fitzgerald 
71050f530e1SRichard Fitzgerald 		/* Field width may be longer than actual field digits. */
71150f530e1SRichard Fitzgerald 		numbers_list_field_width_typemax(number_delimiters[i]);
71250f530e1SRichard Fitzgerald 
71350f530e1SRichard Fitzgerald 		/* Each field width exactly length of actual field digits. */
71450f530e1SRichard Fitzgerald 		numbers_list_field_width_val_width(number_delimiters[i]);
71550f530e1SRichard Fitzgerald 	}
71650f530e1SRichard Fitzgerald 
71750f530e1SRichard Fitzgerald 	/* Slice continuous sequence of digits using field widths. */
71850f530e1SRichard Fitzgerald 	numbers_slice();
71950f530e1SRichard Fitzgerald 
72050f530e1SRichard Fitzgerald 	numbers_prefix_overflow();
72150f530e1SRichard Fitzgerald }
72250f530e1SRichard Fitzgerald 
72350f530e1SRichard Fitzgerald static void __init selftest(void)
72450f530e1SRichard Fitzgerald {
72550f530e1SRichard Fitzgerald 	test_buffer = kmalloc(BUF_SIZE, GFP_KERNEL);
72650f530e1SRichard Fitzgerald 	if (!test_buffer)
72750f530e1SRichard Fitzgerald 		return;
72850f530e1SRichard Fitzgerald 
72950f530e1SRichard Fitzgerald 	fmt_buffer = kmalloc(BUF_SIZE, GFP_KERNEL);
73050f530e1SRichard Fitzgerald 	if (!fmt_buffer) {
73150f530e1SRichard Fitzgerald 		kfree(test_buffer);
73250f530e1SRichard Fitzgerald 		return;
73350f530e1SRichard Fitzgerald 	}
73450f530e1SRichard Fitzgerald 
73550f530e1SRichard Fitzgerald 	prandom_seed_state(&rnd_state, 3141592653589793238ULL);
73650f530e1SRichard Fitzgerald 
73750f530e1SRichard Fitzgerald 	test_numbers();
73850f530e1SRichard Fitzgerald 
73950f530e1SRichard Fitzgerald 	test_simple_strtoull();
74050f530e1SRichard Fitzgerald 	test_simple_strtoll();
74150f530e1SRichard Fitzgerald 	test_simple_strtoul();
74250f530e1SRichard Fitzgerald 	test_simple_strtol();
74350f530e1SRichard Fitzgerald 
74450f530e1SRichard Fitzgerald 	kfree(fmt_buffer);
74550f530e1SRichard Fitzgerald 	kfree(test_buffer);
74650f530e1SRichard Fitzgerald }
74750f530e1SRichard Fitzgerald 
74850f530e1SRichard Fitzgerald KSTM_MODULE_LOADERS(test_scanf);
74950f530e1SRichard Fitzgerald MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
75050f530e1SRichard Fitzgerald MODULE_LICENSE("GPL v2");
751