move-lib-kunit for v6.15-rc1

- move lib/ selftests into lib/tests/ (Kees Cook, Gabriela Bittencourt,
   Luis Felipe Hernandez, Lukas Bulwahn, Tamir Duberstein)
 
 - lib/math: Add int_log test suite (Bruno Sobreira França)
 
 - lib/math: Add Kunit test suite for gcd() (Yu-Chun Lin)
 
 - lib/tests/kfifo_kunit.c: add tests for the kfifo structure (Diego Vieira)
 
 - unicode: refactor selftests into KUnit (Gabriela Bittencourt)
 
 - lib/prime_numbers: convert self-test to KUnit (Tamir Duberstein)
 
 - printf: convert self-test to KUnit (Tamir Duberstein)
 
 - scanf: convert self-test to KUnit (Tamir Duberstein)
 -----BEGIN PGP SIGNATURE-----
 
 iHUEABYKAB0WIQRSPkdeREjth1dHnSE2KwveOeQkuwUCZ9hCvgAKCRA2KwveOeQk
 u1nzAP9F/vQZUPkU9ADuqdcbyyEXlTzNk8R5rC2e1w+uKzJx+QD9EAbeCv9ZLdC0
 KQF0pWVYCJtiSMEhkiMS/bMmpRCgwQ8=
 =VYZG
 -----END PGP SIGNATURE-----

Merge tag 'move-lib-kunit-v6.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux

Pull lib kunit selftest move from Kees Cook:
 "This is a one-off tree to coordinate the move of selftests out of lib/
  and into lib/tests/. A separate tree was used for this to keep the
  paths sane with all the work in the same place.

   - move lib/ selftests into lib/tests/ (Kees Cook, Gabriela
     Bittencourt, Luis Felipe Hernandez, Lukas Bulwahn, Tamir
     Duberstein)

   - lib/math: Add int_log test suite (Bruno Sobreira França)

   - lib/math: Add Kunit test suite for gcd() (Yu-Chun Lin)

   - lib/tests/kfifo_kunit.c: add tests for the kfifo structure (Diego
     Vieira)

   - unicode: refactor selftests into KUnit (Gabriela Bittencourt)

   - lib/prime_numbers: convert self-test to KUnit (Tamir Duberstein)

   - printf: convert self-test to KUnit (Tamir Duberstein)

   - scanf: convert self-test to KUnit (Tamir Duberstein)"

* tag 'move-lib-kunit-v6.15-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux: (21 commits)
  scanf: break kunit into test cases
  scanf: convert self-test to KUnit
  scanf: remove redundant debug logs
  scanf: implicate test line in failure messages
  printf: implicate test line in failure messages
  printf: break kunit into test cases
  printf: convert self-test to KUnit
  kunit/fortify: Replace "volatile" with OPTIMIZER_HIDE_VAR()
  kunit/fortify: Expand testing of __compiletime_strlen()
  kunit/stackinit: Use fill byte different from Clang i386 pattern
  kunit/overflow: Fix DEFINE_FLEX tests for counted_by
  selftests: remove reference to prime_numbers.sh
  MAINTAINERS: adjust entries in FORTIFY_SOURCE and KERNEL HARDENING
  lib/prime_numbers: convert self-test to KUnit
  lib/math: Add Kunit test suite for gcd()
  unicode: kunit: change tests filename and path
  unicode: kunit: refactor selftest to kunit tests
  lib/tests/kfifo_kunit.c: add tests for the kfifo structure
  lib: Move KUnit tests into tests/ subdirectory
  lib/math: Add int_log test suite
  ...
This commit is contained in:
Linus Torvalds 2025-03-24 15:15:11 -07:00
commit 06961fbbbd
54 changed files with 1154 additions and 728 deletions

View File

@ -661,7 +661,7 @@ Do *not* use it from C.
Thanks
======
If you add other %p extensions, please extend <lib/test_printf.c> with
one or more test cases, if at all feasible.
If you add other %p extensions, please extend <lib/tests/printf_kunit.c>
with one or more test cases, if at all feasible.
Thank you for your cooperation and attention.

View File

@ -347,7 +347,7 @@ kselftest. We use kselftests for lib/ as an example.
1. Create the test module
2. Create the test script that will run (load/unload) the module
e.g. ``tools/testing/selftests/lib/printf.sh``
e.g. ``tools/testing/selftests/lib/bitmap.sh``
3. Add line to config file e.g. ``tools/testing/selftests/lib/config``

View File

@ -4014,10 +4014,10 @@ F: include/vdso/bits.h
F: lib/bitmap-str.c
F: lib/bitmap.c
F: lib/cpumask.c
F: lib/cpumask_kunit.c
F: lib/find_bit.c
F: lib/find_bit_benchmark.c
F: lib/test_bitmap.c
F: lib/tests/cpumask_kunit.c
F: tools/include/linux/bitfield.h
F: tools/include/linux/bitmap.h
F: tools/include/linux/bits.h
@ -9075,9 +9075,9 @@ L: linux-hardening@vger.kernel.org
S: Supported
T: git git://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git for-next/hardening
F: include/linux/fortify-string.h
F: lib/fortify_kunit.c
F: lib/memcpy_kunit.c
F: lib/test_fortify/*
F: lib/tests/fortify_kunit.c
F: lib/tests/memcpy_kunit.c
K: \bunsafe_memcpy\b
K: \b__NO_FORTIFY\b
@ -9762,9 +9762,9 @@ F: include/linux/string.h
F: include/linux/string_choices.h
F: include/linux/string_helpers.h
F: lib/string.c
F: lib/string_kunit.c
F: lib/string_helpers.c
F: lib/string_helpers_kunit.c
F: lib/tests/string_helpers_kunit.c
F: lib/tests/string_kunit.c
F: scripts/coccinelle/api/string_choices.cocci
GENERIC UIO DRIVER FOR PCI DEVICES
@ -12592,7 +12592,7 @@ F: arch/*/configs/hardening.config
F: include/linux/overflow.h
F: include/linux/randomize_kstack.h
F: kernel/configs/hardening.config
F: lib/usercopy_kunit.c
F: lib/tests/usercopy_kunit.c
F: mm/usercopy.c
F: security/Kconfig.hardening
K: \b(add|choose)_random_kstack_offset\b
@ -12990,7 +12990,7 @@ F: Documentation/trace/kprobes.rst
F: include/asm-generic/kprobes.h
F: include/linux/kprobes.h
F: kernel/kprobes.c
F: lib/test_kprobes.c
F: lib/tests/test_kprobes.c
F: samples/kprobes
KS0108 LCD CONTROLLER DRIVER
@ -13320,7 +13320,7 @@ M: Mark Brown <broonie@kernel.org>
R: Matti Vaittinen <mazziesaccount@gmail.com>
F: include/linux/linear_range.h
F: lib/linear_ranges.c
F: lib/test_linear_ranges.c
F: lib/tests/test_linear_ranges.c
LINUX FOR POWER MACINTOSH
L: linuxppc-dev@lists.ozlabs.org
@ -13448,7 +13448,7 @@ M: David Gow <davidgow@google.com>
L: linux-kselftest@vger.kernel.org
L: kunit-dev@googlegroups.com
S: Maintained
F: lib/list-test.c
F: lib/tests/list-test.c
LITEX PLATFORM
M: Karol Gugala <kgugala@antmicro.com>
@ -21778,7 +21778,7 @@ M: Jason A. Donenfeld <Jason@zx2c4.com>
S: Maintained
F: include/linux/siphash.h
F: lib/siphash.c
F: lib/siphash_kunit.c
F: lib/tests/siphash_kunit.c
SIS 190 ETHERNET DRIVER
M: Francois Romieu <romieu@fr.zoreil.com>
@ -25453,8 +25453,8 @@ R: Sergey Senozhatsky <senozhatsky@chromium.org>
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux.git
F: Documentation/core-api/printk-formats.rst
F: lib/test_printf.c
F: lib/test_scanf.c
F: lib/tests/printf_kunit.c
F: lib/tests/scanf_kunit.c
F: lib/vsprintf.c
VT1211 HARDWARE MONITOR DRIVER

View File

@ -10,6 +10,7 @@ config UNICODE
be a separate loadable module that gets requested only when a file
system actually use it.
config UNICODE_NORMALIZATION_SELFTEST
config UNICODE_NORMALIZATION_KUNIT_TEST
tristate "Test UTF-8 normalization support"
depends on UNICODE
depends on UNICODE && KUNIT
default KUNIT_ALL_TESTS

View File

@ -4,7 +4,7 @@ ifneq ($(CONFIG_UNICODE),)
obj-y += unicode.o
endif
obj-$(CONFIG_UNICODE) += utf8data.o
obj-$(CONFIG_UNICODE_NORMALIZATION_SELFTEST) += utf8-selftest.o
obj-$(CONFIG_UNICODE_NORMALIZATION_KUNIT_TEST) += tests/utf8_kunit.o
unicode-y := utf8-norm.o utf8-core.o

View File

@ -0,0 +1,3 @@
CONFIG_KUNIT=y
CONFIG_UNICODE=y
CONFIG_UNICODE_NORMALIZATION_KUNIT_TEST=y

View File

@ -1,34 +1,14 @@
// SPDX-License-Identifier: GPL-2.0-only
/*
* Kernel module for testing utf-8 support.
* KUnit tests for utf-8 support.
*
* Copyright 2017 Collabora Ltd.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
#include <linux/printk.h>
#include <linux/unicode.h>
#include <linux/dcache.h>
#include <kunit/test.h>
#include "utf8n.h"
static unsigned int failed_tests;
static unsigned int total_tests;
#define _test(cond, func, line, fmt, ...) do { \
total_tests++; \
if (!cond) { \
failed_tests++; \
pr_err("test %s:%d Failed: %s%s", \
func, line, #cond, (fmt?":":".")); \
if (fmt) \
pr_err(fmt, ##__VA_ARGS__); \
} \
} while (0)
#define test_f(cond, fmt, ...) _test(cond, __func__, __LINE__, fmt, ##__VA_ARGS__)
#define test(cond) _test(cond, __func__, __LINE__, "")
#include "../utf8n.h"
static const struct {
/* UTF-8 strings in this vector _must_ be NULL-terminated. */
@ -167,69 +147,74 @@ static int utf8cursor(struct utf8cursor *u8c, const struct unicode_map *um,
return utf8ncursor(u8c, um, n, s, (unsigned int)-1);
}
static void check_utf8_nfdi(struct unicode_map *um)
static void check_utf8_nfdi(struct kunit *test)
{
int i;
struct utf8cursor u8c;
struct unicode_map *um = test->priv;
for (i = 0; i < ARRAY_SIZE(nfdi_test_data); i++) {
int len = strlen(nfdi_test_data[i].str);
int nlen = strlen(nfdi_test_data[i].dec);
int j = 0;
unsigned char c;
int ret;
test((utf8len(um, UTF8_NFDI, nfdi_test_data[i].str) == nlen));
test((utf8nlen(um, UTF8_NFDI, nfdi_test_data[i].str, len) ==
nlen));
KUNIT_EXPECT_EQ(test, utf8len(um, UTF8_NFDI, nfdi_test_data[i].str), nlen);
KUNIT_EXPECT_EQ(test, utf8nlen(um, UTF8_NFDI, nfdi_test_data[i].str, len),
nlen);
if (utf8cursor(&u8c, um, UTF8_NFDI, nfdi_test_data[i].str) < 0)
pr_err("can't create cursor\n");
ret = utf8cursor(&u8c, um, UTF8_NFDI, nfdi_test_data[i].str);
KUNIT_EXPECT_TRUE_MSG(test, ret >= 0, "Can't create cursor\n");
while ((c = utf8byte(&u8c)) > 0) {
test_f((c == nfdi_test_data[i].dec[j]),
"Unexpected byte 0x%x should be 0x%x\n",
c, nfdi_test_data[i].dec[j]);
KUNIT_EXPECT_EQ_MSG(test, c, nfdi_test_data[i].dec[j],
"Unexpected byte 0x%x should be 0x%x\n",
c, nfdi_test_data[i].dec[j]);
j++;
}
test((j == nlen));
KUNIT_EXPECT_EQ(test, j, nlen);
}
}
static void check_utf8_nfdicf(struct unicode_map *um)
static void check_utf8_nfdicf(struct kunit *test)
{
int i;
struct utf8cursor u8c;
struct unicode_map *um = test->priv;
for (i = 0; i < ARRAY_SIZE(nfdicf_test_data); i++) {
int len = strlen(nfdicf_test_data[i].str);
int nlen = strlen(nfdicf_test_data[i].ncf);
int j = 0;
int ret;
unsigned char c;
test((utf8len(um, UTF8_NFDICF, nfdicf_test_data[i].str) ==
nlen));
test((utf8nlen(um, UTF8_NFDICF, nfdicf_test_data[i].str, len) ==
nlen));
KUNIT_EXPECT_EQ(test, utf8len(um, UTF8_NFDICF, nfdicf_test_data[i].str),
nlen);
KUNIT_EXPECT_EQ(test, utf8nlen(um, UTF8_NFDICF, nfdicf_test_data[i].str, len),
nlen);
if (utf8cursor(&u8c, um, UTF8_NFDICF,
nfdicf_test_data[i].str) < 0)
pr_err("can't create cursor\n");
ret = utf8cursor(&u8c, um, UTF8_NFDICF, nfdicf_test_data[i].str);
KUNIT_EXPECT_TRUE_MSG(test, ret >= 0, "Can't create cursor\n");
while ((c = utf8byte(&u8c)) > 0) {
test_f((c == nfdicf_test_data[i].ncf[j]),
"Unexpected byte 0x%x should be 0x%x\n",
c, nfdicf_test_data[i].ncf[j]);
KUNIT_EXPECT_EQ_MSG(test, c, nfdicf_test_data[i].ncf[j],
"Unexpected byte 0x%x should be 0x%x\n",
c, nfdicf_test_data[i].ncf[j]);
j++;
}
test((j == nlen));
KUNIT_EXPECT_EQ(test, j, nlen);
}
}
static void check_utf8_comparisons(struct unicode_map *table)
static void check_utf8_comparisons(struct kunit *test)
{
int i;
struct unicode_map *um = test->priv;
for (i = 0; i < ARRAY_SIZE(nfdi_test_data); i++) {
const struct qstr s1 = {.name = nfdi_test_data[i].str,
@ -237,8 +222,9 @@ static void check_utf8_comparisons(struct unicode_map *table)
const struct qstr s2 = {.name = nfdi_test_data[i].dec,
.len = sizeof(nfdi_test_data[i].dec)};
test_f(!utf8_strncmp(table, &s1, &s2),
"%s %s comparison mismatch\n", s1.name, s2.name);
/* strncmp returns 0 when strings are equal */
KUNIT_EXPECT_TRUE_MSG(test, utf8_strncmp(um, &s1, &s2) == 0,
"%s %s comparison mismatch\n", s1.name, s2.name);
}
for (i = 0; i < ARRAY_SIZE(nfdicf_test_data); i++) {
@ -247,62 +233,65 @@ static void check_utf8_comparisons(struct unicode_map *table)
const struct qstr s2 = {.name = nfdicf_test_data[i].ncf,
.len = sizeof(nfdicf_test_data[i].ncf)};
test_f(!utf8_strncasecmp(table, &s1, &s2),
"%s %s comparison mismatch\n", s1.name, s2.name);
/* strncasecmp returns 0 when strings are equal */
KUNIT_EXPECT_TRUE_MSG(test, utf8_strncasecmp(um, &s1, &s2) == 0,
"%s %s comparison mismatch\n", s1.name, s2.name);
}
}
static void check_supported_versions(struct unicode_map *um)
static void check_supported_versions(struct kunit *test)
{
struct unicode_map *um = test->priv;
/* Unicode 7.0.0 should be supported. */
test(utf8version_is_supported(um, UNICODE_AGE(7, 0, 0)));
KUNIT_EXPECT_TRUE(test, utf8version_is_supported(um, UNICODE_AGE(7, 0, 0)));
/* Unicode 9.0.0 should be supported. */
test(utf8version_is_supported(um, UNICODE_AGE(9, 0, 0)));
KUNIT_EXPECT_TRUE(test, utf8version_is_supported(um, UNICODE_AGE(9, 0, 0)));
/* Unicode 1x.0.0 (the latest version) should be supported. */
test(utf8version_is_supported(um, UTF8_LATEST));
KUNIT_EXPECT_TRUE(test, utf8version_is_supported(um, UTF8_LATEST));
/* Next versions don't exist. */
test(!utf8version_is_supported(um, UNICODE_AGE(13, 0, 0)));
test(!utf8version_is_supported(um, UNICODE_AGE(0, 0, 0)));
test(!utf8version_is_supported(um, UNICODE_AGE(-1, -1, -1)));
KUNIT_EXPECT_FALSE(test, utf8version_is_supported(um, UNICODE_AGE(13, 0, 0)));
KUNIT_EXPECT_FALSE(test, utf8version_is_supported(um, UNICODE_AGE(0, 0, 0)));
KUNIT_EXPECT_FALSE(test, utf8version_is_supported(um, UNICODE_AGE(-1, -1, -1)));
}
static int __init init_test_ucd(void)
static struct kunit_case unicode_normalization_test_cases[] = {
KUNIT_CASE(check_supported_versions),
KUNIT_CASE(check_utf8_comparisons),
KUNIT_CASE(check_utf8_nfdicf),
KUNIT_CASE(check_utf8_nfdi),
{}
};
static int init_test_ucd(struct kunit *test)
{
struct unicode_map *um;
struct unicode_map *um = utf8_load(UTF8_LATEST);
failed_tests = 0;
total_tests = 0;
test->priv = um;
um = utf8_load(UTF8_LATEST);
if (IS_ERR(um)) {
pr_err("%s: Unable to load utf8 table.\n", __func__);
return PTR_ERR(um);
}
KUNIT_EXPECT_EQ_MSG(test, IS_ERR(um), 0,
"%s: Unable to load utf8 table.\n", __func__);
check_supported_versions(um);
check_utf8_nfdi(um);
check_utf8_nfdicf(um);
check_utf8_comparisons(um);
if (!failed_tests)
pr_info("All %u tests passed\n", total_tests);
else
pr_err("%u out of %u tests failed\n", failed_tests,
total_tests);
utf8_unload(um);
return 0;
}
static void __exit exit_test_ucd(void)
static void exit_test_ucd(struct kunit *test)
{
utf8_unload(test->priv);
}
module_init(init_test_ucd);
module_exit(exit_test_ucd);
static struct kunit_suite unicode_normalization_test_suite = {
.name = "unicode_normalization",
.test_cases = unicode_normalization_test_cases,
.init = init_test_ucd,
.exit = exit_test_ucd,
};
kunit_test_suite(unicode_normalization_test_suite);
MODULE_AUTHOR("Gabriel Krisman Bertazi <krisman@collabora.co.uk>");
MODULE_DESCRIPTION("Kernel module for testing utf-8 support");
MODULE_DESCRIPTION("KUnit tests for utf-8 support.");
MODULE_LICENSE("GPL");

View File

@ -586,7 +586,7 @@ ccc_mismatch:
}
}
#ifdef CONFIG_UNICODE_NORMALIZATION_SELFTEST_MODULE
#if IS_MODULE(CONFIG_UNICODE_NORMALIZATION_KUNIT_TEST)
EXPORT_SYMBOL_GPL(utf8version_is_supported);
EXPORT_SYMBOL_GPL(utf8nlen);
EXPORT_SYMBOL_GPL(utf8ncursor);

