test-memmove.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480
  1. /* Test and measure memmove functions.
  2. Copyright (C) 1999-2026 Free Software Foundation, Inc.
  3. This file is part of the GNU C Library.
  4. The GNU C Library is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU Lesser General Public
  6. License as published by the Free Software Foundation; either
  7. version 2.1 of the License, or (at your option) any later version.
  8. The GNU C Library is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  11. Lesser General Public License for more details.
  12. You should have received a copy of the GNU Lesser General Public
  13. License along with the GNU C Library; if not, see
  14. <https://www.gnu.org/licenses/>. */
  15. #define TEST_MAIN
  16. #ifdef TEST_BCOPY
  17. # define TEST_NAME "bcopy"
  18. #else
  19. # define TEST_NAME "memmove"
  20. #endif
  21. #include "test-string.h"
  22. #include <support/test-driver.h>
  23. char *simple_memmove (char *, const char *, size_t);
  24. #ifdef TEST_BCOPY
  25. typedef void (*proto_t) (const char *, char *, size_t);
  26. IMPL (bcopy, 1)
  27. /* Naive implementation to verify results. */
  28. void
  29. simple_bcopy (const char *src, char *dst, size_t n)
  30. {
  31. simple_memmove (dst, src, n);
  32. }
  33. #else
  34. typedef char *(*proto_t) (char *, const char *, size_t);
  35. IMPL (memmove, 1)
  36. #endif
  37. /* Naive implementation to verify results. */
  38. char *
  39. test_cc_inhibit_loop_to_libcall
  40. simple_memmove (char *dst, const char *src, size_t n)
  41. {
  42. char *ret = dst;
  43. if (src < dst)
  44. {
  45. dst += n;
  46. src += n;
  47. while (n--)
  48. *--dst = *--src;
  49. }
  50. else
  51. while (n--)
  52. *dst++ = *src++;
  53. return ret;
  54. }
  55. static void
  56. do_one_test (impl_t *impl, char *dst, char *src, const char *orig_src,
  57. size_t len)
  58. {
  59. /* This also clears the destination buffer set by the previous run. */
  60. memcpy (src, orig_src, len);
  61. #ifdef TEST_BCOPY
  62. CALL (impl, src, dst, len);
  63. #else
  64. char *res;
  65. res = CALL (impl, dst, src, len);
  66. if (res != dst)
  67. {
  68. error (0, 0, "Wrong result in function %s %p %p", impl->name,
  69. res, dst);
  70. ret = 1;
  71. return;
  72. }
  73. #endif
  74. if (memcmp (dst, orig_src, len) != 0)
  75. {
  76. error (0, 0, "Wrong result in function %s dst \"%s\" src \"%s\"",
  77. impl->name, dst, src);
  78. ret = 1;
  79. return;
  80. }
  81. }
  82. static void
  83. do_test (size_t align1, size_t align2, size_t len)
  84. {
  85. size_t i, j;
  86. char *s1, *s2;
  87. align1 &= (getpagesize() - 1);
  88. if (align1 + len >= page_size)
  89. return;
  90. align2 &= (getpagesize() - 1);
  91. if (align2 + len >= page_size)
  92. return;
  93. s1 = (char *) (buf1 + align1);
  94. s2 = (char *) (buf2 + align2);
  95. for (i = 0, j = 1; i < len; i++, j += 23)
  96. s1[i] = j;
  97. FOR_EACH_IMPL (impl, 0)
  98. do_one_test (impl, s2, (char *) (buf2 + align1), s1, len);
  99. }
  100. static void
  101. do_random_tests (void)
  102. {
  103. size_t i, n, align1, align2, len, size;
  104. size_t srcstart, srcend, dststart, dstend;
  105. int c;
  106. unsigned char *p1, *p2;
  107. #ifndef TEST_BCOPY
  108. unsigned char *res;
  109. #endif
  110. for (n = 0; n < ITERATIONS; n++)
  111. {
  112. if ((random () & 255) == 0)
  113. size = 65536;
  114. else
  115. size = 512;
  116. if (size > page_size)
  117. size = page_size;
  118. if ((random () & 3) == 0)
  119. {
  120. len = random () & (size - 1);
  121. align1 = size - len - (random () & 31);
  122. align2 = size - len - (random () & 31);
  123. if (align1 > size)
  124. align1 = 0;
  125. if (align2 > size)
  126. align2 = 0;
  127. }
  128. else
  129. {
  130. align1 = random () & (size / 2 - 1);
  131. align2 = random () & (size / 2 - 1);
  132. len = random () & (size - 1);
  133. if (align1 + len > size)
  134. align1 = size - len;
  135. if (align2 + len > size)
  136. align2 = size - len;
  137. }
  138. p1 = buf1 + page_size - size;
  139. p2 = buf2 + page_size - size;
  140. c = random () & 255;
  141. srcend = align1 + len + 256;
  142. if (srcend > size)
  143. srcend = size;
  144. if (align1 > 256)
  145. srcstart = align1 - 256;
  146. else
  147. srcstart = 0;
  148. for (i = srcstart; i < srcend; ++i)
  149. p1[i] = random () & 255;
  150. dstend = align2 + len + 256;
  151. if (dstend > size)
  152. dstend = size;
  153. if (align2 > 256)
  154. dststart = align2 - 256;
  155. else
  156. dststart = 0;
  157. FOR_EACH_IMPL (impl, 1)
  158. {
  159. memset (p2 + dststart, c, dstend - dststart);
  160. memcpy (p2 + srcstart, p1 + srcstart, srcend - srcstart);
  161. #ifdef TEST_BCOPY
  162. CALL (impl, (char *) (p2 + align1), (char *) (p2 + align2), len);
  163. #else
  164. res = (unsigned char *) CALL (impl,
  165. (char *) (p2 + align2),
  166. (char *) (p2 + align1), len);
  167. if (res != p2 + align2)
  168. {
  169. error (0, 0, "Iteration %zd - wrong result in function %s (%zd, %zd, %zd) %p != %p",
  170. n, impl->name, align1, align2, len, res, p2 + align2);
  171. ret = 1;
  172. }
  173. #endif
  174. if (memcmp (p1 + align1, p2 + align2, len))
  175. {
  176. error (0, 0, "Iteration %zd - different strings, %s (%zd, %zd, %zd)",
  177. n, impl->name, align1, align2, len);
  178. ret = 1;
  179. }
  180. for (i = dststart; i < dstend; ++i)
  181. {
  182. if (i >= align2 && i < align2 + len)
  183. {
  184. i = align2 + len - 1;
  185. continue;
  186. }
  187. if (i >= srcstart && i < srcend)
  188. {
  189. i = srcend - 1;
  190. continue;
  191. }
  192. if (p2[i] != c)
  193. {
  194. error (0, 0, "Iteration %zd - garbage in memset area, %s (%zd, %zd, %zd)",
  195. n, impl->name, align1, align2, len);
  196. ret = 1;
  197. break;
  198. }
  199. }
  200. if (srcstart < align2
  201. && memcmp (p2 + srcstart, p1 + srcstart,
  202. (srcend > align2 ? align2 : srcend) - srcstart))
  203. {
  204. error (0, 0, "Iteration %zd - garbage before dst, %s (%zd, %zd, %zd)",
  205. n, impl->name, align1, align2, len);
  206. ret = 1;
  207. break;
  208. }
  209. i = srcstart > align2 + len ? srcstart : align2 + len;
  210. if (srcend > align2 + len
  211. && memcmp (p2 + i, p1 + i, srcend - i))
  212. {
  213. error (0, 0, "Iteration %zd - garbage after dst, %s (%zd, %zd, %zd)",
  214. n, impl->name, align1, align2, len);
  215. ret = 1;
  216. break;
  217. }
  218. }
  219. }
  220. }
  221. static void
  222. do_test2 (size_t offset)
  223. {
  224. size_t size = 0x20000000;
  225. uint32_t * large_buf;
  226. large_buf = mmap ((void*) 0x70000000, size, PROT_READ | PROT_WRITE,
  227. MAP_PRIVATE | MAP_ANON, -1, 0);
  228. if (large_buf == MAP_FAILED)
  229. error (EXIT_UNSUPPORTED, errno, "Large mmap failed");
  230. if ((uintptr_t) large_buf > 0x80000000 - 128
  231. || 0x80000000 - (uintptr_t) large_buf > 0x20000000)
  232. {
  233. error (0, 0, "Large mmap allocated improperly");
  234. ret = EXIT_UNSUPPORTED;
  235. munmap ((void *) large_buf, size);
  236. return;
  237. }
  238. size_t bytes_move = 0x80000000 - (uintptr_t) large_buf;
  239. if (bytes_move + offset * sizeof (uint32_t) > size)
  240. {
  241. munmap ((void *) large_buf, size);
  242. return;
  243. }
  244. size_t arr_size = bytes_move / sizeof (uint32_t);
  245. size_t i;
  246. size_t repeats;
  247. uint32_t * src = large_buf;
  248. uint32_t * dst = &large_buf[offset];
  249. for (repeats = 0; repeats < 2; ++repeats)
  250. {
  251. FOR_EACH_IMPL (impl, 0)
  252. {
  253. for (i = 0; i < arr_size; i++)
  254. src[i] = (uint32_t) i;
  255. #ifdef TEST_BCOPY
  256. CALL (impl, (char *) src, (char *) dst, bytes_move);
  257. #else
  258. CALL (impl, (char *) dst, (char *) src, bytes_move);
  259. #endif
  260. for (i = 0; i < arr_size; i++)
  261. {
  262. if (dst[i] != (uint32_t) i)
  263. {
  264. error (0, 0,
  265. "Wrong result in function %s dst \"%p\" src \"%p\" offset \"%zd\"",
  266. impl->name, dst, src, i);
  267. ret = 1;
  268. munmap ((void *) large_buf, size);
  269. return;
  270. }
  271. }
  272. }
  273. src = dst;
  274. dst = large_buf;
  275. }
  276. munmap ((void *) large_buf, size);
  277. }
  278. static void
  279. do_test3 (size_t bytes_move, size_t offset)
  280. {
  281. size_t size = bytes_move * 3;
  282. uint32_t *buf;
  283. buf = mmap (NULL, size, PROT_READ | PROT_WRITE,
  284. MAP_PRIVATE | MAP_ANON, -1, 0);
  285. if (buf == MAP_FAILED)
  286. error (EXIT_UNSUPPORTED, errno, "mmap failed");
  287. size_t arr_size = bytes_move / sizeof (uint32_t);
  288. size_t i;
  289. FOR_EACH_IMPL (impl, 0)
  290. {
  291. for (i = 0; i < arr_size; i++)
  292. buf[i] = (uint32_t) i;
  293. uint32_t *dst = &buf[arr_size + offset];
  294. #ifdef TEST_BCOPY
  295. CALL (impl, (char *) buf, (char *) dst, bytes_move);
  296. #else
  297. CALL (impl, (char *) dst, (char *) buf, bytes_move);
  298. #endif
  299. for (i = 0; i < arr_size; i++)
  300. {
  301. if (dst[i] != (uint32_t) i)
  302. {
  303. error (0, 0,
  304. "Wrong result in function %s dst \"%p\" src \"%p\" offset \"%zd\"",
  305. impl->name, dst, buf, i);
  306. ret = 1;
  307. break;
  308. }
  309. }
  310. }
  311. munmap ((void *) buf, size);
  312. }
  313. static void
  314. do_test4 (size_t bytes_move, size_t offset1, size_t offset2)
  315. {
  316. size_t size, repeats, i;
  317. uint8_t *buf, *dst, *src;
  318. size = bytes_move + MAX(offset1, offset2);
  319. buf = mmap(NULL, size, PROT_READ | PROT_WRITE,
  320. MAP_PRIVATE | MAP_ANON, -1, 0);
  321. if (buf == MAP_FAILED)
  322. error (EXIT_UNSUPPORTED, errno, "mmap failed");
  323. dst = &buf[offset1];
  324. src = &buf[offset2];
  325. for (repeats = 0; repeats < 2; ++repeats)
  326. {
  327. FOR_EACH_IMPL (impl, 0)
  328. {
  329. for (i = 0; i < bytes_move; i++)
  330. src[i] = (uint8_t) i;
  331. #ifdef TEST_BCOPY
  332. CALL (impl, (char *) src, (char *) dst, bytes_move);
  333. #else
  334. CALL (impl, (char *) dst, (char *) src, bytes_move);
  335. #endif
  336. for (i = 0; i < bytes_move; i++)
  337. {
  338. if (dst[i] != (uint8_t) i)
  339. {
  340. error (0, 0,
  341. "Wrong result in function %s dst \"%p\" src \"%p\" offset \"%zd\"",
  342. impl->name, dst, buf, i);
  343. ret = 1;
  344. break;
  345. }
  346. }
  347. }
  348. dst = &buf[offset2];
  349. src = &buf[offset1];
  350. }
  351. munmap ((void *) buf, size);
  352. }
  353. int
  354. test_main (void)
  355. {
  356. size_t i;
  357. test_init ();
  358. printf ("%23s", "");
  359. FOR_EACH_IMPL (impl, 0)
  360. printf ("\t%s", impl->name);
  361. putchar ('\n');
  362. for (i = 0; i < 14; ++i)
  363. {
  364. do_test (0, 32, 1 << i);
  365. do_test (32, 0, 1 << i);
  366. do_test (0, i, 1 << i);
  367. do_test (i, 0, 1 << i);
  368. }
  369. for (i = 0; i < 32; ++i)
  370. {
  371. do_test (0, 32, i);
  372. do_test (32, 0, i);
  373. do_test (0, i, i);
  374. do_test (i, 0, i);
  375. }
  376. for (i = 3; i < 32; ++i)
  377. {
  378. if ((i & (i - 1)) == 0)
  379. continue;
  380. do_test (0, 32, 16 * i);
  381. do_test (32, 0, 16 * i);
  382. do_test (0, i, 16 * i);
  383. do_test (i, 0, 16 * i);
  384. }
  385. do_random_tests ();
  386. do_test2 (0);
  387. do_test2 (33);
  388. do_test2 (0x200000 - 1);
  389. do_test2 (0x200000);
  390. do_test2 (0x200000 + 1);
  391. do_test2 (0x1000000 - 1);
  392. do_test2 (0x1000000);
  393. do_test2 (0x1000000 + 1);
  394. do_test2 (0x4000000 - 1);
  395. do_test2 (0x4000000);
  396. do_test2 (0x4000000 + 1);
  397. /* Copy 16KB data. */
  398. do_test3 (16384, 3);
  399. for (i = 4096; i <= 16384; i <<= 1)
  400. {
  401. do_test4 (i, 0, i);
  402. do_test4 (i, 0, i - 1);
  403. do_test4 (i, 0, i + 1);
  404. do_test4 (i, 63, i + 63);
  405. do_test4 (i, 63, i + 64);
  406. do_test4 (i, 63, i);
  407. do_test4 (i, 0, 1);
  408. do_test4 (i, 0, 15);
  409. do_test4 (i, 0, 31);
  410. do_test4 (i, 0, 63);
  411. do_test4 (i, 0, 64);
  412. do_test4 (i, 0, 65);
  413. do_test4 (i, 0, 127);
  414. do_test4 (i, 0, 129);
  415. }
  416. return ret;
  417. }
  418. #include <support/test-driver.c>