Skip to content

Commit 29d8568

Browse files
committed
string: Convert selftest to KUnit
Convert test_string.c to KUnit so it can be easily run with everything else. Additional text context is retained for failure reporting. For example, when forcing a bad match, we can see the loop counters reported for the memset() tests: [09:21:52] # test_memset64: ASSERTION FAILED at lib/string_kunit.c:93 [09:21:52] Expected v == 0xa2a1a1a1a1a1a1a1ULL, but [09:21:52] v == -6799976246779207263 (0xa1a1a1a1a1a1a1a1) [09:21:52] 0xa2a1a1a1a1a1a1a1ULL == -6727918652741279327 (0xa2a1a1a1a1a1a1a1) [09:21:52] i:0 j:0 k:0 [09:21:52] [FAILED] test_memset64 Currently passes without problems: $ ./tools/testing/kunit/kunit.py run string ... [09:37:40] Starting KUnit Kernel (1/1)... [09:37:40] ============================================================ [09:37:40] =================== string (6 subtests) ==================== [09:37:40] [PASSED] test_memset16 [09:37:40] [PASSED] test_memset32 [09:37:40] [PASSED] test_memset64 [09:37:40] [PASSED] test_strchr [09:37:40] [PASSED] test_strnchr [09:37:40] [PASSED] test_strspn [09:37:40] ===================== [PASSED] string ====================== [09:37:40] ============================================================ [09:37:40] Testing complete. Ran 6 tests: passed: 6 [09:37:40] Elapsed time: 6.730s total, 0.001s configuring, 6.562s building, 0.131s running Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Kees Cook <[email protected]>
1 parent e36b70f commit 29d8568

File tree

5 files changed

+205
-261
lines changed

5 files changed

+205
-261
lines changed

MAINTAINERS

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8976,9 +8976,9 @@ F: include/linux/string.h
89768976
F: include/linux/string_choices.h
89778977
F: include/linux/string_helpers.h
89788978
F: lib/string.c
8979+
F: lib/string_kunit.c
89798980
F: lib/string_helpers.c
89808981
F: lib/test-string_helpers.c
8981-
F: lib/test_string.c
89828982
F: scripts/coccinelle/api/string_choices.cocci
89838983

89848984
GENERIC UIO DRIVER FOR PCI DEVICES

lib/Kconfig.debug

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2352,8 +2352,10 @@ config ASYNC_RAID6_TEST
23522352
config TEST_HEXDUMP
23532353
tristate "Test functions located in the hexdump module at runtime"
23542354

2355-
config STRING_SELFTEST
2356-
tristate "Test string functions at runtime"
2355+
config STRING_KUNIT_TEST
2356+
tristate "KUnit test string functions at runtime" if !KUNIT_ALL_TESTS
2357+
depends on KUNIT
2358+
default KUNIT_ALL_TESTS
23572359

23582360
config TEST_STRING_HELPERS
23592361
tristate "Test functions located in the string_helpers module at runtime"

lib/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ obj-y += bcd.o sort.o parser.o debug_locks.o random32.o \
4949
percpu-refcount.o rhashtable.o base64.o \
5050
once.o refcount.o rcuref.o usercopy.o errseq.o bucket_locks.o \
5151
generic-radix-tree.o bitmap-str.o
52-
obj-$(CONFIG_STRING_SELFTEST) += test_string.o
52+
obj-$(CONFIG_STRING_KUNIT_TEST) += string_kunit.o
5353
obj-y += string_helpers.o
5454
obj-$(CONFIG_TEST_STRING_HELPERS) += test-string_helpers.o
5555
obj-y += hexdump.o