View File

@ -2436,6 +2436,24 @@ config ASYNC_RAID6_TEST
config TEST_HEXDUMP
tristate "Test functions located in the hexdump module at runtime"
config PRINTF_KUNIT_TEST
tristate "KUnit test printf() family of functions at runtime" if !KUNIT_ALL_TESTS
depends on KUNIT
default KUNIT_ALL_TESTS
help
Enable this option to test the printf functions at runtime.
If unsure, say N.
config SCANF_KUNIT_TEST
tristate "KUnit test scanf() family of functions at runtime" if !KUNIT_ALL_TESTS
depends on KUNIT
default KUNIT_ALL_TESTS
help
Enable this option to test the scanf functions at runtime.
If unsure, say N.
config STRING_KUNIT_TEST
tristate "KUnit test string functions at runtime" if !KUNIT_ALL_TESTS
depends on KUNIT
@ -2449,12 +2467,6 @@ config STRING_HELPERS_KUNIT_TEST
config TEST_KSTRTOX
tristate "Test kstrto*() family of functions at runtime"
config TEST_PRINTF
tristate "Test printf() family of functions at runtime"
config TEST_SCANF
tristate "Test scanf() family of functions at runtime"
config TEST_BITMAP
tristate "Test bitmap_*() family of functions at runtime"
help
@ -2700,6 +2712,20 @@ config SYSCTL_KUNIT_TEST
If unsure, say N.
config KFIFO_KUNIT_TEST
tristate "KUnit Test for the generic kernel FIFO implementation" if !KUNIT_ALL_TESTS
depends on KUNIT
default KUNIT_ALL_TESTS
help
This builds the generic FIFO implementation KUnit test suite.
It tests that the API and basic functionality of the kfifo type
and associated macros.
For more information on KUnit and unit tests in general please refer
to the KUnit documentation in Documentation/dev-tools/kunit/.
If unsure, say N.
config LIST_KUNIT_TEST
tristate "KUnit Test for Kernel Linked-list structures" if !KUNIT_ALL_TESTS
depends on KUNIT
@ -3175,7 +3201,7 @@ config TEST_OBJPOOL
If unsure, say N.
config INT_POW_TEST
config INT_POW_KUNIT_TEST
tristate "Integer exponentiation (int_pow) test" if !KUNIT_ALL_TESTS
depends on KUNIT
default KUNIT_ALL_TESTS
@ -3206,6 +3232,44 @@ config INT_SQRT_KUNIT_TEST
If unsure, say N
config INT_LOG_KUNIT_TEST
tristate "Integer log (int_log) test" if !KUNIT_ALL_TESTS
depends on KUNIT
default KUNIT_ALL_TESTS
help
This option enables the KUnit test suite for the int_log library, which
provides two functions to compute the integer logarithm in base 2 and
base 10, called respectively as intlog2 and intlog10.
If unsure, say N
config GCD_KUNIT_TEST
tristate "Greatest common divisor test" if !KUNIT_ALL_TESTS
depends on KUNIT
default KUNIT_ALL_TESTS
help
This option enables the KUnit test suite for the gcd() function,
which computes the greatest common divisor of two numbers.
This test suite verifies the correctness of gcd() across various
scenarios, including edge cases.
If unsure, say N
config PRIME_NUMBERS_KUNIT_TEST
tristate "Prime number generator test" if !KUNIT_ALL_TESTS
depends on KUNIT
select PRIME_NUMBERS
default KUNIT_ALL_TESTS
help
This option enables the KUnit test suite for the {is,next}_prime_number
functions.
Enabling this option will include tests that compare the prime number
generator functions against a brute force implementation.
If unsure, say N
endif # RUNTIME_TESTING_MENU
config ARCH_USE_MEMTEST

View File

@ -52,9 +52,7 @@ obj-y += bcd.o sort.o parser.o debug_locks.o random32.o \
percpu-refcount.o rhashtable.o base64.o \
once.o refcount.o rcuref.o usercopy.o errseq.o bucket_locks.o \
generic-radix-tree.o bitmap-str.o
obj-$(CONFIG_STRING_KUNIT_TEST) += string_kunit.o
obj-y += string_helpers.o
obj-$(CONFIG_STRING_HELPERS_KUNIT_TEST) += string_helpers_kunit.o
obj-y += hexdump.o
obj-$(CONFIG_TEST_HEXDUMP) += test_hexdump.o
obj-y += kstrtox.o
@ -65,27 +63,20 @@ obj-$(CONFIG_TEST_DHRY) += test_dhry.o
obj-$(CONFIG_TEST_FIRMWARE) += test_firmware.o
obj-$(CONFIG_TEST_BITOPS) += test_bitops.o
CFLAGS_test_bitops.o += -Werror
obj-$(CONFIG_CPUMASK_KUNIT_TEST) += cpumask_kunit.o
obj-$(CONFIG_TEST_SYSCTL) += test_sysctl.o
obj-$(CONFIG_TEST_IOV_ITER) += kunit_iov_iter.o
obj-$(CONFIG_HASH_KUNIT_TEST) += test_hash.o
obj-$(CONFIG_TEST_IDA) += test_ida.o
obj-$(CONFIG_TEST_UBSAN) += test_ubsan.o
CFLAGS_test_ubsan.o += $(call cc-disable-warning, vla)
CFLAGS_test_ubsan.o += $(call cc-disable-warning, unused-but-set-variable)
UBSAN_SANITIZE_test_ubsan.o := y
obj-$(CONFIG_TEST_KSTRTOX) += test-kstrtox.o
obj-$(CONFIG_TEST_LIST_SORT) += test_list_sort.o
obj-$(CONFIG_TEST_MIN_HEAP) += test_min_heap.o
obj-$(CONFIG_TEST_LKM) += test_module.o
obj-$(CONFIG_TEST_VMALLOC) += test_vmalloc.o
obj-$(CONFIG_TEST_RHASHTABLE) += test_rhashtable.o
obj-$(CONFIG_TEST_SORT) += test_sort.o
obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_keys.o
obj-$(CONFIG_TEST_STATIC_KEYS) += test_static_key_base.o
obj-$(CONFIG_TEST_DYNAMIC_DEBUG) += test_dynamic_debug.o
obj-$(CONFIG_TEST_PRINTF) += test_printf.o
obj-$(CONFIG_TEST_SCANF) += test_scanf.o
obj-$(CONFIG_TEST_BITMAP) += test_bitmap.o
ifeq ($(CONFIG_CC_IS_CLANG)$(CONFIG_KASAN),yy)
@ -98,7 +89,6 @@ obj-$(CONFIG_TEST_XARRAY) += test_xarray.o
obj-$(CONFIG_TEST_MAPLE_TREE) += test_maple_tree.o
obj-$(CONFIG_TEST_PARMAN) += test_parman.o
obj-$(CONFIG_TEST_KMOD) += test_kmod.o
obj-$(CONFIG_TEST_RUNTIME) += tests/
obj-$(CONFIG_TEST_DEBUG_VIRTUAL) += test_debug_virtual.o
obj-$(CONFIG_TEST_MEMCAT_P) += test_memcat_p.o
obj-$(CONFIG_TEST_OBJAGG) += test_objagg.o
@ -107,10 +97,7 @@ obj-$(CONFIG_TEST_MEMINIT) += test_meminit.o
obj-$(CONFIG_TEST_LOCKUP) += test_lockup.o
obj-$(CONFIG_TEST_HMM) += test_hmm.o
obj-$(CONFIG_TEST_FREE_PAGES) += test_free_pages.o
obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o
obj-$(CONFIG_TEST_REF_TRACKER) += test_ref_tracker.o
CFLAGS_test_fprobe.o += $(CC_FLAGS_FTRACE)
obj-$(CONFIG_FPROBE_SANITY_TEST) += test_fprobe.o
obj-$(CONFIG_TEST_OBJPOOL) += test_objpool.o
obj-$(CONFIG_TEST_FPU) += test_fpu.o
@ -132,7 +119,7 @@ endif
obj-$(CONFIG_DEBUG_INFO_REDUCED) += debug_info.o
CFLAGS_debug_info.o += $(call cc-option, -femit-struct-debug-detailed=any)
obj-y += math/ crypto/
obj-y += math/ crypto/ tests/
obj-$(CONFIG_GENERIC_IOMAP) += iomap.o
obj-$(CONFIG_HAS_IOMEM) += iomap_copy.o devres.o
@ -368,32 +355,6 @@ obj-$(CONFIG_OBJAGG) += objagg.o
# pldmfw library
obj-$(CONFIG_PLDMFW) += pldmfw/
# KUnit tests
CFLAGS_bitfield_kunit.o := $(DISABLE_STRUCTLEAK_PLUGIN)
obj-$(CONFIG_BITFIELD_KUNIT) += bitfield_kunit.o
obj-$(CONFIG_CHECKSUM_KUNIT) += checksum_kunit.o
obj-$(CONFIG_UTIL_MACROS_KUNIT) += util_macros_kunit.o
obj-$(CONFIG_LIST_KUNIT_TEST) += list-test.o
obj-$(CONFIG_HASHTABLE_KUNIT_TEST) += hashtable_test.o
obj-$(CONFIG_LINEAR_RANGES_TEST) += test_linear_ranges.o
obj-$(CONFIG_BITS_TEST) += test_bits.o
obj-$(CONFIG_CMDLINE_KUNIT_TEST) += cmdline_kunit.o
obj-$(CONFIG_SLUB_KUNIT_TEST) += slub_kunit.o
obj-$(CONFIG_MEMCPY_KUNIT_TEST) += memcpy_kunit.o
obj-$(CONFIG_IS_SIGNED_TYPE_KUNIT_TEST) += is_signed_type_kunit.o
CFLAGS_overflow_kunit.o = $(call cc-disable-warning, tautological-constant-out-of-range-compare)
obj-$(CONFIG_OVERFLOW_KUNIT_TEST) += overflow_kunit.o
CFLAGS_stackinit_kunit.o += $(call cc-disable-warning, switch-unreachable)
obj-$(CONFIG_STACKINIT_KUNIT_TEST) += stackinit_kunit.o
CFLAGS_fortify_kunit.o += $(call cc-disable-warning, unsequenced)
CFLAGS_fortify_kunit.o += $(call cc-disable-warning, stringop-overread)
CFLAGS_fortify_kunit.o += $(call cc-disable-warning, stringop-truncation)
CFLAGS_fortify_kunit.o += $(DISABLE_STRUCTLEAK_PLUGIN)
obj-$(CONFIG_FORTIFY_KUNIT_TEST) += fortify_kunit.o
obj-$(CONFIG_CRC_KUNIT_TEST) += crc_kunit.o
obj-$(CONFIG_SIPHASH_KUNIT_TEST) += siphash_kunit.o
obj-$(CONFIG_USERCOPY_KUNIT_TEST) += usercopy_kunit.o
obj-$(CONFIG_GENERIC_LIB_DEVMEM_IS_ALLOWED) += devmem_is_allowed.o
obj-$(CONFIG_FIRMWARE_TABLE) += fw_table.o

View File

