1bb95ebbeSKees Cook // SPDX-License-Identifier: GPL-2.0
2bb95ebbeSKees Cook /*
3bb95ebbeSKees Cook * Test cases for memcpy(), memmove(), and memset().
4bb95ebbeSKees Cook */
5bb95ebbeSKees Cook #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
6bb95ebbeSKees Cook
7bb95ebbeSKees Cook #include <kunit/test.h>
8bb95ebbeSKees Cook #include <linux/device.h>
9bb95ebbeSKees Cook #include <linux/init.h>
10bb95ebbeSKees Cook #include <linux/kernel.h>
11bb95ebbeSKees Cook #include <linux/mm.h>
12bb95ebbeSKees Cook #include <linux/module.h>
13bb95ebbeSKees Cook #include <linux/overflow.h>
14bb95ebbeSKees Cook #include <linux/slab.h>
15bb95ebbeSKees Cook #include <linux/types.h>
16bb95ebbeSKees Cook #include <linux/vmalloc.h>
17bb95ebbeSKees Cook
18bb95ebbeSKees Cook struct some_bytes {
19bb95ebbeSKees Cook union {
20bb95ebbeSKees Cook u8 data[32];
21bb95ebbeSKees Cook struct {
22bb95ebbeSKees Cook u32 one;
23bb95ebbeSKees Cook u16 two;
24bb95ebbeSKees Cook u8 three;
25bb95ebbeSKees Cook /* 1 byte hole */
26bb95ebbeSKees Cook u32 four[4];
27bb95ebbeSKees Cook };
28bb95ebbeSKees Cook };
29bb95ebbeSKees Cook };
30bb95ebbeSKees Cook
31bb95ebbeSKees Cook #define check(instance, v) do { \
32bb95ebbeSKees Cook BUILD_BUG_ON(sizeof(instance.data) != 32); \
33dfbafa70SKees Cook for (size_t i = 0; i < sizeof(instance.data); i++) { \
34bb95ebbeSKees Cook KUNIT_ASSERT_EQ_MSG(test, instance.data[i], v, \
35*3c3d394bSDavid Gow "line %d: '%s' not initialized to 0x%02x @ %zu (saw 0x%02x)\n", \
36bb95ebbeSKees Cook __LINE__, #instance, v, i, instance.data[i]); \
37bb95ebbeSKees Cook } \
38bb95ebbeSKees Cook } while (0)
39bb95ebbeSKees Cook
40bb95ebbeSKees Cook #define compare(name, one, two) do { \
41bb95ebbeSKees Cook BUILD_BUG_ON(sizeof(one) != sizeof(two)); \
42dfbafa70SKees Cook for (size_t i = 0; i < sizeof(one); i++) { \
43bb95ebbeSKees Cook KUNIT_EXPECT_EQ_MSG(test, one.data[i], two.data[i], \
44*3c3d394bSDavid Gow "line %d: %s.data[%zu] (0x%02x) != %s.data[%zu] (0x%02x)\n", \
45bb95ebbeSKees Cook __LINE__, #one, i, one.data[i], #two, i, two.data[i]); \
46bb95ebbeSKees Cook } \
47bb95ebbeSKees Cook kunit_info(test, "ok: " TEST_OP "() " name "\n"); \
48bb95ebbeSKees Cook } while (0)
49bb95ebbeSKees Cook
memcpy_test(struct kunit * test)50bb95ebbeSKees Cook static void memcpy_test(struct kunit *test)
51bb95ebbeSKees Cook {
52bb95ebbeSKees Cook #define TEST_OP "memcpy"
53bb95ebbeSKees Cook struct some_bytes control = {
54bb95ebbeSKees Cook .data = { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
55bb95ebbeSKees Cook 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
56bb95ebbeSKees Cook 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
57bb95ebbeSKees Cook 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
58bb95ebbeSKees Cook },
59bb95ebbeSKees Cook };
60bb95ebbeSKees Cook struct some_bytes zero = { };
61bb95ebbeSKees Cook struct some_bytes middle = {
62bb95ebbeSKees Cook .data = { 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
63bb95ebbeSKees Cook 0x20, 0x20, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00,
64bb95ebbeSKees Cook 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20,
65bb95ebbeSKees Cook 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
66bb95ebbeSKees Cook },
67bb95ebbeSKees Cook };
68bb95ebbeSKees Cook struct some_bytes three = {
69bb95ebbeSKees Cook .data = { 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
70bb95ebbeSKees Cook 0x20, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20,
71bb95ebbeSKees Cook 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
72bb95ebbeSKees Cook 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
73bb95ebbeSKees Cook },
74bb95ebbeSKees Cook };
75bb95ebbeSKees Cook struct some_bytes dest = { };
76bb95ebbeSKees Cook int count;
77bb95ebbeSKees Cook u8 *ptr;
78bb95ebbeSKees Cook
79bb95ebbeSKees Cook /* Verify static initializers. */
80bb95ebbeSKees Cook check(control, 0x20);
81bb95ebbeSKees Cook check(zero, 0);
82bb95ebbeSKees Cook compare("static initializers", dest, zero);
83bb95ebbeSKees Cook
84bb95ebbeSKees Cook /* Verify assignment. */
85bb95ebbeSKees Cook dest = control;
86bb95ebbeSKees Cook compare("direct assignment", dest, control);
87bb95ebbeSKees Cook
88bb95ebbeSKees Cook /* Verify complete overwrite. */
89bb95ebbeSKees Cook memcpy(dest.data, zero.data, sizeof(dest.data));
90bb95ebbeSKees Cook compare("complete overwrite", dest, zero);
91bb95ebbeSKees Cook
92bb95ebbeSKees Cook /* Verify middle overwrite. */
93bb95ebbeSKees Cook dest = control;
94bb95ebbeSKees Cook memcpy(dest.data + 12, zero.data, 7);
95bb95ebbeSKees Cook compare("middle overwrite", dest, middle);
96bb95ebbeSKees Cook
97bb95ebbeSKees Cook /* Verify argument side-effects aren't repeated. */
98bb95ebbeSKees Cook dest = control;
99bb95ebbeSKees Cook ptr = dest.data;
100bb95ebbeSKees Cook count = 1;
101bb95ebbeSKees Cook memcpy(ptr++, zero.data, count++);
102bb95ebbeSKees Cook ptr += 8;
103bb95ebbeSKees Cook memcpy(ptr++, zero.data, count++);
104bb95ebbeSKees Cook compare("argument side-effects", dest, three);
105bb95ebbeSKees Cook #undef TEST_OP
106bb95ebbeSKees Cook }
107bb95ebbeSKees Cook
108bce5a1e8SNick Desaulniers static unsigned char larger_array [2048];
109bce5a1e8SNick Desaulniers
memmove_test(struct kunit * test)110bb95ebbeSKees Cook static void memmove_test(struct kunit *test)
111bb95ebbeSKees Cook {
112bb95ebbeSKees Cook #define TEST_OP "memmove"
113bb95ebbeSKees Cook struct some_bytes control = {
114bb95ebbeSKees Cook .data = { 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
115bb95ebbeSKees Cook 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
116bb95ebbeSKees Cook 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
117bb95ebbeSKees Cook 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
118bb95ebbeSKees Cook },
119bb95ebbeSKees Cook };
120bb95ebbeSKees Cook struct some_bytes zero = { };
121bb95ebbeSKees Cook struct some_bytes middle = {
122bb95ebbeSKees Cook .data = { 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
123bb95ebbeSKees Cook 0x99, 0x99, 0x99, 0x99, 0x00, 0x00, 0x00, 0x00,
124bb95ebbeSKees Cook 0x00, 0x00, 0x00, 0x99, 0x99, 0x99, 0x99, 0x99,
125bb95ebbeSKees Cook 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
126bb95ebbeSKees Cook },
127bb95ebbeSKees Cook };
128bb95ebbeSKees Cook struct some_bytes five = {
129bb95ebbeSKees Cook .data = { 0x00, 0x00, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
130bb95ebbeSKees Cook 0x99, 0x99, 0x00, 0x00, 0x00, 0x99, 0x99, 0x99,
131bb95ebbeSKees Cook 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
132bb95ebbeSKees Cook 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
133bb95ebbeSKees Cook },
134bb95ebbeSKees Cook };
135bb95ebbeSKees Cook struct some_bytes overlap = {
136bb95ebbeSKees Cook .data = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
137bb95ebbeSKees Cook 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
138bb95ebbeSKees Cook 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
139bb95ebbeSKees Cook 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
140bb95ebbeSKees Cook },
141bb95ebbeSKees Cook };
142bb95ebbeSKees Cook struct some_bytes overlap_expected = {
143bb95ebbeSKees Cook .data = { 0x00, 0x01, 0x00, 0x01, 0x02, 0x03, 0x04, 0x07,
144bb95ebbeSKees Cook 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
145bb95ebbeSKees Cook 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
146bb95ebbeSKees Cook 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
147bb95ebbeSKees Cook },
148bb95ebbeSKees Cook };
149bb95ebbeSKees Cook struct some_bytes dest = { };
150bb95ebbeSKees Cook int count;
151bb95ebbeSKees Cook u8 *ptr;
152bb95ebbeSKees Cook
153bb95ebbeSKees Cook /* Verify static initializers. */
154bb95ebbeSKees Cook check(control, 0x99);
155bb95ebbeSKees Cook check(zero, 0);
156bb95ebbeSKees Cook compare("static initializers", zero, dest);
157bb95ebbeSKees Cook
158bb95ebbeSKees Cook /* Verify assignment. */
159bb95ebbeSKees Cook dest = control;
160bb95ebbeSKees Cook compare("direct assignment", dest, control);
161bb95ebbeSKees Cook
162bb95ebbeSKees Cook /* Verify complete overwrite. */
163bb95ebbeSKees Cook memmove(dest.data, zero.data, sizeof(dest.data));
164bb95ebbeSKees Cook compare("complete overwrite", dest, zero);
165bb95ebbeSKees Cook
166bb95ebbeSKees Cook /* Verify middle overwrite. */
167bb95ebbeSKees Cook dest = control;
168bb95ebbeSKees Cook memmove(dest.data + 12, zero.data, 7);
169bb95ebbeSKees Cook compare("middle overwrite", dest, middle);
170bb95ebbeSKees Cook
171bb95ebbeSKees Cook /* Verify argument side-effects aren't repeated. */
172bb95ebbeSKees Cook dest = control;
173bb95ebbeSKees Cook ptr = dest.data;
174bb95ebbeSKees Cook count = 2;
175bb95ebbeSKees Cook memmove(ptr++, zero.data, count++);
176bb95ebbeSKees Cook ptr += 9;
177bb95ebbeSKees Cook memmove(ptr++, zero.data, count++);
178bb95ebbeSKees Cook compare("argument side-effects", dest, five);
179bb95ebbeSKees Cook
180bb95ebbeSKees Cook /* Verify overlapping overwrite is correct. */
181bb95ebbeSKees Cook ptr = &overlap.data[2];
182bb95ebbeSKees Cook memmove(ptr, overlap.data, 5);
183bb95ebbeSKees Cook compare("overlapping write", overlap, overlap_expected);
184bce5a1e8SNick Desaulniers
185bce5a1e8SNick Desaulniers /* Verify larger overlapping moves. */
186bce5a1e8SNick Desaulniers larger_array[256] = 0xAAu;
187bce5a1e8SNick Desaulniers /*
188bce5a1e8SNick Desaulniers * Test a backwards overlapping memmove first. 256 and 1024 are
189bce5a1e8SNick Desaulniers * important for i386 to use rep movsl.
190bce5a1e8SNick Desaulniers */
191bce5a1e8SNick Desaulniers memmove(larger_array, larger_array + 256, 1024);
192bce5a1e8SNick Desaulniers KUNIT_ASSERT_EQ(test, larger_array[0], 0xAAu);
193bce5a1e8SNick Desaulniers KUNIT_ASSERT_EQ(test, larger_array[256], 0x00);
194bce5a1e8SNick Desaulniers KUNIT_ASSERT_NULL(test,
195bce5a1e8SNick Desaulniers memchr(larger_array + 1, 0xaa, ARRAY_SIZE(larger_array) - 1));
196bce5a1e8SNick Desaulniers /* Test a forwards overlapping memmove. */
197bce5a1e8SNick Desaulniers larger_array[0] = 0xBBu;
198bce5a1e8SNick Desaulniers memmove(larger_array + 256, larger_array, 1024);
199bce5a1e8SNick Desaulniers KUNIT_ASSERT_EQ(test, larger_array[0], 0xBBu);
200bce5a1e8SNick Desaulniers KUNIT_ASSERT_EQ(test, larger_array[256], 0xBBu);
201bce5a1e8SNick Desaulniers KUNIT_ASSERT_NULL(test, memchr(larger_array + 1, 0xBBu, 256 - 1));
202bce5a1e8SNick Desaulniers KUNIT_ASSERT_NULL(test,
203bce5a1e8SNick Desaulniers memchr(larger_array + 257, 0xBBu, ARRAY_SIZE(larger_array) - 257));
204bb95ebbeSKees Cook #undef TEST_OP
205bb95ebbeSKees Cook }
206bb95ebbeSKees Cook
memset_test(struct kunit * test)207bb95ebbeSKees Cook static void memset_test(struct kunit *test)
208bb95ebbeSKees Cook {
209bb95ebbeSKees Cook #define TEST_OP "memset"
210bb95ebbeSKees Cook struct some_bytes control = {
211bb95ebbeSKees Cook .data = { 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
212bb95ebbeSKees Cook 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
213bb95ebbeSKees Cook 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
214bb95ebbeSKees Cook 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
215bb95ebbeSKees Cook },
216bb95ebbeSKees Cook };
217bb95ebbeSKees Cook struct some_bytes complete = {
218bb95ebbeSKees Cook .data = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
219bb95ebbeSKees Cook 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
220bb95ebbeSKees Cook 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
221bb95ebbeSKees Cook 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
222bb95ebbeSKees Cook },
223bb95ebbeSKees Cook };
224bb95ebbeSKees Cook struct some_bytes middle = {
225bb95ebbeSKees Cook .data = { 0x30, 0x30, 0x30, 0x30, 0x31, 0x31, 0x31, 0x31,
226bb95ebbeSKees Cook 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31, 0x31,
227bb95ebbeSKees Cook 0x31, 0x31, 0x31, 0x31, 0x30, 0x30, 0x30, 0x30,
228bb95ebbeSKees Cook 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
229bb95ebbeSKees Cook },
230bb95ebbeSKees Cook };
231bb95ebbeSKees Cook struct some_bytes three = {
232bb95ebbeSKees Cook .data = { 0x60, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
233bb95ebbeSKees Cook 0x30, 0x61, 0x61, 0x30, 0x30, 0x30, 0x30, 0x30,
234bb95ebbeSKees Cook 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
235bb95ebbeSKees Cook 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
236bb95ebbeSKees Cook },
237bb95ebbeSKees Cook };
2384797632fSKees Cook struct some_bytes after = {
2394797632fSKees Cook .data = { 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x72,
2404797632fSKees Cook 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72,
2414797632fSKees Cook 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72,
2424797632fSKees Cook 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72, 0x72,
2434797632fSKees Cook },
2444797632fSKees Cook };
2456dbefad4SKees Cook struct some_bytes startat = {
2466dbefad4SKees Cook .data = { 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30,
2476dbefad4SKees Cook 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79,
2486dbefad4SKees Cook 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79,
2496dbefad4SKees Cook 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79,
2506dbefad4SKees Cook },
2516dbefad4SKees Cook };
252bb95ebbeSKees Cook struct some_bytes dest = { };
253bb95ebbeSKees Cook int count, value;
254bb95ebbeSKees Cook u8 *ptr;
255bb95ebbeSKees Cook
256bb95ebbeSKees Cook /* Verify static initializers. */
257bb95ebbeSKees Cook check(control, 0x30);
258bb95ebbeSKees Cook check(dest, 0);
259bb95ebbeSKees Cook
260bb95ebbeSKees Cook /* Verify assignment. */
261bb95ebbeSKees Cook dest = control;
262bb95ebbeSKees Cook compare("direct assignment", dest, control);
263bb95ebbeSKees Cook
264bb95ebbeSKees Cook /* Verify complete overwrite. */
265bb95ebbeSKees Cook memset(dest.data, 0xff, sizeof(dest.data));
266bb95ebbeSKees Cook compare("complete overwrite", dest, complete);
267bb95ebbeSKees Cook
268bb95ebbeSKees Cook /* Verify middle overwrite. */
269bb95ebbeSKees Cook dest = control;
270bb95ebbeSKees Cook memset(dest.data + 4, 0x31, 16);
271bb95ebbeSKees Cook compare("middle overwrite", dest, middle);
272bb95ebbeSKees Cook
273bb95ebbeSKees Cook /* Verify argument side-effects aren't repeated. */
274bb95ebbeSKees Cook dest = control;
275bb95ebbeSKees Cook ptr = dest.data;
276bb95ebbeSKees Cook value = 0x60;
277bb95ebbeSKees Cook count = 1;
278bb95ebbeSKees Cook memset(ptr++, value++, count++);
279bb95ebbeSKees Cook ptr += 8;
280bb95ebbeSKees Cook memset(ptr++, value++, count++);
281bb95ebbeSKees Cook compare("argument side-effects", dest, three);
2824797632fSKees Cook
2834797632fSKees Cook /* Verify memset_after() */
2844797632fSKees Cook dest = control;
2854797632fSKees Cook memset_after(&dest, 0x72, three);
2864797632fSKees Cook compare("memset_after()", dest, after);
2874797632fSKees Cook
2886dbefad4SKees Cook /* Verify memset_startat() */
2896dbefad4SKees Cook dest = control;
2906dbefad4SKees Cook memset_startat(&dest, 0x79, four);
2916dbefad4SKees Cook compare("memset_startat()", dest, startat);
292bb95ebbeSKees Cook #undef TEST_OP
293bb95ebbeSKees Cook }
294bb95ebbeSKees Cook
29596fce387SKees Cook static u8 large_src[1024];
29696fce387SKees Cook static u8 large_dst[2048];
29796fce387SKees Cook static const u8 large_zero[2048];
29896fce387SKees Cook
set_random_nonzero(struct kunit * test,u8 * byte)29996fce387SKees Cook static void set_random_nonzero(struct kunit *test, u8 *byte)
30096fce387SKees Cook {
30196fce387SKees Cook int failed_rng = 0;
30296fce387SKees Cook
30396fce387SKees Cook while (*byte == 0) {
30496fce387SKees Cook get_random_bytes(byte, 1);
30596fce387SKees Cook KUNIT_ASSERT_LT_MSG(test, failed_rng++, 100,
30696fce387SKees Cook "Is the RNG broken?");
30796fce387SKees Cook }
30896fce387SKees Cook }
30996fce387SKees Cook
init_large(struct kunit * test)31096fce387SKees Cook static void init_large(struct kunit *test)
31196fce387SKees Cook {
3124acf1de3SKees Cook if (!IS_ENABLED(CONFIG_MEMCPY_SLOW_KUNIT_TEST))
3134acf1de3SKees Cook kunit_skip(test, "Slow test skipped. Enable with CONFIG_MEMCPY_SLOW_KUNIT_TEST=y");
31496fce387SKees Cook
31596fce387SKees Cook /* Get many bit patterns. */
31696fce387SKees Cook get_random_bytes(large_src, ARRAY_SIZE(large_src));
31796fce387SKees Cook
31896fce387SKees Cook /* Make sure we have non-zero edges. */
31996fce387SKees Cook set_random_nonzero(test, &large_src[0]);
32096fce387SKees Cook set_random_nonzero(test, &large_src[ARRAY_SIZE(large_src) - 1]);
32196fce387SKees Cook
32296fce387SKees Cook /* Explicitly zero the entire destination. */
32396fce387SKees Cook memset(large_dst, 0, ARRAY_SIZE(large_dst));
32496fce387SKees Cook }
32596fce387SKees Cook
32696fce387SKees Cook /*
32796fce387SKees Cook * Instead of an indirect function call for "copy" or a giant macro,
32896fce387SKees Cook * use a bool to pick memcpy or memmove.
32996fce387SKees Cook */
copy_large_test(struct kunit * test,bool use_memmove)33096fce387SKees Cook static void copy_large_test(struct kunit *test, bool use_memmove)
33196fce387SKees Cook {
33296fce387SKees Cook init_large(test);
33396fce387SKees Cook
33496fce387SKees Cook /* Copy a growing number of non-overlapping bytes ... */
33596fce387SKees Cook for (int bytes = 1; bytes <= ARRAY_SIZE(large_src); bytes++) {
33696fce387SKees Cook /* Over a shifting destination window ... */
33796fce387SKees Cook for (int offset = 0; offset < ARRAY_SIZE(large_src); offset++) {
33896fce387SKees Cook int right_zero_pos = offset + bytes;
33996fce387SKees Cook int right_zero_size = ARRAY_SIZE(large_dst) - right_zero_pos;
34096fce387SKees Cook
34196fce387SKees Cook /* Copy! */
34296fce387SKees Cook if (use_memmove)
34396fce387SKees Cook memmove(large_dst + offset, large_src, bytes);
34496fce387SKees Cook else
34596fce387SKees Cook memcpy(large_dst + offset, large_src, bytes);
34696fce387SKees Cook
34796fce387SKees Cook /* Did we touch anything before the copy area? */
34896fce387SKees Cook KUNIT_ASSERT_EQ_MSG(test,
34996fce387SKees Cook memcmp(large_dst, large_zero, offset), 0,
35096fce387SKees Cook "with size %d at offset %d", bytes, offset);
35196fce387SKees Cook /* Did we touch anything after the copy area? */
35296fce387SKees Cook KUNIT_ASSERT_EQ_MSG(test,
35396fce387SKees Cook memcmp(&large_dst[right_zero_pos], large_zero, right_zero_size), 0,
35496fce387SKees Cook "with size %d at offset %d", bytes, offset);
35596fce387SKees Cook
35696fce387SKees Cook /* Are we byte-for-byte exact across the copy? */
35796fce387SKees Cook KUNIT_ASSERT_EQ_MSG(test,
35896fce387SKees Cook memcmp(large_dst + offset, large_src, bytes), 0,
35996fce387SKees Cook "with size %d at offset %d", bytes, offset);
36096fce387SKees Cook
36196fce387SKees Cook /* Zero out what we copied for the next cycle. */
36296fce387SKees Cook memset(large_dst + offset, 0, bytes);
36396fce387SKees Cook }
36496fce387SKees Cook /* Avoid stall warnings if this loop gets slow. */
36596fce387SKees Cook cond_resched();
36696fce387SKees Cook }
36796fce387SKees Cook }
36896fce387SKees Cook
memcpy_large_test(struct kunit * test)36996fce387SKees Cook static void memcpy_large_test(struct kunit *test)
37096fce387SKees Cook {
37196fce387SKees Cook copy_large_test(test, false);
37296fce387SKees Cook }
37396fce387SKees Cook
memmove_large_test(struct kunit * test)37496fce387SKees Cook static void memmove_large_test(struct kunit *test)
37596fce387SKees Cook {
37696fce387SKees Cook copy_large_test(test, true);
37796fce387SKees Cook }
37896fce387SKees Cook
37996fce387SKees Cook /*
38096fce387SKees Cook * On the assumption that boundary conditions are going to be the most
38196fce387SKees Cook * sensitive, instead of taking a full step (inc) each iteration,
38296fce387SKees Cook * take single index steps for at least the first "inc"-many indexes
38396fce387SKees Cook * from the "start" and at least the last "inc"-many indexes before
38496fce387SKees Cook * the "end". When in the middle, take full "inc"-wide steps. For
38596fce387SKees Cook * example, calling next_step(idx, 1, 15, 3) with idx starting at 0
38696fce387SKees Cook * would see the following pattern: 1 2 3 4 7 10 11 12 13 14 15.
38796fce387SKees Cook */
next_step(int idx,int start,int end,int inc)38896fce387SKees Cook static int next_step(int idx, int start, int end, int inc)
38996fce387SKees Cook {
39096fce387SKees Cook start += inc;
39196fce387SKees Cook end -= inc;
39296fce387SKees Cook
39396fce387SKees Cook if (idx < start || idx + inc > end)
39496fce387SKees Cook inc = 1;
39596fce387SKees Cook return idx + inc;
39696fce387SKees Cook }
39796fce387SKees Cook
inner_loop(struct kunit * test,int bytes,int d_off,int s_off)39896fce387SKees Cook static void inner_loop(struct kunit *test, int bytes, int d_off, int s_off)
39996fce387SKees Cook {
40096fce387SKees Cook int left_zero_pos, left_zero_size;
40196fce387SKees Cook int right_zero_pos, right_zero_size;
40296fce387SKees Cook int src_pos, src_orig_pos, src_size;
40396fce387SKees Cook int pos;
40496fce387SKees Cook
40596fce387SKees Cook /* Place the source in the destination buffer. */
40696fce387SKees Cook memcpy(&large_dst[s_off], large_src, bytes);
40796fce387SKees Cook
40896fce387SKees Cook /* Copy to destination offset. */
40996fce387SKees Cook memmove(&large_dst[d_off], &large_dst[s_off], bytes);
41096fce387SKees Cook
41196fce387SKees Cook /* Make sure destination entirely matches. */
41296fce387SKees Cook KUNIT_ASSERT_EQ_MSG(test, memcmp(&large_dst[d_off], large_src, bytes), 0,
41396fce387SKees Cook "with size %d at src offset %d and dest offset %d",
41496fce387SKees Cook bytes, s_off, d_off);
41596fce387SKees Cook
41696fce387SKees Cook /* Calculate the expected zero spans. */
41796fce387SKees Cook if (s_off < d_off) {
41896fce387SKees Cook left_zero_pos = 0;
41996fce387SKees Cook left_zero_size = s_off;
42096fce387SKees Cook
42196fce387SKees Cook right_zero_pos = d_off + bytes;
42296fce387SKees Cook right_zero_size = ARRAY_SIZE(large_dst) - right_zero_pos;
42396fce387SKees Cook
42496fce387SKees Cook src_pos = s_off;
42596fce387SKees Cook src_orig_pos = 0;
42696fce387SKees Cook src_size = d_off - s_off;
42796fce387SKees Cook } else {
42896fce387SKees Cook left_zero_pos = 0;
42996fce387SKees Cook left_zero_size = d_off;
43096fce387SKees Cook
43196fce387SKees Cook right_zero_pos = s_off + bytes;
43296fce387SKees Cook right_zero_size = ARRAY_SIZE(large_dst) - right_zero_pos;
43396fce387SKees Cook
43496fce387SKees Cook src_pos = d_off + bytes;
43596fce387SKees Cook src_orig_pos = src_pos - s_off;
43696fce387SKees Cook src_size = right_zero_pos - src_pos;
43796fce387SKees Cook }
43896fce387SKees Cook
43996fce387SKees Cook /* Check non-overlapping source is unchanged.*/
44096fce387SKees Cook KUNIT_ASSERT_EQ_MSG(test,
44196fce387SKees Cook memcmp(&large_dst[src_pos], &large_src[src_orig_pos], src_size), 0,
44296fce387SKees Cook "with size %d at src offset %d and dest offset %d",
44396fce387SKees Cook bytes, s_off, d_off);
44496fce387SKees Cook
44596fce387SKees Cook /* Check leading buffer contents are zero. */
44696fce387SKees Cook KUNIT_ASSERT_EQ_MSG(test,
44796fce387SKees Cook memcmp(&large_dst[left_zero_pos], large_zero, left_zero_size), 0,
44896fce387SKees Cook "with size %d at src offset %d and dest offset %d",
44996fce387SKees Cook bytes, s_off, d_off);
45096fce387SKees Cook /* Check trailing buffer contents are zero. */
45196fce387SKees Cook KUNIT_ASSERT_EQ_MSG(test,
45296fce387SKees Cook memcmp(&large_dst[right_zero_pos], large_zero, right_zero_size), 0,
45396fce387SKees Cook "with size %d at src offset %d and dest offset %d",
45496fce387SKees Cook bytes, s_off, d_off);
45596fce387SKees Cook
45696fce387SKees Cook /* Zero out everything not already zeroed.*/
45796fce387SKees Cook pos = left_zero_pos + left_zero_size;
45896fce387SKees Cook memset(&large_dst[pos], 0, right_zero_pos - pos);
45996fce387SKees Cook }
46096fce387SKees Cook
memmove_overlap_test(struct kunit * test)46196fce387SKees Cook static void memmove_overlap_test(struct kunit *test)
46296fce387SKees Cook {
46396fce387SKees Cook /*
46496fce387SKees Cook * Running all possible offset and overlap combinations takes a
46596fce387SKees Cook * very long time. Instead, only check up to 128 bytes offset
46696fce387SKees Cook * into the destination buffer (which should result in crossing
46796fce387SKees Cook * cachelines), with a step size of 1 through 7 to try to skip some
46896fce387SKees Cook * redundancy.
46996fce387SKees Cook */
47096fce387SKees Cook static const int offset_max = 128; /* less than ARRAY_SIZE(large_src); */
47196fce387SKees Cook static const int bytes_step = 7;
47296fce387SKees Cook static const int window_step = 7;
47396fce387SKees Cook
47496fce387SKees Cook static const int bytes_start = 1;
47596fce387SKees Cook static const int bytes_end = ARRAY_SIZE(large_src) + 1;
47696fce387SKees Cook
47796fce387SKees Cook init_large(test);
47896fce387SKees Cook
47996fce387SKees Cook /* Copy a growing number of overlapping bytes ... */
48096fce387SKees Cook for (int bytes = bytes_start; bytes < bytes_end;
48196fce387SKees Cook bytes = next_step(bytes, bytes_start, bytes_end, bytes_step)) {
48296fce387SKees Cook
48396fce387SKees Cook /* Over a shifting destination window ... */
48496fce387SKees Cook for (int d_off = 0; d_off < offset_max; d_off++) {
48596fce387SKees Cook int s_start = max(d_off - bytes, 0);
48696fce387SKees Cook int s_end = min_t(int, d_off + bytes, ARRAY_SIZE(large_src));
48796fce387SKees Cook
48896fce387SKees Cook /* Over a shifting source window ... */
48996fce387SKees Cook for (int s_off = s_start; s_off < s_end;
49096fce387SKees Cook s_off = next_step(s_off, s_start, s_end, window_step))
49196fce387SKees Cook inner_loop(test, bytes, d_off, s_off);
49296fce387SKees Cook
49396fce387SKees Cook /* Avoid stall warnings. */
49496fce387SKees Cook cond_resched();
49596fce387SKees Cook }
49696fce387SKees Cook }
49796fce387SKees Cook }
49896fce387SKees Cook
strtomem_test(struct kunit * test)499dfbafa70SKees Cook static void strtomem_test(struct kunit *test)
500dfbafa70SKees Cook {
50166cb2a36SKees Cook static const char input[sizeof(unsigned long)] = "hi";
502dfbafa70SKees Cook static const char truncate[] = "this is too long";
503dfbafa70SKees Cook struct {
504dfbafa70SKees Cook unsigned long canary1;
505dfbafa70SKees Cook unsigned char output[sizeof(unsigned long)] __nonstring;
506dfbafa70SKees Cook unsigned long canary2;
507dfbafa70SKees Cook } wrap;
508dfbafa70SKees Cook
509dfbafa70SKees Cook memset(&wrap, 0xFF, sizeof(wrap));
510dfbafa70SKees Cook KUNIT_EXPECT_EQ_MSG(test, wrap.canary1, ULONG_MAX,
511dfbafa70SKees Cook "bad initial canary value");
512dfbafa70SKees Cook KUNIT_EXPECT_EQ_MSG(test, wrap.canary2, ULONG_MAX,
513dfbafa70SKees Cook "bad initial canary value");
514dfbafa70SKees Cook
515dfbafa70SKees Cook /* Check unpadded copy leaves surroundings untouched. */
516dfbafa70SKees Cook strtomem(wrap.output, input);
517dfbafa70SKees Cook KUNIT_EXPECT_EQ(test, wrap.canary1, ULONG_MAX);
518dfbafa70SKees Cook KUNIT_EXPECT_EQ(test, wrap.output[0], input[0]);
519dfbafa70SKees Cook KUNIT_EXPECT_EQ(test, wrap.output[1], input[1]);
520dfbafa70SKees Cook for (size_t i = 2; i < sizeof(wrap.output); i++)
521dfbafa70SKees Cook KUNIT_EXPECT_EQ(test, wrap.output[i], 0xFF);
522dfbafa70SKees Cook KUNIT_EXPECT_EQ(test, wrap.canary2, ULONG_MAX);
523dfbafa70SKees Cook
524dfbafa70SKees Cook /* Check truncated copy leaves surroundings untouched. */
525dfbafa70SKees Cook memset(&wrap, 0xFF, sizeof(wrap));
526dfbafa70SKees Cook strtomem(wrap.output, truncate);
527dfbafa70SKees Cook KUNIT_EXPECT_EQ(test, wrap.canary1, ULONG_MAX);
528dfbafa70SKees Cook for (size_t i = 0; i < sizeof(wrap.output); i++)
529dfbafa70SKees Cook KUNIT_EXPECT_EQ(test, wrap.output[i], truncate[i]);
530dfbafa70SKees Cook KUNIT_EXPECT_EQ(test, wrap.canary2, ULONG_MAX);
531dfbafa70SKees Cook
532dfbafa70SKees Cook /* Check padded copy leaves only string padded. */
533dfbafa70SKees Cook memset(&wrap, 0xFF, sizeof(wrap));
534dfbafa70SKees Cook strtomem_pad(wrap.output, input, 0xAA);
535dfbafa70SKees Cook KUNIT_EXPECT_EQ(test, wrap.canary1, ULONG_MAX);
536dfbafa70SKees Cook KUNIT_EXPECT_EQ(test, wrap.output[0], input[0]);
537dfbafa70SKees Cook KUNIT_EXPECT_EQ(test, wrap.output[1], input[1]);
538dfbafa70SKees Cook for (size_t i = 2; i < sizeof(wrap.output); i++)
539dfbafa70SKees Cook KUNIT_EXPECT_EQ(test, wrap.output[i], 0xAA);
540dfbafa70SKees Cook KUNIT_EXPECT_EQ(test, wrap.canary2, ULONG_MAX);
541dfbafa70SKees Cook
542dfbafa70SKees Cook /* Check truncated padded copy has no padding. */
543dfbafa70SKees Cook memset(&wrap, 0xFF, sizeof(wrap));
544dfbafa70SKees Cook strtomem(wrap.output, truncate);
545dfbafa70SKees Cook KUNIT_EXPECT_EQ(test, wrap.canary1, ULONG_MAX);
546dfbafa70SKees Cook for (size_t i = 0; i < sizeof(wrap.output); i++)
547dfbafa70SKees Cook KUNIT_EXPECT_EQ(test, wrap.output[i], truncate[i]);
548dfbafa70SKees Cook KUNIT_EXPECT_EQ(test, wrap.canary2, ULONG_MAX);
549dfbafa70SKees Cook }
550dfbafa70SKees Cook
551bb95ebbeSKees Cook static struct kunit_case memcpy_test_cases[] = {
552bb95ebbeSKees Cook KUNIT_CASE(memset_test),
553bb95ebbeSKees Cook KUNIT_CASE(memcpy_test),
554d055c6a2SRae Moar KUNIT_CASE_SLOW(memcpy_large_test),
555d055c6a2SRae Moar KUNIT_CASE_SLOW(memmove_test),
556d055c6a2SRae Moar KUNIT_CASE_SLOW(memmove_large_test),
557d055c6a2SRae Moar KUNIT_CASE_SLOW(memmove_overlap_test),
558dfbafa70SKees Cook KUNIT_CASE(strtomem_test),
559bb95ebbeSKees Cook {}
560bb95ebbeSKees Cook };
561bb95ebbeSKees Cook
562bb95ebbeSKees Cook static struct kunit_suite memcpy_test_suite = {
563bb95ebbeSKees Cook .name = "memcpy",
564bb95ebbeSKees Cook .test_cases = memcpy_test_cases,
565bb95ebbeSKees Cook };
566bb95ebbeSKees Cook
567bb95ebbeSKees Cook kunit_test_suite(memcpy_test_suite);
568bb95ebbeSKees Cook
569bb95ebbeSKees Cook MODULE_LICENSE("GPL");
570