lib/string_kunit.c

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Test cases for string functions.
4+
*/
5+
6+
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7+
8+
#include <kunit/test.h>
9+
#include <linux/module.h>
10+
#include <linux/printk.h>
11+
#include <linux/slab.h>
12+
#include <linux/string.h>
13+
14+
static void test_memset16(struct kunit *test)
15+
{
16+
unsigned i, j, k;
17+
u16 v, *p;
18+
19+
p = kunit_kzalloc(test, 256 * 2 * 2, GFP_KERNEL);
20+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, p);
21+
22+
for (i = 0; i < 256; i++) {
23+
for (j = 0; j < 256; j++) {
24+
memset(p, 0xa1, 256 * 2 * sizeof(v));
25+
memset16(p + i, 0xb1b2, j);
26+
for (k = 0; k < 512; k++) {
27+
v = p[k];
28+
if (k < i) {
29+
KUNIT_ASSERT_EQ_MSG(test, v, 0xa1a1,
30+
"i:%d j:%d k:%d", i, j, k);
31+
} else if (k < i + j) {
32+
KUNIT_ASSERT_EQ_MSG(test, v, 0xb1b2,
33+
"i:%d j:%d k:%d", i, j, k);
34+
} else {
35+
KUNIT_ASSERT_EQ_MSG(test, v, 0xa1a1,
36+
"i:%d j:%d k:%d", i, j, k);
37+
}
38+
}
39+
}
40+
}
41+
}
42+
43+
static void test_memset32(struct kunit *test)
44+
{
45+
unsigned i, j, k;
46+
u32 v, *p;
47+
48+
p = kunit_kzalloc(test, 256 * 2 * 4, GFP_KERNEL);
49+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, p);
50+
51+
for (i = 0; i < 256; i++) {
52+
for (j = 0; j < 256; j++) {
53+
memset(p, 0xa1, 256 * 2 * sizeof(v));
54+
memset32(p + i, 0xb1b2b3b4, j);
55+
for (k = 0; k < 512; k++) {
56+
v = p[k];
57+
if (k < i) {
58+
KUNIT_ASSERT_EQ_MSG(test, v, 0xa1a1a1a1,
59+
"i:%d j:%d k:%d", i, j, k);
60+
} else if (k < i + j) {
61+
KUNIT_ASSERT_EQ_MSG(test, v, 0xb1b2b3b4,
62+
"i:%d j:%d k:%d", i, j, k);
63+
} else {
64+
KUNIT_ASSERT_EQ_MSG(test, v, 0xa1a1a1a1,
65+
"i:%d j:%d k:%d", i, j, k);
66+
}
67+
}
68+
}
69+
}
70+
}
71+
72+
static void test_memset64(struct kunit *test)
73+
{
74+
unsigned i, j, k;
75+
u64 v, *p;
76+
77+
p = kunit_kzalloc(test, 256 * 2 * 8, GFP_KERNEL);
78+
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, p);
79+
80+
for (i = 0; i < 256; i++) {
81+
for (j = 0; j < 256; j++) {
82+
memset(p, 0xa1, 256 * 2 * sizeof(v));
83+
memset64(p + i, 0xb1b2b3b4b5b6b7b8ULL, j);
84+
for (k = 0; k < 512; k++) {
85+
v = p[k];
86+
if (k < i) {
87+
KUNIT_ASSERT_EQ_MSG(test, v, 0xa1a1a1a1a1a1a1a1ULL,
88+
"i:%d j:%d k:%d", i, j, k);
89+
} else if (k < i + j) {
90+
KUNIT_ASSERT_EQ_MSG(test, v, 0xb1b2b3b4b5b6b7b8ULL,
91+
"i:%d j:%d k:%d", i, j, k);
92+
} else {
93+
KUNIT_ASSERT_EQ_MSG(test, v, 0xa1a1a1a1a1a1a1a1ULL,
94+
"i:%d j:%d k:%d", i, j, k);
95+
}
96+
}
97+
}
98+
}
99+
}
100+
101+
static void test_strchr(struct kunit *test)
102+
{
103+
const char *test_string = "abcdefghijkl";
104+
const char *empty_string = "";
105+
char *result;
106+
int i;
107+
108+
for (i = 0; i < strlen(test_string) + 1; i++) {
109+
result = strchr(test_string, test_string[i]);
110+
KUNIT_ASSERT_EQ_MSG(test, result - test_string, i,
111+
"char:%c", 'a' + i);
112+
}
113+
114+
result = strchr(empty_string, '\0');
115+
KUNIT_ASSERT_PTR_EQ(test, result, empty_string);
116+
117+
result = strchr(empty_string, 'a');
118+
KUNIT_ASSERT_NULL(test, result);
119+
120+
result = strchr(test_string, 'z');
121+
KUNIT_ASSERT_NULL(test, result);
122+
}
123+
124+
static void test_strnchr(struct kunit *test)
125+
{
126+
const char *test_string = "abcdefghijkl";
127+
const char *empty_string = "";
128+
char *result;
129+
int i, j;
130+
131+
for (i = 0; i < strlen(test_string) + 1; i++) {
132+
for (j = 0; j < strlen(test_string) + 2; j++) {
133+
result = strnchr(test_string, j, test_string[i]);
134+
if (j <= i) {
135+
KUNIT_ASSERT_NULL_MSG(test, result,
136+
"char:%c i:%d j:%d", 'a' + i, i, j);
137+
} else {
138+
KUNIT_ASSERT_EQ_MSG(test, result - test_string, i,
139+
"char:%c i:%d j:%d", 'a' + i, i, j);
140+
}
141+
}
142+
}
143+
144+
result = strnchr(empty_string, 0, '\0');
145+
KUNIT_ASSERT_NULL(test, result);
146+
147+
result = strnchr(empty_string, 1, '\0');
148+
KUNIT_ASSERT_PTR_EQ(test, result, empty_string);
149+
150+
result = strnchr(empty_string, 1, 'a');
151+
KUNIT_ASSERT_NULL(test, result);
152+
153+
result = strnchr(NULL, 0, '\0');
154+
KUNIT_ASSERT_NULL(test, result);
155+
}
156+
157+
static void test_strspn(struct kunit *test)
158+
{
159+
static const struct strspn_test {
160+
const char str[16];
161+
const char accept[16];
162+
const char reject[16];
163+
unsigned a;
164+
unsigned r;
165+
} tests[] = {
166+
{ "foobar", "", "", 0, 6 },
167+
{ "abba", "abc", "ABBA", 4, 4 },
168+
{ "abba", "a", "b", 1, 1 },
169+
{ "", "abc", "abc", 0, 0},
170+
};
171+
const struct strspn_test *s = tests;
172+
size_t i;
173+
174+
for (i = 0; i < ARRAY_SIZE(tests); ++i, ++s) {
175+
KUNIT_ASSERT_EQ_MSG(test, s->a, strspn(s->str, s->accept),
176+
"i:%zu", i);
177+
KUNIT_ASSERT_EQ_MSG(test, s->r, strcspn(s->str, s->reject),
178+
"i:%zu", i);
179+
}
180+
}
181+
182+
static struct kunit_case string_test_cases[] = {
183+
KUNIT_CASE(test_memset16),
184+
KUNIT_CASE(test_memset32),
185+
KUNIT_CASE(test_memset64),
186+
KUNIT_CASE(test_strchr),
187+
KUNIT_CASE(test_strnchr),
188+
KUNIT_CASE(test_strspn),
189+
{}
190+
};
191+
192+
static struct kunit_suite string_test_suite = {
193+
.name = "string",
194+
.test_cases = string_test_cases,
195+
};
196+
197+
kunit_test_suites(&string_test_suite);
198+
199+
MODULE_LICENSE("GPL v2");

0 commit comments

Comments
 (0)