@ -5,8 +5,7 @@ obj-$(CONFIG_CORDIC) += cordic.o
obj-$(CONFIG_PRIME_NUMBERS) += prime_numbers.o
obj-$(CONFIG_RATIONAL) += rational.o
obj-$(CONFIG_INT_POW_TEST) += tests/int_pow_kunit.o
obj-$(CONFIG_TEST_DIV64) += test_div64.o
obj-$(CONFIG_TEST_MULDIV64) += test_mul_u64_u64_div_u64.o
obj-$(CONFIG_RATIONAL_KUNIT_TEST) += rational-test.o
obj-$(CONFIG_INT_SQRT_KUNIT_TEST) += tests/int_sqrt_kunit.o
obj-y += tests/

View File

@ -1,16 +1,11 @@
// SPDX-License-Identifier: GPL-2.0-only
#define pr_fmt(fmt) "prime numbers: " fmt
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/prime_numbers.h>
#include <linux/slab.h>
struct primes {
struct rcu_head rcu;
unsigned long last, sz;
unsigned long primes[];
};
#include "prime_numbers_private.h"
#if BITS_PER_LONG == 64
static const struct primes small_primes = {
@ -62,9 +57,25 @@ static const struct primes small_primes = {
static DEFINE_MUTEX(lock);
static const struct primes __rcu *primes = RCU_INITIALIZER(&small_primes);
static unsigned long selftest_max;
#if IS_ENABLED(CONFIG_PRIME_NUMBERS_KUNIT_TEST)
/*
* Calls the callback under RCU lock. The callback must not retain
* the primes pointer.
*/
void with_primes(void *ctx, primes_fn fn)
{
rcu_read_lock();
fn(ctx, rcu_dereference(primes));
rcu_read_unlock();
}
EXPORT_SYMBOL(with_primes);
static bool slow_is_prime_number(unsigned long x)
EXPORT_SYMBOL(slow_is_prime_number);
#else
static
#endif
bool slow_is_prime_number(unsigned long x)
{
unsigned long y = int_sqrt(x);
@ -239,77 +250,13 @@ bool is_prime_number(unsigned long x)
}
EXPORT_SYMBOL(is_prime_number);
static void dump_primes(void)
{
const struct primes *p;
char *buf;
buf = kmalloc(PAGE_SIZE, GFP_KERNEL);
rcu_read_lock();
p = rcu_dereference(primes);
if (buf)
bitmap_print_to_pagebuf(true, buf, p->primes, p->sz);
pr_info("primes.{last=%lu, .sz=%lu, .primes[]=...x%lx} = %s\n",
p->last, p->sz, p->primes[BITS_TO_LONGS(p->sz) - 1], buf);
rcu_read_unlock();
kfree(buf);
}
static int selftest(unsigned long max)
{
unsigned long x, last;
if (!max)
return 0;
for (last = 0, x = 2; x < max; x++) {
bool slow = slow_is_prime_number(x);
bool fast = is_prime_number(x);
if (slow != fast) {
pr_err("inconsistent result for is-prime(%lu): slow=%s, fast=%s!\n",
x, slow ? "yes" : "no", fast ? "yes" : "no");
goto err;
}
if (!slow)
continue;
if (next_prime_number(last) != x) {
pr_err("incorrect result for next-prime(%lu): expected %lu, got %lu\n",
last, x, next_prime_number(last));
goto err;
}
last = x;
}
pr_info("%s(%lu) passed, last prime was %lu\n", __func__, x, last);
return 0;
err:
dump_primes();
return -EINVAL;
}
static int __init primes_init(void)
{
return selftest(selftest_max);
}
static void __exit primes_exit(void)
{
free_primes();
}
module_init(primes_init);
module_exit(primes_exit);
module_param_named(selftest, selftest_max, ulong, 0400);
MODULE_AUTHOR("Intel Corporation");
MODULE_DESCRIPTION("Prime number library");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,16 @@
/* SPDX-License-Identifier: GPL-2.0 */
#include <linux/types.h>
struct primes {
struct rcu_head rcu;
unsigned long last, sz;
unsigned long primes[];
};
#if IS_ENABLED(CONFIG_PRIME_NUMBERS_KUNIT_TEST)
typedef void (*primes_fn)(void *, const struct primes *);
void with_primes(void *ctx, primes_fn fn);
bool slow_is_prime_number(unsigned long x);
#endif

View File

@ -1,4 +1,8 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_INT_POW_TEST) += int_pow_kunit.o
obj-$(CONFIG_INT_SQRT_KUNIT_TEST) += int_sqrt_kunit.o
obj-$(CONFIG_GCD_KUNIT_TEST) += gcd_kunit.o
obj-$(CONFIG_INT_LOG_KUNIT_TEST) += int_log_kunit.o
obj-$(CONFIG_INT_POW_KUNIT_TEST) += int_pow_kunit.o
obj-$(CONFIG_INT_SQRT_KUNIT_TEST) += int_sqrt_kunit.o
obj-$(CONFIG_PRIME_NUMBERS_KUNIT_TEST) += prime_numbers_kunit.o
obj-$(CONFIG_RATIONAL_KUNIT_TEST) += rational_kunit.o

View File

@ -0,0 +1,56 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <kunit/test.h>
#include <linux/gcd.h>
#include <linux/limits.h>
struct test_case_params {
unsigned long val1;
unsigned long val2;
unsigned long expected_result;
const char *name;
};
static const struct test_case_params params[] = {
{ 48, 18, 6, "GCD of 48 and 18" },
{ 18, 48, 6, "GCD of 18 and 48" },
{ 56, 98, 14, "GCD of 56 and 98" },
{ 17, 13, 1, "Coprime numbers" },
{ 101, 103, 1, "Coprime numbers" },
{ 270, 192, 6, "GCD of 270 and 192" },
{ 0, 5, 5, "GCD with zero" },
{ 7, 0, 7, "GCD with zero reversed" },
{ 36, 36, 36, "GCD of identical numbers" },
{ ULONG_MAX, 1, 1, "GCD of max ulong and 1" },
{ ULONG_MAX, ULONG_MAX, ULONG_MAX, "GCD of max ulong values" },
};
static void get_desc(const struct test_case_params *tc, char *desc)
{
strscpy(desc, tc->name, KUNIT_PARAM_DESC_SIZE);
}
KUNIT_ARRAY_PARAM(gcd, params, get_desc);
static void gcd_test(struct kunit *test)
{
const struct test_case_params *tc = (const struct test_case_params *)test->param_value;
KUNIT_EXPECT_EQ(test, tc->expected_result, gcd(tc->val1, tc->val2));
}
static struct kunit_case math_gcd_test_cases[] = {
KUNIT_CASE_PARAM(gcd_test, gcd_gen_params),
{}
};
static struct kunit_suite gcd_test_suite = {
.name = "math-gcd",
.test_cases = math_gcd_test_cases,
};
kunit_test_suite(gcd_test_suite);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("math.gcd KUnit test suite");
MODULE_AUTHOR("Yu-Chun Lin <eleanor15x@gmail.com>");

View File

@ -0,0 +1,74 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <kunit/test.h>
#include <linux/int_log.h>
struct test_case_params {
u32 value;
unsigned int expected_result;
const char *name;
};
/* The expected result takes into account the log error */
static const struct test_case_params intlog2_params[] = {
{0, 0, "Log base 2 of 0"},
{1, 0, "Log base 2 of 1"},
{2, 16777216, "Log base 2 of 2"},
{3, 26591232, "Log base 2 of 3"},
{4, 33554432, "Log base 2 of 4"},
{8, 50331648, "Log base 2 of 8"},
{16, 67108864, "Log base 2 of 16"},
{32, 83886080, "Log base 2 of 32"},
{U32_MAX, 536870911, "Log base 2 of MAX"},
};
static const struct test_case_params intlog10_params[] = {
{0, 0, "Log base 10 of 0"},
{1, 0, "Log base 10 of 1"},
{6, 13055203, "Log base 10 of 6"},
{10, 16777225, "Log base 10 of 10"},
{100, 33554450, "Log base 10 of 100"},
{1000, 50331675, "Log base 10 of 1000"},
{10000, 67108862, "Log base 10 of 10000"},
{U32_MAX, 161614247, "Log base 10 of MAX"}
};
static void get_desc(const struct test_case_params *tc, char *desc)
{
strscpy(desc, tc->name, KUNIT_PARAM_DESC_SIZE);
}
KUNIT_ARRAY_PARAM(intlog2, intlog2_params, get_desc);
static void intlog2_test(struct kunit *test)
{
const struct test_case_params *tc = (const struct test_case_params *)test->param_value;
KUNIT_EXPECT_EQ(test, tc->expected_result, intlog2(tc->value));
}
KUNIT_ARRAY_PARAM(intlog10, intlog10_params, get_desc);
static void intlog10_test(struct kunit *test)
{
const struct test_case_params *tc = (const struct test_case_params *)test->param_value;
KUNIT_EXPECT_EQ(test, tc->expected_result, intlog10(tc->value));
}
static struct kunit_case math_int_log_test_cases[] = {
KUNIT_CASE_PARAM(intlog2_test, intlog2_gen_params),
KUNIT_CASE_PARAM(intlog10_test, intlog10_gen_params),
{}
};
static struct kunit_suite int_log_test_suite = {
.name = "math-int_log",
.test_cases = math_int_log_test_cases,
};
kunit_test_suites(&int_log_test_suite);
MODULE_DESCRIPTION("math.int_log KUnit test suite");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,59 @@
// SPDX-License-Identifier: GPL-2.0-only
#include <kunit/test.h>
#include <linux/module.h>
#include <linux/prime_numbers.h>
#include "../prime_numbers_private.h"
static void dump_primes(void *ctx, const struct primes *p)
{
static char buf[PAGE_SIZE];
struct kunit_suite *suite = ctx;
bitmap_print_to_pagebuf(true, buf, p->primes, p->sz);
kunit_info(suite, "primes.{last=%lu, .sz=%lu, .primes[]=...x%lx} = %s",
p->last, p->sz, p->primes[BITS_TO_LONGS(p->sz) - 1], buf);
}
static void prime_numbers_test(struct kunit *test)
{
const unsigned long max = 65536;
unsigned long x, last, next;
for (last = 0, x = 2; x < max; x++) {
const bool slow = slow_is_prime_number(x);
const bool fast = is_prime_number(x);
KUNIT_ASSERT_EQ_MSG(test, slow, fast, "is-prime(%lu)", x);
if (!slow)
continue;
next = next_prime_number(last);
KUNIT_ASSERT_EQ_MSG(test, next, x, "next-prime(%lu)", last);
last = next;
}
}
static void kunit_suite_exit(struct kunit_suite *suite)
{
with_primes(suite, dump_primes);
}
static struct kunit_case prime_numbers_cases[] = {
KUNIT_CASE(prime_numbers_test),
{},
};
static struct kunit_suite prime_numbers_suite = {
.name = "math-prime_numbers",
.suite_exit = kunit_suite_exit,
.test_cases = prime_numbers_cases,
};
kunit_test_suite(prime_numbers_suite);
MODULE_AUTHOR("Intel Corporation");
MODULE_DESCRIPTION("Prime number library");
MODULE_LICENSE("GPL");

View File

@ -1 +1,44 @@
# SPDX-License-Identifier: GPL-2.0
#
# Makefile for tests of kernel library functions.
# KUnit tests
CFLAGS_bitfield_kunit.o := $(DISABLE_STRUCTLEAK_PLUGIN)
obj-$(CONFIG_BITFIELD_KUNIT) += bitfield_kunit.o
obj-$(CONFIG_BITS_TEST) += test_bits.o
obj-$(CONFIG_CHECKSUM_KUNIT) += checksum_kunit.o
obj-$(CONFIG_CMDLINE_KUNIT_TEST) += cmdline_kunit.o
obj-$(CONFIG_CPUMASK_KUNIT_TEST) += cpumask_kunit.o
obj-$(CONFIG_CRC_KUNIT_TEST) += crc_kunit.o
CFLAGS_fortify_kunit.o += $(call cc-disable-warning, unsequenced)
CFLAGS_fortify_kunit.o += $(call cc-disable-warning, stringop-overread)
CFLAGS_fortify_kunit.o += $(call cc-disable-warning, stringop-truncation)
CFLAGS_fortify_kunit.o += $(DISABLE_STRUCTLEAK_PLUGIN)
obj-$(CONFIG_FORTIFY_KUNIT_TEST) += fortify_kunit.o
CFLAGS_test_fprobe.o += $(CC_FLAGS_FTRACE)
obj-$(CONFIG_FPROBE_SANITY_TEST) += test_fprobe.o
obj-$(CONFIG_HASHTABLE_KUNIT_TEST) += hashtable_test.o
obj-$(CONFIG_HASH_KUNIT_TEST) += test_hash.o
obj-$(CONFIG_TEST_IOV_ITER) += kunit_iov_iter.o
obj-$(CONFIG_IS_SIGNED_TYPE_KUNIT_TEST) += is_signed_type_kunit.o
obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o
obj-$(CONFIG_LIST_KUNIT_TEST) += list-test.o
obj-$(CONFIG_KFIFO_KUNIT_TEST) += kfifo_kunit.o
obj-$(CONFIG_TEST_LIST_SORT) += test_list_sort.o
obj-$(CONFIG_LINEAR_RANGES_TEST) += test_linear_ranges.o
obj-$(CONFIG_MEMCPY_KUNIT_TEST) += memcpy_kunit.o
CFLAGS_overflow_kunit.o = $(call cc-disable-warning, tautological-constant-out-of-range-compare)
obj-$(CONFIG_OVERFLOW_KUNIT_TEST) += overflow_kunit.o
obj-$(CONFIG_PRINTF_KUNIT_TEST) += printf_kunit.o
obj-$(CONFIG_SCANF_KUNIT_TEST) += scanf_kunit.o
obj-$(CONFIG_SIPHASH_KUNIT_TEST) += siphash_kunit.o
obj-$(CONFIG_SLUB_KUNIT_TEST) += slub_kunit.o
obj-$(CONFIG_TEST_SORT) += test_sort.o
CFLAGS_stackinit_kunit.o += $(call cc-disable-warning, switch-unreachable)
obj-$(CONFIG_STACKINIT_KUNIT_TEST) += stackinit_kunit.o
obj-$(CONFIG_STRING_KUNIT_TEST) += string_kunit.o
obj-$(CONFIG_STRING_HELPERS_KUNIT_TEST) += string_helpers_kunit.o
obj-$(CONFIG_USERCOPY_KUNIT_TEST) += usercopy_kunit.o
obj-$(CONFIG_UTIL_MACROS_KUNIT) += util_macros_kunit.o
obj-$(CONFIG_TEST_RUNTIME_MODULE) += module/

View File

@ -60,6 +60,7 @@ static int fortify_write_overflows;
static const char array_of_10[] = "this is 10";
static const char *ptr_of_11 = "this is 11!";
static const char * const unchanging_12 = "this is 12!!";
static char array_unknown[] = "compiler thinks I might change";
void fortify_add_kunit_error(int write)
@ -83,12 +84,28 @@ void fortify_add_kunit_error(int write)
static void fortify_test_known_sizes(struct kunit *test)
{
char stack[80] = "Test!";
KUNIT_EXPECT_FALSE(test, __is_constexpr(__builtin_strlen(stack)));
KUNIT_EXPECT_EQ(test, __compiletime_strlen(stack), 5);
KUNIT_EXPECT_TRUE(test, __is_constexpr(__builtin_strlen("88888888")));
KUNIT_EXPECT_EQ(test, __compiletime_strlen("88888888"), 8);
KUNIT_EXPECT_TRUE(test, __is_constexpr(__builtin_strlen(array_of_10)));
KUNIT_EXPECT_EQ(test, __compiletime_strlen(array_of_10), 10);
KUNIT_EXPECT_FALSE(test, __is_constexpr(__builtin_strlen(ptr_of_11)));
KUNIT_EXPECT_EQ(test, __compiletime_strlen(ptr_of_11), 11);
KUNIT_EXPECT_TRUE(test, __is_constexpr(__builtin_strlen(unchanging_12)));
KUNIT_EXPECT_EQ(test, __compiletime_strlen(unchanging_12), 12);
KUNIT_EXPECT_FALSE(test, __is_constexpr(__builtin_strlen(array_unknown)));
KUNIT_EXPECT_EQ(test, __compiletime_strlen(array_unknown), SIZE_MAX);
/* Externally defined and dynamically sized string pointer: */
KUNIT_EXPECT_FALSE(test, __is_constexpr(__builtin_strlen(test->name)));
KUNIT_EXPECT_EQ(test, __compiletime_strlen(test->name), SIZE_MAX);
}
@ -394,8 +411,6 @@ struct fortify_padding {
char buf[32];
unsigned long bytes_after;
};
/* Force compiler into not being able to resolve size at compile-time. */
static volatile int unconst;
static void fortify_test_strlen(struct kunit *test)
{
@ -520,57 +535,56 @@ static void fortify_test_strncpy(struct kunit *test)
{
struct fortify_padding pad = { };
char src[] = "Copy me fully into a small buffer and I will overflow!";
size_t sizeof_buf = sizeof(pad.buf);
OPTIMIZER_HIDE_VAR(sizeof_buf);
/* Destination is %NUL-filled to start with. */
KUNIT_EXPECT_EQ(test, pad.bytes_before, 0);
KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0');
KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 2], '\0');
KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 3], '\0');
KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 1], '\0');
KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 2], '\0');
KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 3], '\0');
KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
/* Legitimate strncpy() 1 less than of max size. */
KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src,
sizeof(pad.buf) + unconst - 1)
KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, sizeof_buf - 1)
== pad.buf);
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0);
/* Only last byte should be %NUL */
KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 3], '\0');
KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 1], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 3], '\0');
/* Legitimate (though unterminated) max-size strncpy. */
KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src,
sizeof(pad.buf) + unconst)
KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, sizeof_buf)
== pad.buf);
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0);
/* No trailing %NUL -- thanks strncpy API. */
KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 1], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 1], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
/* But we will not have gone beyond. */
KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
/* Now verify that FORTIFY is working... */
KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src,
sizeof(pad.buf) + unconst + 1)
KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, sizeof_buf + 1)
== pad.buf);
/* Should catch the overflow. */
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 1);
KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 1], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 1], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
/* And we will not have gone beyond. */
KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
/* And further... */
KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src,
sizeof(pad.buf) + unconst + 2)
KUNIT_ASSERT_TRUE(test, strncpy(pad.buf, src, sizeof_buf + 2)
== pad.buf);
/* Should catch the overflow. */
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 2);
KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 1], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 1], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
/* And we will not have gone beyond. */
KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
}
@ -579,55 +593,56 @@ static void fortify_test_strscpy(struct kunit *test)
{
struct fortify_padding pad = { };
char src[] = "Copy me fully into a small buffer and I will overflow!";
size_t sizeof_buf = sizeof(pad.buf);
size_t sizeof_src = sizeof(src);
OPTIMIZER_HIDE_VAR(sizeof_buf);
OPTIMIZER_HIDE_VAR(sizeof_src);
/* Destination is %NUL-filled to start with. */
KUNIT_EXPECT_EQ(test, pad.bytes_before, 0);
KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0');
KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 2], '\0');
KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 3], '\0');
KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 1], '\0');
KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 2], '\0');
KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 3], '\0');
KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
/* Legitimate strscpy() 1 less than of max size. */
KUNIT_ASSERT_EQ(test, strscpy(pad.buf, src,
sizeof(pad.buf) + unconst - 1),
KUNIT_ASSERT_EQ(test, strscpy(pad.buf, src, sizeof_buf - 1),
-E2BIG);
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0);
/* Keeping space for %NUL, last two bytes should be %NUL */
KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0');
KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 2], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 3], '\0');
KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 1], '\0');
KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 2], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 3], '\0');
/* Legitimate max-size strscpy. */
KUNIT_ASSERT_EQ(test, strscpy(pad.buf, src,
sizeof(pad.buf) + unconst),
KUNIT_ASSERT_EQ(test, strscpy(pad.buf, src, sizeof_buf),
-E2BIG);
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0);
/* A trailing %NUL will exist. */
KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0');
KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 1], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
/* Now verify that FORTIFY is working... */
KUNIT_ASSERT_EQ(test, strscpy(pad.buf, src,
sizeof(pad.buf) + unconst + 1),
KUNIT_ASSERT_EQ(test, strscpy(pad.buf, src, sizeof_buf + 1),
-E2BIG);
/* Should catch the overflow. */
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 1);
KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0');
KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 1], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
/* And we will not have gone beyond. */
KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
/* And much further... */
KUNIT_ASSERT_EQ(test, strscpy(pad.buf, src,
sizeof(src) * 2 + unconst),
KUNIT_ASSERT_EQ(test, strscpy(pad.buf, src, sizeof_src * 2),
-E2BIG);
/* Should catch the overflow. */
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 2);
KUNIT_EXPECT_EQ(test, pad.buf[sizeof(pad.buf) - 1], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof(pad.buf) - 2], '\0');
KUNIT_EXPECT_EQ(test, pad.buf[sizeof_buf - 1], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
KUNIT_EXPECT_NE(test, pad.buf[sizeof_buf - 2], '\0');
/* And we will not have gone beyond. */
KUNIT_EXPECT_EQ(test, pad.bytes_after, 0);
}
@ -767,7 +782,9 @@ static void fortify_test_strlcat(struct kunit *test)
struct fortify_padding pad = { };
char src[sizeof(pad.buf)] = { };
int i, partial;
int len = sizeof(pad.buf) + unconst;
int len = sizeof(pad.buf);
OPTIMIZER_HIDE_VAR(len);
/* Fill 15 bytes with valid characters. */
partial = sizeof(src) / 2 - 1;
@ -857,28 +874,32 @@ struct fortify_zero_sized {
#define __fortify_test(memfunc) \
static void fortify_test_##memfunc(struct kunit *test) \
{ \
struct fortify_zero_sized zero = { }; \
struct fortify_zero_sized empty = { }; \
struct fortify_padding pad = { }; \
char srcA[sizeof(pad.buf) + 2]; \
char srcB[sizeof(pad.buf) + 2]; \
size_t len = sizeof(pad.buf) + unconst; \
size_t len = sizeof(pad.buf); \
size_t zero = 0; \
\
OPTIMIZER_HIDE_VAR(len); \
OPTIMIZER_HIDE_VAR(zero); \
\
memset(srcA, 'A', sizeof(srcA)); \
KUNIT_ASSERT_EQ(test, srcA[0], 'A'); \
memset(srcB, 'B', sizeof(srcB)); \
KUNIT_ASSERT_EQ(test, srcB[0], 'B'); \
\
memfunc(pad.buf, srcA, 0 + unconst); \
memfunc(pad.buf, srcA, zero); \
KUNIT_EXPECT_EQ(test, pad.buf[0], '\0'); \
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); \
memfunc(pad.buf + 1, srcB, 1 + unconst); \
memfunc(pad.buf + 1, srcB, zero + 1); \
KUNIT_EXPECT_EQ(test, pad.buf[0], '\0'); \
KUNIT_EXPECT_EQ(test, pad.buf[1], 'B'); \
KUNIT_EXPECT_EQ(test, pad.buf[2], '\0'); \
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); \
memfunc(pad.buf, srcA, 1 + unconst); \
memfunc(pad.buf, srcA, zero + 1); \
KUNIT_EXPECT_EQ(test, pad.buf[0], 'A'); \
KUNIT_EXPECT_EQ(test, pad.buf[1], 'B'); \
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \
@ -904,10 +925,10 @@ static void fortify_test_##memfunc(struct kunit *test) \
/* Reset error counter. */ \
fortify_write_overflows = 0; \
/* Copy nothing into nothing: no errors. */ \
memfunc(zero.buf, srcB, 0 + unconst); \
memfunc(empty.buf, srcB, zero); \
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 0); \
memfunc(zero.buf, srcB, 1 + unconst); \
memfunc(empty.buf, srcB, zero + 1); \
KUNIT_EXPECT_EQ(test, fortify_read_overflows, 0); \
KUNIT_EXPECT_EQ(test, fortify_write_overflows, 1); \
}
@ -919,7 +940,9 @@ static void fortify_test_memscan(struct kunit *test)
char haystack[] = "Where oh where is my memory range?";
char *mem = haystack + strlen("Where oh where is ");
char needle = 'm';
size_t len = sizeof(haystack) + unconst;
size_t len = sizeof(haystack);
OPTIMIZER_HIDE_VAR(len);
KUNIT_ASSERT_PTR_EQ(test, memscan(haystack, needle, len),
mem);
@ -938,7 +961,9 @@ static void fortify_test_memchr(struct kunit *test)
char haystack[] = "Where oh where is my memory range?";
char *mem = haystack + strlen("Where oh where is ");
char needle = 'm';
size_t len = sizeof(haystack) + unconst;
size_t len = sizeof(haystack);
OPTIMIZER_HIDE_VAR(len);
KUNIT_ASSERT_PTR_EQ(test, memchr(haystack, needle, len),
mem);
@ -957,7 +982,9 @@ static void fortify_test_memchr_inv(struct kunit *test)
char haystack[] = "Where oh where is my memory range?";
char *mem = haystack + 1;
char needle = 'W';
size_t len = sizeof(haystack) + unconst;
size_t len = sizeof(haystack);
OPTIMIZER_HIDE_VAR(len);
/* Normal search is okay. */
KUNIT_ASSERT_PTR_EQ(test, memchr_inv(haystack, needle, len),
@ -976,8 +1003,11 @@ static void fortify_test_memcmp(struct kunit *test)
{
char one[] = "My mind is going ...";
char two[] = "My mind is going ... I can feel it.";
size_t one_len = sizeof(one) + unconst - 1;
size_t two_len = sizeof(two) + unconst - 1;
size_t one_len = sizeof(one) - 1;
size_t two_len = sizeof(two) - 1;
OPTIMIZER_HIDE_VAR(one_len);
OPTIMIZER_HIDE_VAR(two_len);
/* We match the first string (ignoring the %NUL). */
KUNIT_ASSERT_EQ(test, memcmp(one, two, one_len), 0);
@ -998,7 +1028,9 @@ static void fortify_test_kmemdup(struct kunit *test)
{
char src[] = "I got Doom running on it!";
char *copy;
size_t len = sizeof(src) + unconst;
size_t len = sizeof(src);
OPTIMIZER_HIDE_VAR(len);
/* Copy is within bounds. */
copy = kmemdup(src, len, GFP_KERNEL);

224
lib/tests/kfifo_kunit.c Normal file
View File

@ -0,0 +1,224 @@
// SPDX-License-Identifier: GPL-2.0
/*
* KUnit test for the generic kernel FIFO implementation.
*
* Copyright (C) 2024 Diego Vieira <diego.daniel.professional@gmail.com>
*/
#include <kunit/test.h>
#include <linux/kfifo.h>
#define KFIFO_SIZE 32
#define N_ELEMENTS 5
static void kfifo_test_reset_should_clear_the_fifo(struct kunit *test)
{
DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE);
kfifo_put(&my_fifo, 1);
kfifo_put(&my_fifo, 2);
kfifo_put(&my_fifo, 3);
KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 3);
kfifo_reset(&my_fifo);
KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 0);
KUNIT_EXPECT_TRUE(test, kfifo_is_empty(&my_fifo));
}
static void kfifo_test_define_should_define_an_empty_fifo(struct kunit *test)
{
DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE);
KUNIT_EXPECT_TRUE(test, kfifo_initialized(&my_fifo));
KUNIT_EXPECT_TRUE(test, kfifo_is_empty(&my_fifo));
KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 0);
}
static void kfifo_test_len_should_ret_n_of_stored_elements(struct kunit *test)
{
u8 buffer1[N_ELEMENTS];
for (int i = 0; i < N_ELEMENTS; i++)
buffer1[i] = i + 1;
DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE);
KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 0);
kfifo_in(&my_fifo, buffer1, N_ELEMENTS);
KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), N_ELEMENTS);
kfifo_in(&my_fifo, buffer1, N_ELEMENTS);
KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), N_ELEMENTS * 2);
kfifo_reset(&my_fifo);
KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 0);
}
static void kfifo_test_put_should_insert_and_get_should_pop(struct kunit *test)
{
u8 out_data = 0;
int processed_elements;
u8 elements[] = { 3, 5, 11 };
DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE);
// If the fifo is empty, get returns 0
processed_elements = kfifo_get(&my_fifo, &out_data);
KUNIT_EXPECT_EQ(test, processed_elements, 0);
KUNIT_EXPECT_EQ(test, out_data, 0);
for (int i = 0; i < 3; i++)
kfifo_put(&my_fifo, elements[i]);
for (int i = 0; i < 3; i++) {
processed_elements = kfifo_get(&my_fifo, &out_data);
KUNIT_EXPECT_EQ(test, processed_elements, 1);
KUNIT_EXPECT_EQ(test, out_data, elements[i]);
}
}
static void kfifo_test_in_should_insert_multiple_elements(struct kunit *test)
{
u8 in_buffer[] = { 11, 25, 65 };
u8 out_data;
int processed_elements;
DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE);
kfifo_in(&my_fifo, in_buffer, 3);
for (int i = 0; i < 3; i++) {
processed_elements = kfifo_get(&my_fifo, &out_data);
KUNIT_EXPECT_EQ(test, processed_elements, 1);
KUNIT_EXPECT_EQ(test, out_data, in_buffer[i]);
}
}
static void kfifo_test_out_should_pop_multiple_elements(struct kunit *test)
{
u8 in_buffer[] = { 11, 25, 65 };
u8 out_buffer[3];
int copied_elements;
DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE);
for (int i = 0; i < 3; i++)
kfifo_put(&my_fifo, in_buffer[i]);
copied_elements = kfifo_out(&my_fifo, out_buffer, 3);
KUNIT_EXPECT_EQ(test, copied_elements, 3);
for (int i = 0; i < 3; i++)
KUNIT_EXPECT_EQ(test, out_buffer[i], in_buffer[i]);
KUNIT_EXPECT_TRUE(test, kfifo_is_empty(&my_fifo));
}
static void kfifo_test_dec_init_should_define_an_empty_fifo(struct kunit *test)
{
DECLARE_KFIFO(my_fifo, u8, KFIFO_SIZE);
INIT_KFIFO(my_fifo);
// my_fifo is a struct with an inplace buffer
KUNIT_EXPECT_FALSE(test, __is_kfifo_ptr(&my_fifo));
KUNIT_EXPECT_TRUE(test, kfifo_initialized(&my_fifo));
}
static void kfifo_test_define_should_equal_declare_init(struct kunit *test)
{
// declare a variable my_fifo of type struct kfifo of u8
DECLARE_KFIFO(my_fifo1, u8, KFIFO_SIZE);
// initialize the my_fifo variable
INIT_KFIFO(my_fifo1);
// DEFINE_KFIFO declares the variable with the initial value
// essentially the same as calling DECLARE_KFIFO and INIT_KFIFO
DEFINE_KFIFO(my_fifo2, u8, KFIFO_SIZE);
// my_fifo1 and my_fifo2 have the same size
KUNIT_EXPECT_EQ(test, sizeof(my_fifo1), sizeof(my_fifo2));
KUNIT_EXPECT_EQ(test, kfifo_initialized(&my_fifo1),
kfifo_initialized(&my_fifo2));
KUNIT_EXPECT_EQ(test, kfifo_is_empty(&my_fifo1),
kfifo_is_empty(&my_fifo2));
}
static void kfifo_test_alloc_should_initiliaze_a_ptr_fifo(struct kunit *test)
{
int ret;
DECLARE_KFIFO_PTR(my_fifo, u8);
INIT_KFIFO(my_fifo);
// kfifo_initialized returns false signaling the buffer pointer is NULL
KUNIT_EXPECT_FALSE(test, kfifo_initialized(&my_fifo));
// kfifo_alloc allocates the buffer
ret = kfifo_alloc(&my_fifo, KFIFO_SIZE, GFP_KERNEL);
KUNIT_EXPECT_EQ_MSG(test, ret, 0, "Memory allocation should succeed");
KUNIT_EXPECT_TRUE(test, kfifo_initialized(&my_fifo));
// kfifo_free frees the buffer
kfifo_free(&my_fifo);
}
static void kfifo_test_peek_should_not_remove_elements(struct kunit *test)
{
u8 out_data;
int processed_elements;
DEFINE_KFIFO(my_fifo, u8, KFIFO_SIZE);
// If the fifo is empty, peek returns 0
processed_elements = kfifo_peek(&my_fifo, &out_data);
KUNIT_EXPECT_EQ(test, processed_elements, 0);
kfifo_put(&my_fifo, 3);
kfifo_put(&my_fifo, 5);
kfifo_put(&my_fifo, 11);
KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 3);
processed_elements = kfifo_peek(&my_fifo, &out_data);
KUNIT_EXPECT_EQ(test, processed_elements, 1);
KUNIT_EXPECT_EQ(test, out_data, 3);
KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 3);
// Using peek doesn't remove the element
// so the read element and the fifo length
// remains the same
processed_elements = kfifo_peek(&my_fifo, &out_data);
KUNIT_EXPECT_EQ(test, processed_elements, 1);
KUNIT_EXPECT_EQ(test, out_data, 3);
KUNIT_EXPECT_EQ(test, kfifo_len(&my_fifo), 3);
}
static struct kunit_case kfifo_test_cases[] = {
KUNIT_CASE(kfifo_test_reset_should_clear_the_fifo),
KUNIT_CASE(kfifo_test_define_should_define_an_empty_fifo),
KUNIT_CASE(kfifo_test_len_should_ret_n_of_stored_elements),
KUNIT_CASE(kfifo_test_put_should_insert_and_get_should_pop),
KUNIT_CASE(kfifo_test_in_should_insert_multiple_elements),
KUNIT_CASE(kfifo_test_out_should_pop_multiple_elements),
KUNIT_CASE(kfifo_test_dec_init_should_define_an_empty_fifo),
KUNIT_CASE(kfifo_test_define_should_equal_declare_init),
KUNIT_CASE(kfifo_test_alloc_should_initiliaze_a_ptr_fifo),
KUNIT_CASE(kfifo_test_peek_should_not_remove_elements),
{},
};
static struct kunit_suite kfifo_test_module = {
.name = "kfifo",
.test_cases = kfifo_test_cases,
};
kunit_test_suites(&kfifo_test_module);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Diego Vieira <diego.daniel.professional@gmail.com>");
MODULE_DESCRIPTION("KUnit test for the kernel FIFO");

