]>
Commit | Line | Data |
---|---|---|
41eefc46 KC |
1 | // SPDX-License-Identifier: GPL-2.0+ |
2 | /* | |
3 | * Kernel module for testing 'strscpy' family of functions. | |
4 | */ | |
5 | ||
6 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt | |
7 | ||
8 | #include <kunit/test.h> | |
9 | #include <linux/string.h> | |
10 | ||
11 | /* | |
12 | * tc() - Run a specific test case. | |
13 | * @src: Source string, argument to strscpy_pad() | |
14 | * @count: Size of destination buffer, argument to strscpy_pad() | |
15 | * @expected: Expected return value from call to strscpy_pad() | |
16 | * @terminator: 1 if there should be a terminating null byte 0 otherwise. | |
17 | * @chars: Number of characters from the src string expected to be | |
18 | * written to the dst buffer. | |
19 | * @pad: Number of pad characters expected (in the tail of dst buffer). | |
20 | * (@pad does not include the null terminator byte.) | |
21 | * | |
22 | * Calls strscpy_pad() and verifies the return value and state of the | |
23 | * destination buffer after the call returns. | |
24 | */ | |
25 | static void tc(struct kunit *test, char *src, int count, int expected, | |
26 | int chars, int terminator, int pad) | |
27 | { | |
28 | int nr_bytes_poison; | |
29 | int max_expected; | |
30 | int max_count; | |
31 | int written; | |
32 | char buf[6]; | |
33 | int index, i; | |
34 | const char POISON = 'z'; | |
35 | ||
36 | KUNIT_ASSERT_TRUE_MSG(test, src != NULL, | |
37 | "null source string not supported"); | |
38 | ||
39 | memset(buf, POISON, sizeof(buf)); | |
40 | /* Future proofing test suite, validate args */ | |
41 | max_count = sizeof(buf) - 2; /* Space for null and to verify overflow */ | |
42 | max_expected = count - 1; /* Space for the null */ | |
43 | ||
44 | KUNIT_ASSERT_LE_MSG(test, count, max_count, | |
45 | "count (%d) is too big (%d) ... aborting", count, max_count); | |
46 | KUNIT_EXPECT_LE_MSG(test, expected, max_expected, | |
47 | "expected (%d) is bigger than can possibly be returned (%d)", | |
48 | expected, max_expected); | |
49 | ||
50 | written = strscpy_pad(buf, src, count); | |
51 | KUNIT_ASSERT_EQ(test, written, expected); | |
52 | ||
53 | if (count && written == -E2BIG) { | |
54 | KUNIT_ASSERT_EQ_MSG(test, 0, strncmp(buf, src, count - 1), | |
55 | "buffer state invalid for -E2BIG"); | |
56 | KUNIT_ASSERT_EQ_MSG(test, buf[count - 1], '\0', | |
57 | "too big string is not null terminated correctly"); | |
58 | } | |
59 | ||
60 | for (i = 0; i < chars; i++) | |
61 | KUNIT_ASSERT_EQ_MSG(test, buf[i], src[i], | |
62 | "buf[i]==%c != src[i]==%c", buf[i], src[i]); | |
63 | ||
64 | if (terminator) | |
65 | KUNIT_ASSERT_EQ_MSG(test, buf[count - 1], '\0', | |
66 | "string is not null terminated correctly"); | |
67 | ||
68 | for (i = 0; i < pad; i++) { | |
69 | index = chars + terminator + i; | |
70 | KUNIT_ASSERT_EQ_MSG(test, buf[index], '\0', | |
71 | "padding missing at index: %d", i); | |
72 | } | |
73 | ||
74 | nr_bytes_poison = sizeof(buf) - chars - terminator - pad; | |
75 | for (i = 0; i < nr_bytes_poison; i++) { | |
76 | index = sizeof(buf) - 1 - i; /* Check from the end back */ | |
77 | KUNIT_ASSERT_EQ_MSG(test, buf[index], POISON, | |
78 | "poison value missing at index: %d", i); | |
79 | } | |
80 | } | |
81 | ||
82 | static void strscpy_test(struct kunit *test) | |
83 | { | |
62e1cbfc KC |
84 | char dest[8]; |
85 | ||
41eefc46 KC |
86 | /* |
87 | * tc() uses a destination buffer of size 6 and needs at | |
88 | * least 2 characters spare (one for null and one to check for | |
89 | * overflow). This means we should only call tc() with | |
90 | * strings up to a maximum of 4 characters long and 'count' | |
91 | * should not exceed 4. To test with longer strings increase | |
92 | * the buffer size in tc(). | |
93 | */ | |
94 | ||
95 | /* tc(test, src, count, expected, chars, terminator, pad) */ | |
96 | tc(test, "a", 0, -E2BIG, 0, 0, 0); | |
97 | tc(test, "", 0, -E2BIG, 0, 0, 0); | |
98 | ||
99 | tc(test, "a", 1, -E2BIG, 0, 1, 0); | |
100 | tc(test, "", 1, 0, 0, 1, 0); | |
101 | ||
102 | tc(test, "ab", 2, -E2BIG, 1, 1, 0); | |
103 | tc(test, "a", 2, 1, 1, 1, 0); | |
104 | tc(test, "", 2, 0, 0, 1, 1); | |
105 | ||
106 | tc(test, "abc", 3, -E2BIG, 2, 1, 0); | |
107 | tc(test, "ab", 3, 2, 2, 1, 0); | |
108 | tc(test, "a", 3, 1, 1, 1, 1); | |
109 | tc(test, "", 3, 0, 0, 1, 2); | |
110 | ||
111 | tc(test, "abcd", 4, -E2BIG, 3, 1, 0); | |
112 | tc(test, "abc", 4, 3, 3, 1, 0); | |
113 | tc(test, "ab", 4, 2, 2, 1, 1); | |
114 | tc(test, "a", 4, 1, 1, 1, 2); | |
115 | tc(test, "", 4, 0, 0, 1, 3); | |
62e1cbfc KC |
116 | |
117 | /* Compile-time-known source strings. */ | |
118 | KUNIT_EXPECT_EQ(test, strscpy(dest, "", ARRAY_SIZE(dest)), 0); | |
119 | KUNIT_EXPECT_EQ(test, strscpy(dest, "", 3), 0); | |
120 | KUNIT_EXPECT_EQ(test, strscpy(dest, "", 1), 0); | |
121 | KUNIT_EXPECT_EQ(test, strscpy(dest, "", 0), -E2BIG); | |
122 | KUNIT_EXPECT_EQ(test, strscpy(dest, "Fixed", ARRAY_SIZE(dest)), 5); | |
123 | KUNIT_EXPECT_EQ(test, strscpy(dest, "Fixed", 3), -E2BIG); | |
124 | KUNIT_EXPECT_EQ(test, strscpy(dest, "Fixed", 1), -E2BIG); | |
125 | KUNIT_EXPECT_EQ(test, strscpy(dest, "Fixed", 0), -E2BIG); | |
126 | KUNIT_EXPECT_EQ(test, strscpy(dest, "This is too long", ARRAY_SIZE(dest)), -E2BIG); | |
41eefc46 KC |
127 | } |
128 | ||
129 | static struct kunit_case strscpy_test_cases[] = { | |
130 | KUNIT_CASE(strscpy_test), | |
131 | {} | |
132 | }; | |
133 | ||
134 | static struct kunit_suite strscpy_test_suite = { | |
135 | .name = "strscpy", | |
136 | .test_cases = strscpy_test_cases, | |
137 | }; | |
138 | ||
139 | kunit_test_suite(strscpy_test_suite); | |
140 | ||
141 | MODULE_AUTHOR("Tobin C. Harding <[email protected]>"); | |
142 | MODULE_LICENSE("GPL"); |