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