View File

@ -1185,22 +1185,40 @@ struct bar {
static void DEFINE_FLEX_test(struct kunit *test)
{
/* Using _RAW_ on a __counted_by struct will initialize "counter" to zero */
DEFINE_RAW_FLEX(struct foo, two_but_zero, array, 2);
#ifdef CONFIG_CC_HAS_COUNTED_BY
int expected_raw_size = sizeof(struct foo);
#else
int expected_raw_size = sizeof(struct foo) + 2 * sizeof(s16);
#endif
/* Without annotation, it will always be on-stack size. */
DEFINE_RAW_FLEX(struct bar, two, array, 2);
DEFINE_FLEX(struct foo, eight, array, counter, 8);
DEFINE_FLEX(struct foo, empty, array, counter, 0);
/* Using _RAW_ on a __counted_by struct will initialize "counter" to zero */
DEFINE_RAW_FLEX(struct foo, two_but_zero, array, 2);
int array_size_override = 0;
KUNIT_EXPECT_EQ(test, __struct_size(two_but_zero), expected_raw_size);
KUNIT_EXPECT_EQ(test, sizeof(*two), sizeof(struct bar));
KUNIT_EXPECT_EQ(test, __struct_size(two), sizeof(struct bar) + 2 * sizeof(s16));
KUNIT_EXPECT_EQ(test, __struct_size(eight), 24);
KUNIT_EXPECT_EQ(test, __member_size(two), sizeof(struct bar) + 2 * sizeof(s16));
KUNIT_EXPECT_EQ(test, __struct_size(two->array), 2 * sizeof(s16));
KUNIT_EXPECT_EQ(test, __member_size(two->array), 2 * sizeof(s16));
KUNIT_EXPECT_EQ(test, sizeof(*eight), sizeof(struct foo));
KUNIT_EXPECT_EQ(test, __struct_size(eight), sizeof(struct foo) + 8 * sizeof(s16));
KUNIT_EXPECT_EQ(test, __member_size(eight), sizeof(struct foo) + 8 * sizeof(s16));
KUNIT_EXPECT_EQ(test, __struct_size(eight->array), 8 * sizeof(s16));
KUNIT_EXPECT_EQ(test, __member_size(eight->array), 8 * sizeof(s16));
KUNIT_EXPECT_EQ(test, sizeof(*empty), sizeof(struct foo));
KUNIT_EXPECT_EQ(test, __struct_size(empty), sizeof(struct foo));
KUNIT_EXPECT_EQ(test, __member_size(empty), sizeof(struct foo));
KUNIT_EXPECT_EQ(test, __struct_size(empty->array), 0);
KUNIT_EXPECT_EQ(test, __member_size(empty->array), 0);
/* If __counted_by is not being used, array size will have the on-stack size. */
if (!IS_ENABLED(CONFIG_CC_HAS_COUNTED_BY))
array_size_override = 2 * sizeof(s16);
KUNIT_EXPECT_EQ(test, sizeof(*two_but_zero), sizeof(struct foo));
KUNIT_EXPECT_EQ(test, __struct_size(two_but_zero), sizeof(struct foo) + 2 * sizeof(s16));
KUNIT_EXPECT_EQ(test, __member_size(two_but_zero), sizeof(struct foo) + 2 * sizeof(s16));
KUNIT_EXPECT_EQ(test, __struct_size(two_but_zero->array), array_size_override);
KUNIT_EXPECT_EQ(test, __member_size(two_but_zero->array), array_size_override);
}
static struct kunit_case overflow_test_cases[] = {

View File

@ -3,9 +3,7 @@
* Test cases for printf facility.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/init.h>
#include <kunit/test.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/printk.h>
@ -25,8 +23,6 @@
#include <linux/property.h>
#include "../tools/testing/selftests/kselftest_module.h"
#define BUF_SIZE 256
#define PAD_SIZE 16
#define FILL_CHAR '$'
@ -37,14 +33,14 @@
block \
__diag_pop();
KSTM_MODULE_GLOBALS();
static unsigned int total_tests;
static char *test_buffer __initdata;
static char *alloced_buffer __initdata;
static char *test_buffer;
static char *alloced_buffer;
static int __printf(4, 0) __init
do_test(int bufsize, const char *expect, int elen,
const char *fmt, va_list ap)
static void __printf(7, 0)
do_test(struct kunit *kunittest, const char *file, const int line, int bufsize, const char *expect,
int elen, const char *fmt, va_list ap)
{
va_list aq;
int ret, written;
@ -57,62 +53,70 @@ do_test(int bufsize, const char *expect, int elen,
va_end(aq);
if (ret != elen) {
pr_warn("vsnprintf(buf, %d, \"%s\", ...) returned %d, expected %d\n",
bufsize, fmt, ret, elen);
return 1;
KUNIT_FAIL(kunittest,
"%s:%d: vsnprintf(buf, %d, \"%s\", ...) returned %d, expected %d\n",
file, line, bufsize, fmt, ret, elen);
return;
}
if (memchr_inv(alloced_buffer, FILL_CHAR, PAD_SIZE)) {
pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote before buffer\n", bufsize, fmt);
return 1;
KUNIT_FAIL(kunittest,
"%s:%d: vsnprintf(buf, %d, \"%s\", ...) wrote before buffer\n",
file, line, bufsize, fmt);
return;
}
if (!bufsize) {
if (memchr_inv(test_buffer, FILL_CHAR, BUF_SIZE + PAD_SIZE)) {
pr_warn("vsnprintf(buf, 0, \"%s\", ...) wrote to buffer\n",
fmt);
return 1;
KUNIT_FAIL(kunittest,
"%s:%d: vsnprintf(buf, 0, \"%s\", ...) wrote to buffer\n",
file, line, fmt);
}
return 0;
return;
}
written = min(bufsize-1, elen);
if (test_buffer[written]) {
pr_warn("vsnprintf(buf, %d, \"%s\", ...) did not nul-terminate buffer\n",
bufsize, fmt);
return 1;
KUNIT_FAIL(kunittest,
"%s:%d: vsnprintf(buf, %d, \"%s\", ...) did not nul-terminate buffer\n",
file, line, bufsize, fmt);
return;
}
if (memchr_inv(test_buffer + written + 1, FILL_CHAR, bufsize - (written + 1))) {
pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote beyond the nul-terminator\n",
bufsize, fmt);
return 1;
KUNIT_FAIL(kunittest,
"%s:%d: vsnprintf(buf, %d, \"%s\", ...) wrote beyond the nul-terminator\n",
file, line, bufsize, fmt);
return;
}
if (memchr_inv(test_buffer + bufsize, FILL_CHAR, BUF_SIZE + PAD_SIZE - bufsize)) {
pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote beyond buffer\n", bufsize, fmt);
return 1;
KUNIT_FAIL(kunittest,
"%s:%d: vsnprintf(buf, %d, \"%s\", ...) wrote beyond buffer\n",
file, line, bufsize, fmt);
return;
}
if (memcmp(test_buffer, expect, written)) {
pr_warn("vsnprintf(buf, %d, \"%s\", ...) wrote '%s', expected '%.*s'\n",
bufsize, fmt, test_buffer, written, expect);
return 1;
KUNIT_FAIL(kunittest,
"%s:%d: vsnprintf(buf, %d, \"%s\", ...) wrote '%s', expected '%.*s'\n",
file, line, bufsize, fmt, test_buffer, written, expect);
return;
}
return 0;
}
static void __printf(3, 4) __init
__test(const char *expect, int elen, const char *fmt, ...)
static void __printf(6, 7)
__test(struct kunit *kunittest, const char *file, const int line, const char *expect, int elen,
const char *fmt, ...)
{
va_list ap;
int rand;
char *p;
if (elen >= BUF_SIZE) {
pr_err("error in test suite: expected output length %d too long. Format was '%s'.\n",
elen, fmt);
failed_tests++;
KUNIT_FAIL(kunittest,
"%s:%d: error in test suite: expected length (%d) >= BUF_SIZE (%d). fmt=\"%s\"\n",
file, line, elen, BUF_SIZE, fmt);
return;
}
@ -124,19 +128,19 @@ __test(const char *expect, int elen, const char *fmt, ...)
* enough and 0), and then we also test that kvasprintf would
* be able to print it as expected.
*/
failed_tests += do_test(BUF_SIZE, expect, elen, fmt, ap);
do_test(kunittest, file, line, BUF_SIZE, expect, elen, fmt, ap);
rand = get_random_u32_inclusive(1, elen + 1);
/* Since elen < BUF_SIZE, we have 1 <= rand <= BUF_SIZE. */
failed_tests += do_test(rand, expect, elen, fmt, ap);
failed_tests += do_test(0, expect, elen, fmt, ap);
do_test(kunittest, file, line, rand, expect, elen, fmt, ap);
do_test(kunittest, file, line, 0, expect, elen, fmt, ap);
p = kvasprintf(GFP_KERNEL, fmt, ap);
if (p) {
total_tests++;
if (memcmp(p, expect, elen+1)) {
pr_warn("kvasprintf(..., \"%s\", ...) returned '%s', expected '%s'\n",
fmt, p, expect);
failed_tests++;
KUNIT_FAIL(kunittest,
"%s:%d: kvasprintf(..., \"%s\", ...) returned '%s', expected '%s'\n",
file, line, fmt, p, expect);
}
kfree(p);
}
@ -144,10 +148,10 @@ __test(const char *expect, int elen, const char *fmt, ...)
}
#define test(expect, fmt, ...) \
__test(expect, strlen(expect), fmt, ##__VA_ARGS__)
__test(kunittest, __FILE__, __LINE__, expect, strlen(expect), fmt, ##__VA_ARGS__)
static void __init
test_basic(void)
static void
test_basic(struct kunit *kunittest)
{
/* Work around annoying "warning: zero-length gnu_printf format string". */
char nul = '\0';
@ -155,11 +159,11 @@ test_basic(void)
test("", &nul);
test("100%", "100%%");
test("xxx%yyy", "xxx%cyyy", '%');
__test("xxx\0yyy", 7, "xxx%cyyy", '\0');
__test(kunittest, __FILE__, __LINE__, "xxx\0yyy", 7, "xxx%cyyy", '\0');
}
static void __init
test_number(void)
static void
test_number(struct kunit *kunittest)
{
test("0x1234abcd ", "%#-12x", 0x1234abcd);
test(" 0x1234abcd", "%#12x", 0x1234abcd);
@ -180,8 +184,8 @@ test_number(void)
test("00|0|0|0|0", "%.2d|%.1d|%.0d|%.*d|%1.0d", 0, 0, 0, 0, 0, 0);
}
static void __init
test_string(void)
static void
test_string(struct kunit *kunittest)
{
test("", "%s%.0s", "", "123");
test("ABCD|abc|123", "%s|%.3s|%.*s", "ABCD", "abcdef", 3, "123456");
@ -218,29 +222,6 @@ test_string(void)
#define ZEROS "00000000" /* hex 32 zero bits */
#define ONES "ffffffff" /* hex 32 one bits */
static int __init
plain_format(void)
{
char buf[PLAIN_BUF_SIZE];
int nchars;
nchars = snprintf(buf, PLAIN_BUF_SIZE, "%p", PTR);
if (nchars != PTR_WIDTH)
return -1;
if (strncmp(buf, PTR_VAL_NO_CRNG, PTR_WIDTH) == 0) {
pr_warn("crng possibly not yet initialized. plain 'p' buffer contains \"%s\"",
PTR_VAL_NO_CRNG);
return 0;
}
if (strncmp(buf, ZEROS, strlen(ZEROS)) != 0)
return -1;
return 0;
}
#else
#define PTR_WIDTH 8
@ -250,92 +231,47 @@ plain_format(void)
#define ZEROS ""
#define ONES ""
static int __init
plain_format(void)
{
/* Format is implicitly tested for 32 bit machines by plain_hash() */
return 0;
}
#endif /* BITS_PER_LONG == 64 */
static int __init
plain_hash_to_buffer(const void *p, char *buf, size_t len)
static void
plain_hash_to_buffer(struct kunit *kunittest, const void *p, char *buf, size_t len)
{
int nchars;
nchars = snprintf(buf, len, "%p", p);
if (nchars != PTR_WIDTH)
return -1;
KUNIT_ASSERT_EQ(kunittest, snprintf(buf, len, "%p", p), PTR_WIDTH);
if (strncmp(buf, PTR_VAL_NO_CRNG, PTR_WIDTH) == 0) {
pr_warn("crng possibly not yet initialized. plain 'p' buffer contains \"%s\"",
PTR_VAL_NO_CRNG);
return 0;
kunit_skip(kunittest,
"crng possibly not yet initialized. plain 'p' buffer contains \"%s\"\n",
PTR_VAL_NO_CRNG);
}
return 0;
}
static int __init
plain_hash(void)
static void
hash_pointer(struct kunit *kunittest)
{
if (no_hash_pointers)
kunit_skip(kunittest, "hash pointers disabled");
char buf[PLAIN_BUF_SIZE];
int ret;
ret = plain_hash_to_buffer(PTR, buf, PLAIN_BUF_SIZE);
if (ret)
return ret;
if (strncmp(buf, PTR_STR, PTR_WIDTH) == 0)
return -1;
return 0;
}
/*
* We can't use test() to test %p because we don't know what output to expect
* after an address is hashed.
*/
static void __init
plain(void)
{
int err;
if (no_hash_pointers) {
pr_warn("skipping plain 'p' tests");
skipped_tests += 2;
return;
}
err = plain_hash();
if (err) {
pr_warn("plain 'p' does not appear to be hashed\n");
failed_tests++;
return;
}
err = plain_format();
if (err) {
pr_warn("hashing plain 'p' has unexpected format\n");
failed_tests++;
}
}
static void __init
test_hashed(const char *fmt, const void *p)
{
char buf[PLAIN_BUF_SIZE];
int ret;
plain_hash_to_buffer(kunittest, PTR, buf, PLAIN_BUF_SIZE);
/*
* No need to increase failed test counter since this is assumed
* to be called after plain().
* The hash of %p is unpredictable, therefore test() cannot be used.
*
* Instead verify that the first 32 bits are zeros on a 64-bit system
* and that the non-hashed value is not printed.
*/
ret = plain_hash_to_buffer(p, buf, PLAIN_BUF_SIZE);
if (ret)
return;
KUNIT_EXPECT_MEMEQ(kunittest, buf, ZEROS, strlen(ZEROS));
KUNIT_EXPECT_MEMNEQ(kunittest, buf, PTR_STR, PTR_WIDTH);
}
static void
test_hashed(struct kunit *kunittest, const char *fmt, const void *p)
{
char buf[PLAIN_BUF_SIZE];
plain_hash_to_buffer(kunittest, p, buf, PLAIN_BUF_SIZE);
test(buf, fmt, p);
}
@ -343,8 +279,8 @@ test_hashed(const char *fmt, const void *p)
/*
* NULL pointers aren't hashed.
*/
static void __init
null_pointer(void)
static void
null_pointer(struct kunit *kunittest)
{
test(ZEROS "00000000", "%p", NULL);
test(ZEROS "00000000", "%px", NULL);
@ -354,8 +290,8 @@ null_pointer(void)
/*
* Error pointers aren't hashed.
*/
static void __init
error_pointer(void)
static void
error_pointer(struct kunit *kunittest)
{
test(ONES "fffffff5", "%p", ERR_PTR(-11));
test(ONES "fffffff5", "%px", ERR_PTR(-11));
@ -364,27 +300,27 @@ error_pointer(void)
#define PTR_INVALID ((void *)0x000000ab)
static void __init
invalid_pointer(void)
static void
invalid_pointer(struct kunit *kunittest)
{
test_hashed("%p", PTR_INVALID);
test_hashed(kunittest, "%p", PTR_INVALID);
test(ZEROS "000000ab", "%px", PTR_INVALID);
test("(efault)", "%pE", PTR_INVALID);
}
static void __init
symbol_ptr(void)
static void
symbol_ptr(struct kunit *kunittest)
{
}
static void __init
kernel_ptr(void)
static void
kernel_ptr(struct kunit *kunittest)
{
/* We can't test this without access to kptr_restrict. */
}
static void __init
struct_resource(void)
static void
struct_resource(struct kunit *kunittest)
{
struct resource test_resource = {
.start = 0xc0ffee00,
@ -432,8 +368,8 @@ struct_resource(void)
"%pR", &test_resource);
}
static void __init
struct_range(void)
static void
struct_range(struct kunit *kunittest)
{
struct range test_range = DEFINE_RANGE(0xc0ffee00ba5eba11,
0xc0ffee00ba5eba11);
@ -448,18 +384,18 @@ struct_range(void)
"%pra", &test_range);
}
static void __init
addr(void)
static void
addr(struct kunit *kunittest)
{
}
static void __init
escaped_str(void)
static void
escaped_str(struct kunit *kunittest)
{
}
static void __init
hex_string(void)
static void
hex_string(struct kunit *kunittest)
{
const char buf[3] = {0xc0, 0xff, 0xee};
@ -469,8 +405,8 @@ hex_string(void)
"%*ph|%*phC|%*phD|%*phN", 3, buf, 3, buf, 3, buf, 3, buf);
}
static void __init
mac(void)
static void
mac(struct kunit *kunittest)
{
const u8 addr[6] = {0x2d, 0x48, 0xd6, 0xfc, 0x7a, 0x05};
@ -481,8 +417,8 @@ mac(void)
test("057afcd6482d", "%pmR", addr);
}
static void __init
ip4(void)
static void
ip4(struct kunit *kunittest)
{
struct sockaddr_in sa;
@ -496,20 +432,13 @@ ip4(void)
test("001.002.003.004:12345|1.2.3.4:12345", "%piSp|%pISp", &sa, &sa);
}
static void __init
ip6(void)
static void
ip6(struct kunit *kunittest)
{
}
static void __init
ip(void)
{
ip4();
ip6();
}
static void __init
uuid(void)
static void
uuid(struct kunit *kunittest)
{
const char uuid[16] = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
@ -520,7 +449,7 @@ uuid(void)
test("03020100-0504-0706-0809-0A0B0C0D0E0F", "%pUL", uuid);
}
static struct dentry test_dentry[4] __initdata = {
static struct dentry test_dentry[4] = {
{ .d_parent = &test_dentry[0],
.d_name = QSTR_INIT(test_dentry[0].d_iname, 3),
.d_iname = "foo" },
@ -535,8 +464,8 @@ static struct dentry test_dentry[4] __initdata = {
.d_iname = "romeo" },
};
static void __init
dentry(void)
static void
dentry(struct kunit *kunittest)
{
test("foo", "%pd", &test_dentry[0]);
test("foo", "%pd2", &test_dentry[0]);
@ -556,13 +485,13 @@ dentry(void)
test(" bravo/alfa| bravo/alfa", "%12pd2|%*pd2", &test_dentry[2], 12, &test_dentry[2]);
}
static void __init
struct_va_format(void)
static void
struct_va_format(struct kunit *kunittest)
{
}
static void __init
time_and_date(void)
static void
time_and_date(struct kunit *kunittest)
{
/* 1543210543 */
const struct rtc_time tm = {
@ -595,13 +524,13 @@ time_and_date(void)
test("15:32:23|0119-00-04", "%ptTtrs|%ptTdrs", &t, &t);
}
static void __init
struct_clk(void)
static void
struct_clk(struct kunit *kunittest)
{
}
static void __init
large_bitmap(void)
static void
large_bitmap(struct kunit *kunittest)
{
const int nbits = 1 << 16;
unsigned long *bits = bitmap_zalloc(nbits, GFP_KERNEL);
@ -614,8 +543,8 @@ large_bitmap(void)
bitmap_free(bits);
}
static void __init
bitmap(void)
static void
bitmap(struct kunit *kunittest)
{
DECLARE_BITMAP(bits, 20);
const int primes[] = {2,3,5,7,11,13,17,19};
@ -634,11 +563,11 @@ bitmap(void)
test("fffff|fffff", "%20pb|%*pb", bits, 20, bits);
test("0-19|0-19", "%20pbl|%*pbl", bits, 20, bits);
large_bitmap();
large_bitmap(kunittest);
}
static void __init
netdev_features(void)
static void
netdev_features(struct kunit *kunittest)
{
}
@ -663,9 +592,9 @@ static const struct page_flags_test pft[] = {
"%#x", "kasantag"},
};
static void __init
page_flags_test(int section, int node, int zone, int last_cpupid,
int kasan_tag, unsigned long flags, const char *name,
static void
page_flags_test(struct kunit *kunittest, int section, int node, int zone,
int last_cpupid, int kasan_tag, unsigned long flags, const char *name,
char *cmp_buf)
{
unsigned long values[] = {section, node, zone, last_cpupid, kasan_tag};
@ -701,26 +630,25 @@ page_flags_test(int section, int node, int zone, int last_cpupid,
test(cmp_buf, "%pGp", &flags);
}
static void __init
flags(void)
static void
flags(struct kunit *kunittest)
{
unsigned long flags;
char *cmp_buffer;
gfp_t gfp;
cmp_buffer = kmalloc(BUF_SIZE, GFP_KERNEL);
if (!cmp_buffer)
return;
cmp_buffer = kunit_kmalloc(kunittest, BUF_SIZE, GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(kunittest, cmp_buffer);
flags = 0;
page_flags_test(0, 0, 0, 0, 0, flags, "", cmp_buffer);
page_flags_test(kunittest, 0, 0, 0, 0, 0, flags, "", cmp_buffer);
flags = 1UL << NR_PAGEFLAGS;
page_flags_test(0, 0, 0, 0, 0, flags, "", cmp_buffer);
page_flags_test(kunittest, 0, 0, 0, 0, 0, flags, "", cmp_buffer);
flags |= 1UL << PG_uptodate | 1UL << PG_dirty | 1UL << PG_lru
| 1UL << PG_active | 1UL << PG_swapbacked;
page_flags_test(1, 1, 1, 0x1fffff, 1, flags,
page_flags_test(kunittest, 1, 1, 1, 0x1fffff, 1, flags,
"uptodate|dirty|lru|active|swapbacked",
cmp_buffer);
@ -745,11 +673,9 @@ flags(void)
(unsigned long) gfp);
gfp |= __GFP_HIGH;
test(cmp_buffer, "%pGg", &gfp);
kfree(cmp_buffer);
}
static void __init fwnode_pointer(void)
static void fwnode_pointer(struct kunit *kunittest)
{
const struct software_node first = { .name = "first" };
const struct software_node second = { .name = "second", .parent = &first };
@ -763,8 +689,7 @@ static void __init fwnode_pointer(void)
rval = software_node_register_node_group(group);
if (rval) {
pr_warn("cannot register softnodes; rval %d\n", rval);
return;
kunit_skip(kunittest, "cannot register softnodes; rval %d\n", rval);
}
test(full_name_second, "%pfw", software_node_fwnode(&second));
@ -776,7 +701,7 @@ static void __init fwnode_pointer(void)
software_node_unregister_node_group(group);
}
static void __init fourcc_pointer(void)
static void fourcc_pointer(struct kunit *kunittest)
{
struct {
u32 code;
@ -793,14 +718,14 @@ static void __init fourcc_pointer(void)
test(try[i].str, "%p4cc", &try[i].code);
}
static void __init
errptr(void)
static void
errptr(struct kunit *kunittest)
{
test("-1234", "%pe", ERR_PTR(-1234));
/* Check that %pe with a non-ERR_PTR gets treated as ordinary %p. */
BUILD_BUG_ON(IS_ERR(PTR));
test_hashed("%pe", PTR);
test_hashed(kunittest, "%pe", PTR);
#ifdef CONFIG_SYMBOLIC_ERRNAME
test("(-ENOTSOCK)", "(%pe)", ERR_PTR(-ENOTSOCK));
@ -813,51 +738,66 @@ errptr(void)
#endif
}
static void __init
test_pointer(void)
static int printf_suite_init(struct kunit_suite *suite)
{
plain();
null_pointer();
error_pointer();
invalid_pointer();
symbol_ptr();
kernel_ptr();
struct_resource();
struct_range();
addr();
escaped_str();
hex_string();
mac();
ip();
uuid();
dentry();
struct_va_format();
time_and_date();
struct_clk();
bitmap();
netdev_features();
flags();
errptr();
fwnode_pointer();
fourcc_pointer();
}
total_tests = 0;
static void __init selftest(void)
{
alloced_buffer = kmalloc(BUF_SIZE + 2*PAD_SIZE, GFP_KERNEL);
if (!alloced_buffer)
return;
return -ENOMEM;
test_buffer = alloced_buffer + PAD_SIZE;
test_basic();
test_number();
test_string();
test_pointer();
kfree(alloced_buffer);
return 0;
}
KSTM_MODULE_LOADERS(test_printf);
static void printf_suite_exit(struct kunit_suite *suite)
{
kfree(alloced_buffer);
kunit_info(suite, "ran %u tests\n", total_tests);
}
static struct kunit_case printf_test_cases[] = {
KUNIT_CASE(test_basic),
KUNIT_CASE(test_number),
KUNIT_CASE(test_string),
KUNIT_CASE(hash_pointer),
KUNIT_CASE(null_pointer),
KUNIT_CASE(error_pointer),
KUNIT_CASE(invalid_pointer),
KUNIT_CASE(symbol_ptr),
KUNIT_CASE(kernel_ptr),
KUNIT_CASE(struct_resource),
KUNIT_CASE(struct_range),
KUNIT_CASE(addr),
KUNIT_CASE(escaped_str),
KUNIT_CASE(hex_string),
KUNIT_CASE(mac),
KUNIT_CASE(ip4),
KUNIT_CASE(ip6),
KUNIT_CASE(uuid),
KUNIT_CASE(dentry),
KUNIT_CASE(struct_va_format),
KUNIT_CASE(time_and_date),
KUNIT_CASE(struct_clk),
KUNIT_CASE(bitmap),
KUNIT_CASE(netdev_features),
KUNIT_CASE(flags),
KUNIT_CASE(errptr),
KUNIT_CASE(fwnode_pointer),
KUNIT_CASE(fourcc_pointer),
{}
};
static struct kunit_suite printf_test_suite = {
.name = "printf",
.suite_init = printf_suite_init,
.suite_exit = printf_suite_exit,
.test_cases = printf_test_cases,
};
kunit_test_suite(printf_test_suite);
MODULE_AUTHOR("Rasmus Villemoes <linux@rasmusvillemoes.dk>");
MODULE_DESCRIPTION("Test cases for printf facility");
MODULE_LICENSE("GPL");

View File

@ -3,152 +3,138 @@
* Test cases for sscanf facility.
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <kunit/test.h>
#include <linux/bitops.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/overflow.h>
#include <linux/printk.h>
#include <linux/prandom.h>
#include <linux/slab.h>
#include <linux/string.h>
#include "../tools/testing/selftests/kselftest_module.h"
#define BUF_SIZE 1024
KSTM_MODULE_GLOBALS();
static char *test_buffer __initdata;
static char *fmt_buffer __initdata;
static struct rnd_state rnd_state __initdata;
static char *test_buffer;
static char *fmt_buffer;
static struct rnd_state rnd_state;
typedef int (*check_fn)(const void *check_data, const char *string,
const char *fmt, int n_args, va_list ap);
typedef void (*check_fn)(struct kunit *test, const char *file, const int line,
const void *check_data, const char *string, const char *fmt, int n_args,
va_list ap);
static void __scanf(4, 6) __init
_test(check_fn fn, const void *check_data, const char *string, const char *fmt,
int n_args, ...)
static void __scanf(7, 9)
_test(struct kunit *test, const char *file, const int line, check_fn fn, const void *check_data,
const char *string, const char *fmt, int n_args, ...)
{
va_list ap, ap_copy;
int ret;
total_tests++;
va_start(ap, n_args);
va_copy(ap_copy, ap);
ret = vsscanf(string, fmt, ap_copy);
va_end(ap_copy);
if (ret != n_args) {
pr_warn("vsscanf(\"%s\", \"%s\", ...) returned %d expected %d\n",
string, fmt, ret, n_args);
goto fail;
KUNIT_FAIL(test, "%s:%d: vsscanf(\"%s\", \"%s\", ...) returned %d expected %d",
file, line, string, fmt, ret, n_args);
} else {
(*fn)(test, file, line, check_data, string, fmt, n_args, ap);
}
ret = (*fn)(check_data, string, fmt, n_args, ap);
if (ret)
goto fail;
va_end(ap);
return;
fail:
failed_tests++;
va_end(ap);
}
#define _check_numbers_template(arg_fmt, expect, str, fmt, n_args, ap) \
do { \
pr_debug("\"%s\", \"%s\" ->\n", str, fmt); \
for (; n_args > 0; n_args--, expect++) { \
typeof(*expect) got = *va_arg(ap, typeof(expect)); \
pr_debug("\t" arg_fmt "\n", got); \
if (got != *expect) { \
pr_warn("vsscanf(\"%s\", \"%s\", ...) expected " arg_fmt " got " arg_fmt "\n", \
str, fmt, *expect, got); \
return 1; \
KUNIT_FAIL(test, \
"%s:%d: vsscanf(\"%s\", \"%s\", ...) expected " arg_fmt " got " arg_fmt, \
file, line, str, fmt, *expect, got); \
return; \
} \
} \
return 0; \
} while (0)
static int __init check_ull(const void *check_data, const char *string,
const char *fmt, int n_args, va_list ap)
static void check_ull(struct kunit *test, const char *file, const int line, const void *check_data,
const char *string, const char *fmt, int n_args, va_list ap)
{
const unsigned long long *pval = check_data;
_check_numbers_template("%llu", pval, string, fmt, n_args, ap);
}
static int __init check_ll(const void *check_data, const char *string,
const char *fmt, int n_args, va_list ap)
static void check_ll(struct kunit *test, const char *file, const int line, const void *check_data,
const char *string, const char *fmt, int n_args, va_list ap)
{
const long long *pval = check_data;
_check_numbers_template("%lld", pval, string, fmt, n_args, ap);
}
static int __init check_ulong(const void *check_data, const char *string,
const char *fmt, int n_args, va_list ap)
static void check_ulong(struct kunit *test, const char *file, const int line,
const void *check_data, const char *string, const char *fmt, int n_args,
va_list ap)
{
const unsigned long *pval = check_data;
_check_numbers_template("%lu", pval, string, fmt, n_args, ap);
}
static int __init check_long(const void *check_data, const char *string,
const char *fmt, int n_args, va_list ap)
static void check_long(struct kunit *test, const char *file, const int line, const void *check_data,
const char *string, const char *fmt, int n_args, va_list ap)
{
const long *pval = check_data;
_check_numbers_template("%ld", pval, string, fmt, n_args, ap);
}
static int __init check_uint(const void *check_data, const char *string,
const char *fmt, int n_args, va_list ap)
static void check_uint(struct kunit *test, const char *file, const int line, const void *check_data,
const char *string, const char *fmt, int n_args, va_list ap)
{
const unsigned int *pval = check_data;
_check_numbers_template("%u", pval, string, fmt, n_args, ap);
}
static int __init check_int(const void *check_data, const char *string,
const char *fmt, int n_args, va_list ap)
static void check_int(struct kunit *test, const char *file, const int line, const void *check_data,
const char *string, const char *fmt, int n_args, va_list ap)
{
const int *pval = check_data;
_check_numbers_template("%d", pval, string, fmt, n_args, ap);
}
static int __init check_ushort(const void *check_data, const char *string,
const char *fmt, int n_args, va_list ap)
static void check_ushort(struct kunit *test, const char *file, const int line,
const void *check_data, const char *string, const char *fmt, int n_args,
va_list ap)
{
const unsigned short *pval = check_data;
_check_numbers_template("%hu", pval, string, fmt, n_args, ap);
}
static int __init check_short(const void *check_data, const char *string,
const char *fmt, int n_args, va_list ap)
static void check_short(struct kunit *test, const char *file, const int line,
const void *check_data, const char *string, const char *fmt, int n_args,
va_list ap)
{
const short *pval = check_data;
_check_numbers_template("%hd", pval, string, fmt, n_args, ap);
}
static int __init check_uchar(const void *check_data, const char *string,
const char *fmt, int n_args, va_list ap)
static void check_uchar(struct kunit *test, const char *file, const int line,
const void *check_data, const char *string, const char *fmt, int n_args,
va_list ap)
{
const unsigned char *pval = check_data;
_check_numbers_template("%hhu", pval, string, fmt, n_args, ap);
}
static int __init check_char(const void *check_data, const char *string,
const char *fmt, int n_args, va_list ap)
static void check_char(struct kunit *test, const char *file, const int line, const void *check_data,
const char *string, const char *fmt, int n_args, va_list ap)
{
const signed char *pval = check_data;
@ -156,7 +142,7 @@ static int __init check_char(const void *check_data, const char *string,
}
/* Selection of interesting numbers to test, copied from test-kstrtox.c */
static const unsigned long long numbers[] __initconst = {
static const unsigned long long numbers[] = {
0x0ULL,
0x1ULL,
0x7fULL,
@ -196,7 +182,7 @@ do { \
T result = ~expect_val; /* should be overwritten */ \
\
snprintf(test_buffer, BUF_SIZE, gen_fmt, expect_val); \
_test(fn, &expect_val, test_buffer, "%" scan_fmt, 1, &result); \
_test(test, __FILE__, __LINE__, fn, &expect_val, test_buffer, "%" scan_fmt, 1, &result);\
} while (0)
#define simple_numbers_loop(T, gen_fmt, scan_fmt, fn) \
@ -214,7 +200,7 @@ do { \
} \
} while (0)
static void __init numbers_simple(void)
static void numbers_simple(struct kunit *test)
{
simple_numbers_loop(unsigned long long, "%llu", "llu", check_ull);
simple_numbers_loop(long long, "%lld", "lld", check_ll);
@ -267,14 +253,14 @@ static void __init numbers_simple(void)
* the raw prandom*() functions (Not mathematically rigorous!!).
* Variabilty of length and value is more important than perfect randomness.
*/
static u32 __init next_test_random(u32 max_bits)
static u32 next_test_random(u32 max_bits)
{
u32 n_bits = hweight32(prandom_u32_state(&rnd_state)) % (max_bits + 1);
return prandom_u32_state(&rnd_state) & GENMASK(n_bits, 0);
}
static unsigned long long __init next_test_random_ull(void)
static unsigned long long next_test_random_ull(void)
{
u32 rand1 = prandom_u32_state(&rnd_state);
u32 n_bits = (hweight32(rand1) * 3) % 64;
@ -311,7 +297,7 @@ do { \
* updating buf_pos and returning the number of characters appended.
* On error buf_pos is not changed and return value is 0.
*/
static int __init __printf(4, 5)
static int __printf(4, 5)
append_fmt(char *buf, int *buf_pos, int buf_len, const char *val_fmt, ...)
{
va_list ap;
@ -333,7 +319,7 @@ append_fmt(char *buf, int *buf_pos, int buf_len, const char *val_fmt, ...)
* Convenience function to append the field delimiter string
* to both the value string and format string buffers.
*/
static void __init append_delim(char *str_buf, int *str_buf_pos, int str_buf_len,
static void append_delim(char *str_buf, int *str_buf_pos, int str_buf_len,
char *fmt_buf, int *fmt_buf_pos, int fmt_buf_len,
const char *delim_str)
{
@ -344,7 +330,7 @@ static void __init append_delim(char *str_buf, int *str_buf_pos, int str_buf_len
#define test_array_8(fn, check_data, string, fmt, arr) \
do { \
BUILD_BUG_ON(ARRAY_SIZE(arr) != 8); \
_test(fn, check_data, string, fmt, 8, \
_test(test, __FILE__, __LINE__, fn, check_data, string, fmt, 8, \
&(arr)[0], &(arr)[1], &(arr)[2], &(arr)[3], \
&(arr)[4], &(arr)[5], &(arr)[6], &(arr)[7]); \
} while (0)
@ -398,7 +384,7 @@ do { \
test_array_8(fn, expect, test_buffer, fmt_buffer, result); \
} while (0)
static void __init numbers_list_ll(const char *delim)
static void numbers_list_ll(struct kunit *test, const char *delim)
{
numbers_list_8(unsigned long long, "%llu", delim, "llu", check_ull);
numbers_list_8(long long, "%lld", delim, "lld", check_ll);
@ -408,7 +394,7 @@ static void __init numbers_list_ll(const char *delim)
numbers_list_8(long long, "0x%llx", delim, "lli", check_ll);
}
static void __init numbers_list_l(const char *delim)
static void numbers_list_l(struct kunit *test, const char *delim)
{
numbers_list_8(unsigned long, "%lu", delim, "lu", check_ulong);
numbers_list_8(long, "%ld", delim, "ld", check_long);
@ -418,7 +404,7 @@ static void __init numbers_list_l(const char *delim)
numbers_list_8(long, "0x%lx", delim, "li", check_long);
}
static void __init numbers_list_d(const char *delim)
static void numbers_list_d(struct kunit *test, const char *delim)
{
numbers_list_8(unsigned int, "%u", delim, "u", check_uint);
numbers_list_8(int, "%d", delim, "d", check_int);
@ -428,7 +414,7 @@ static void __init numbers_list_d(const char *delim)
numbers_list_8(int, "0x%x", delim, "i", check_int);
}
static void __init numbers_list_h(const char *delim)
static void numbers_list_h(struct kunit *test, const char *delim)
{
numbers_list_8(unsigned short, "%hu", delim, "hu", check_ushort);
numbers_list_8(short, "%hd", delim, "hd", check_short);
@ -438,7 +424,7 @@ static void __init numbers_list_h(const char *delim)
numbers_list_8(short, "0x%hx", delim, "hi", check_short);
}
static void __init numbers_list_hh(const char *delim)
static void numbers_list_hh(struct kunit *test, const char *delim)
{
numbers_list_8(unsigned char, "%hhu", delim, "hhu", check_uchar);
numbers_list_8(signed char, "%hhd", delim, "hhd", check_char);
@ -448,16 +434,19 @@ static void __init numbers_list_hh(const char *delim)
numbers_list_8(signed char, "0x%hhx", delim, "hhi", check_char);
}
static void __init numbers_list(const char *delim)
static void numbers_list(struct kunit *test)
{
numbers_list_ll(delim);
numbers_list_l(delim);
numbers_list_d(delim);
numbers_list_h(delim);
numbers_list_hh(delim);
const char * const *param = test->param_value;
const char *delim = *param;
numbers_list_ll(test, delim);
numbers_list_l(test, delim);
numbers_list_d(test, delim);
numbers_list_h(test, delim);
numbers_list_hh(test, delim);
}
static void __init numbers_list_field_width_ll(const char *delim)
static void numbers_list_field_width_ll(struct kunit *test, const char *delim)
{
numbers_list_fix_width(unsigned long long, "%llu", delim, 20, "llu", check_ull);
numbers_list_fix_width(long long, "%lld", delim, 20, "lld", check_ll);
@ -467,7 +456,7 @@ static void __init numbers_list_field_width_ll(const char *delim)
numbers_list_fix_width(long long, "0x%llx", delim, 18, "lli", check_ll);
}
static void __init numbers_list_field_width_l(const char *delim)
static void numbers_list_field_width_l(struct kunit *test, const char *delim)
{
#if BITS_PER_LONG == 64
numbers_list_fix_width(unsigned long, "%lu", delim, 20, "lu", check_ulong);
@ -486,7 +475,7 @@ static void __init numbers_list_field_width_l(const char *delim)
#endif
}
static void __init numbers_list_field_width_d(const char *delim)
static void numbers_list_field_width_d(struct kunit *test, const char *delim)
{
numbers_list_fix_width(unsigned int, "%u", delim, 10, "u", check_uint);
numbers_list_fix_width(int, "%d", delim, 11, "d", check_int);
@ -496,7 +485,7 @@ static void __init numbers_list_field_width_d(const char *delim)
numbers_list_fix_width(int, "0x%x", delim, 10, "i", check_int);
}
static void __init numbers_list_field_width_h(const char *delim)
static void numbers_list_field_width_h(struct kunit *test, const char *delim)
{
numbers_list_fix_width(unsigned short, "%hu", delim, 5, "hu", check_ushort);
numbers_list_fix_width(short, "%hd", delim, 6, "hd", check_short);
@ -506,7 +495,7 @@ static void __init numbers_list_field_width_h(const char *delim)
numbers_list_fix_width(short, "0x%hx", delim, 6, "hi", check_short);
}
static void __init numbers_list_field_width_hh(const char *delim)
static void numbers_list_field_width_hh(struct kunit *test, const char *delim)
{
numbers_list_fix_width(unsigned char, "%hhu", delim, 3, "hhu", check_uchar);
numbers_list_fix_width(signed char, "%hhd", delim, 4, "hhd", check_char);
@ -520,16 +509,19 @@ static void __init numbers_list_field_width_hh(const char *delim)
* List of numbers separated by delim. Each field width specifier is the
* maximum possible digits for the given type and base.
*/
static void __init numbers_list_field_width_typemax(const char *delim)
static void numbers_list_field_width_typemax(struct kunit *test)
{
numbers_list_field_width_ll(delim);
numbers_list_field_width_l(delim);
numbers_list_field_width_d(delim);
numbers_list_field_width_h(delim);
numbers_list_field_width_hh(delim);
const char * const *param = test->param_value;
const char *delim = *param;
numbers_list_field_width_ll(test, delim);
numbers_list_field_width_l(test, delim);
numbers_list_field_width_d(test, delim);
numbers_list_field_width_h(test, delim);
numbers_list_field_width_hh(test, delim);
}
static void __init numbers_list_field_width_val_ll(const char *delim)
static void numbers_list_field_width_val_ll(struct kunit *test, const char *delim)
{
numbers_list_val_width(unsigned long long, "%llu", delim, "llu", check_ull);
numbers_list_val_width(long long, "%lld", delim, "lld", check_ll);
@ -539,7 +531,7 @@ static void __init numbers_list_field_width_val_ll(const char *delim)
numbers_list_val_width(long long, "0x%llx", delim, "lli", check_ll);
}
static void __init numbers_list_field_width_val_l(const char *delim)
static void numbers_list_field_width_val_l(struct kunit *test, const char *delim)
{
numbers_list_val_width(unsigned long, "%lu", delim, "lu", check_ulong);
numbers_list_val_width(long, "%ld", delim, "ld", check_long);
@ -549,7 +541,7 @@ static void __init numbers_list_field_width_val_l(const char *delim)
numbers_list_val_width(long, "0x%lx", delim, "li", check_long);
}
static void __init numbers_list_field_width_val_d(const char *delim)
static void numbers_list_field_width_val_d(struct kunit *test, const char *delim)
{
numbers_list_val_width(unsigned int, "%u", delim, "u", check_uint);
numbers_list_val_width(int, "%d", delim, "d", check_int);
@ -559,7 +551,7 @@ static void __init numbers_list_field_width_val_d(const char *delim)
numbers_list_val_width(int, "0x%x", delim, "i", check_int);
}
static void __init numbers_list_field_width_val_h(const char *delim)
static void numbers_list_field_width_val_h(struct kunit *test, const char *delim)
{
numbers_list_val_width(unsigned short, "%hu", delim, "hu", check_ushort);
numbers_list_val_width(short, "%hd", delim, "hd", check_short);
@ -569,7 +561,7 @@ static void __init numbers_list_field_width_val_h(const char *delim)
numbers_list_val_width(short, "0x%hx", delim, "hi", check_short);
}
static void __init numbers_list_field_width_val_hh(const char *delim)
static void numbers_list_field_width_val_hh(struct kunit *test, const char *delim)
{
numbers_list_val_width(unsigned char, "%hhu", delim, "hhu", check_uchar);
numbers_list_val_width(signed char, "%hhd", delim, "hhd", check_char);
@ -583,13 +575,16 @@ static void __init numbers_list_field_width_val_hh(const char *delim)
* List of numbers separated by delim. Each field width specifier is the
* exact length of the corresponding value digits in the string being scanned.
*/
static void __init numbers_list_field_width_val_width(const char *delim)
static void numbers_list_field_width_val_width(struct kunit *test)
{
numbers_list_field_width_val_ll(delim);
numbers_list_field_width_val_l(delim);
numbers_list_field_width_val_d(delim);
numbers_list_field_width_val_h(delim);
numbers_list_field_width_val_hh(delim);
const char * const *param = test->param_value;
const char *delim = *param;
numbers_list_field_width_val_ll(test, delim);
numbers_list_field_width_val_l(test, delim);
numbers_list_field_width_val_d(test, delim);
numbers_list_field_width_val_h(test, delim);
numbers_list_field_width_val_hh(test, delim);
}
/*
@ -598,9 +593,14 @@ static void __init numbers_list_field_width_val_width(const char *delim)
* of digits. For example the hex values c0,3,bf01,303 would have a
* string representation of "c03bf01303" and extracted with "%2x%1x%4x%3x".
*/
static void __init numbers_slice(void)
static void numbers_slice(struct kunit *test)
{
numbers_list_field_width_val_width("");
const char *delim = "";
KUNIT_ASSERT_PTR_EQ(test, test->param_value, NULL);
test->param_value = &delim;
numbers_list_field_width_val_width(test);
}
#define test_number_prefix(T, str, scan_fmt, expect0, expect1, n_args, fn) \
@ -608,14 +608,14 @@ do { \
const T expect[2] = { expect0, expect1 }; \
T result[2] = { (T)~expect[0], (T)~expect[1] }; \
\
_test(fn, &expect, str, scan_fmt, n_args, &result[0], &result[1]); \
_test(test, __FILE__, __LINE__, fn, &expect, str, scan_fmt, n_args, &result[0], &result[1]);\
} while (0)
/*
* Number prefix is >= field width.
* Expected behaviour is derived from testing userland sscanf.
*/
static void __init numbers_prefix_overflow(void)
static void numbers_prefix_overflow(struct kunit *test)
{
/*
* Negative decimal with a field of width 1, should quit scanning
@ -684,25 +684,17 @@ do { \
T got; \
char *endp; \
int len; \
bool fail = false; \
\
total_tests++; \
len = snprintf(test_buffer, BUF_SIZE, gen_fmt, expect); \
got = (fn)(test_buffer, &endp, base); \
pr_debug(#fn "(\"%s\", %d) -> " gen_fmt "\n", test_buffer, base, got); \
if (got != (expect)) { \
fail = true; \
pr_warn(#fn "(\"%s\", %d): got " gen_fmt " expected " gen_fmt "\n", \
test_buffer, base, got, expect); \
KUNIT_FAIL(test, #fn "(\"%s\", %d): got " gen_fmt " expected " gen_fmt, \
test_buffer, base, got, expect); \
} else if (endp != test_buffer + len) { \
fail = true; \
pr_warn(#fn "(\"%s\", %d) startp=0x%px got endp=0x%px expected 0x%px\n", \
test_buffer, base, test_buffer, \
test_buffer + len, endp); \
KUNIT_FAIL(test, #fn "(\"%s\", %d) startp=0x%px got endp=0x%px expected 0x%px", \
test_buffer, base, test_buffer, \
test_buffer + len, endp); \
} \
\
if (fail) \
failed_tests++; \
} while (0)
#define test_simple_strtoxx(T, fn, gen_fmt, base) \
@ -718,7 +710,7 @@ do { \
} \
} while (0)
static void __init test_simple_strtoull(void)
static void test_simple_strtoull(struct kunit *test)
{
test_simple_strtoxx(unsigned long long, simple_strtoull, "%llu", 10);
test_simple_strtoxx(unsigned long long, simple_strtoull, "%llu", 0);
@ -727,7 +719,7 @@ static void __init test_simple_strtoull(void)
test_simple_strtoxx(unsigned long long, simple_strtoull, "0x%llx", 0);
}
static void __init test_simple_strtoll(void)
static void test_simple_strtoll(struct kunit *test)
{
test_simple_strtoxx(long long, simple_strtoll, "%lld", 10);
test_simple_strtoxx(long long, simple_strtoll, "%lld", 0);
@ -736,7 +728,7 @@ static void __init test_simple_strtoll(void)
test_simple_strtoxx(long long, simple_strtoll, "0x%llx", 0);
}
static void __init test_simple_strtoul(void)
static void test_simple_strtoul(struct kunit *test)
{
test_simple_strtoxx(unsigned long, simple_strtoul, "%lu", 10);
test_simple_strtoxx(unsigned long, simple_strtoul, "%lu", 0);
@ -745,7 +737,7 @@ static void __init test_simple_strtoul(void)
test_simple_strtoxx(unsigned long, simple_strtoul, "0x%lx", 0);
}
static void __init test_simple_strtol(void)
static void test_simple_strtol(struct kunit *test)
{
test_simple_strtoxx(long, simple_strtol, "%ld", 10);
test_simple_strtoxx(long, simple_strtol, "%ld", 0);
@ -755,60 +747,69 @@ static void __init test_simple_strtol(void)
}
/* Selection of common delimiters/separators between numbers in a string. */
static const char * const number_delimiters[] __initconst = {
static const char * const number_delimiters[] = {
" ", ":", ",", "-", "/",
};
static void __init test_numbers(void)
static void number_delimiter_param_desc(const char * const *param,
char *desc)
{
int i;
/* String containing only one number. */
numbers_simple();
/* String with multiple numbers separated by delimiter. */
for (i = 0; i < ARRAY_SIZE(number_delimiters); i++) {
numbers_list(number_delimiters[i]);
/* Field width may be longer than actual field digits. */
numbers_list_field_width_typemax(number_delimiters[i]);
/* Each field width exactly length of actual field digits. */
numbers_list_field_width_val_width(number_delimiters[i]);
}
/* Slice continuous sequence of digits using field widths. */
numbers_slice();
numbers_prefix_overflow();
snprintf(desc, KUNIT_PARAM_DESC_SIZE, "\"%s\"", *param);
}
static void __init selftest(void)
KUNIT_ARRAY_PARAM(number_delimiters, number_delimiters, number_delimiter_param_desc);
static struct kunit_case scanf_test_cases[] = {
KUNIT_CASE(numbers_simple),
/* String with multiple numbers separated by delimiter. */
KUNIT_CASE_PARAM(numbers_list, number_delimiters_gen_params),
/* Field width may be longer than actual field digits. */
KUNIT_CASE_PARAM(numbers_list_field_width_typemax, number_delimiters_gen_params),
/* Each field width exactly length of actual field digits. */
KUNIT_CASE_PARAM(numbers_list_field_width_val_width, number_delimiters_gen_params),
/* Slice continuous sequence of digits using field widths. */
KUNIT_CASE(numbers_slice),
KUNIT_CASE(numbers_prefix_overflow),
KUNIT_CASE(test_simple_strtoull),
KUNIT_CASE(test_simple_strtoll),
KUNIT_CASE(test_simple_strtoul),
KUNIT_CASE(test_simple_strtol),
{}
};
static int scanf_suite_init(struct kunit_suite *suite)
{
test_buffer = kmalloc(BUF_SIZE, GFP_KERNEL);
if (!test_buffer)
return;
return -ENOMEM;
fmt_buffer = kmalloc(BUF_SIZE, GFP_KERNEL);
if (!fmt_buffer) {
kfree(test_buffer);
return;
return -ENOMEM;
}
prandom_seed_state(&rnd_state, 3141592653589793238ULL);
test_numbers();
test_simple_strtoull();
test_simple_strtoll();
test_simple_strtoul();
test_simple_strtol();
return 0;
}
static void scanf_suite_exit(struct kunit_suite *suite)
{
kfree(fmt_buffer);
kfree(test_buffer);
}
KSTM_MODULE_LOADERS(test_scanf);
static struct kunit_suite scanf_test_suite = {
.name = "scanf",
.suite_init = scanf_suite_init,
.suite_exit = scanf_suite_exit,
.test_cases = scanf_test_cases,
};
kunit_test_suite(scanf_test_suite);
MODULE_AUTHOR("Richard Fitzgerald <rf@opensource.cirrus.com>");
MODULE_DESCRIPTION("Test cases for sscanf facility");
MODULE_LICENSE("GPL v2");

View File

@ -184,6 +184,15 @@ static bool stackinit_range_contains(char *haystack_start, size_t haystack_size,
#define INIT_UNION_assigned_copy(var_type) \
INIT_STRUCT_assigned_copy(var_type)
/*
* The "did we actually fill the stack?" check value needs
* to be neither 0 nor any of the "pattern" bytes. The
* pattern bytes are compiler, architecture, and type based,
* so we have to pick a value that never appears for those
* combinations. Use 0x99 which is not 0xFF, 0xFE, nor 0xAA.
*/
#define FILL_BYTE 0x99
/*
* @name: unique string name for the test
* @var_type: type to be tested for zeroing initialization
@ -206,12 +215,12 @@ static noinline void test_ ## name (struct kunit *test) \
ZERO_CLONE_ ## which(zero); \
/* Clear entire check buffer for 0xFF overlap test. */ \
memset(check_buf, 0x00, sizeof(check_buf)); \
/* Fill stack with 0xFF. */ \
/* Fill stack with FILL_BYTE. */ \
ignored = leaf_ ##name((unsigned long)&ignored, 1, \
FETCH_ARG_ ## which(zero)); \
/* Verify all bytes overwritten with 0xFF. */ \
/* Verify all bytes overwritten with FILL_BYTE. */ \
for (sum = 0, i = 0; i < target_size; i++) \
sum += (check_buf[i] != 0xFF); \
sum += (check_buf[i] != FILL_BYTE); \
/* Clear entire check buffer for later bit tests. */ \
memset(check_buf, 0x00, sizeof(check_buf)); \
/* Extract stack-defined variable contents. */ \
@ -222,7 +231,8 @@ static noinline void test_ ## name (struct kunit *test) \
* possible between the two leaf function calls. \
*/ \
KUNIT_ASSERT_EQ_MSG(test, sum, 0, \
"leaf fill was not 0xFF!?\n"); \
"leaf fill was not 0x%02X!?\n", \
FILL_BYTE); \
\
/* Validate that compiler lined up fill and target. */ \
KUNIT_ASSERT_TRUE_MSG(test, \
@ -234,9 +244,9 @@ static noinline void test_ ## name (struct kunit *test) \
(int)((ssize_t)(uintptr_t)fill_start - \
(ssize_t)(uintptr_t)target_start)); \
\
/* Look for any bytes still 0xFF in check region. */ \
/* Validate check region has no FILL_BYTE bytes. */ \
for (sum = 0, i = 0; i < target_size; i++) \
sum += (check_buf[i] == 0xFF); \
sum += (check_buf[i] == FILL_BYTE); \
\
if (sum != 0 && xfail) \
kunit_skip(test, \
@ -271,12 +281,12 @@ static noinline int leaf_ ## name(unsigned long sp, bool fill, \
* stack frame of SOME kind... \
*/ \
memset(buf, (char)(sp & 0xff), sizeof(buf)); \
/* Fill variable with 0xFF. */ \
/* Fill variable with FILL_BYTE. */ \
if (fill) { \
fill_start = &var; \
fill_size = sizeof(var); \
memset(fill_start, \
(char)((sp & 0xff) | forced_mask), \
FILL_BYTE & forced_mask, \
fill_size); \
} \
\
@ -469,7 +479,7 @@ static int noinline __leaf_switch_none(int path, bool fill)
fill_start = &var;
fill_size = sizeof(var);
memset(fill_start, forced_mask | 0x55, fill_size);
memset(fill_start, (forced_mask | 0x55) & FILL_BYTE, fill_size);
}
memcpy(check_buf, target_start, target_size);
break;
@ -480,7 +490,7 @@ static int noinline __leaf_switch_none(int path, bool fill)
fill_start = &var;
fill_size = sizeof(var);
memset(fill_start, forced_mask | 0xaa, fill_size);
memset(fill_start, (forced_mask | 0xaa) & FILL_BYTE, fill_size);
}
memcpy(check_buf, target_start, target_size);
break;

View File

@ -11,7 +11,7 @@
# SPDX-License-Identifier: GPL-2.0+
# $(dirname $0)/../kselftest/module.sh "description" module_name
#
# Example: tools/testing/selftests/lib/printf.sh
# Example: tools/testing/selftests/lib/bitmap.sh
desc="" # Output prefix.
module="" # Filename (without the .ko).

View File

@ -4,5 +4,5 @@
# No binaries, but make sure arg-less "make" doesn't trigger "run_tests"
all:
TEST_PROGS := printf.sh bitmap.sh prime_numbers.sh scanf.sh
TEST_PROGS := bitmap.sh
include ../lib.mk

View File

@ -1,5 +1,2 @@
CONFIG_TEST_PRINTF=m
CONFIG_TEST_SCANF=m
CONFIG_TEST_BITMAP=m
CONFIG_PRIME_NUMBERS=m
CONFIG_TEST_BITOPS=m

View File

@ -1,4 +0,0 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# Checks fast/slow prime_number generation for inconsistencies
$(dirname $0)/../kselftest/module.sh "prime numbers" prime_numbers selftest=65536

View File

@ -1,4 +0,0 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# Tests the printf infrastructure using test_printf kernel module.
$(dirname $0)/../kselftest/module.sh "printf" test_printf

View File

@ -1,4 +0,0 @@
#!/bin/sh
# SPDX-License-Identifier: GPL-2.0
# Tests the scanf infrastructure using test_scanf kernel module.
$(dirname $0)/../kselftest/module.sh "scanf" test_scanf