xref: /llvm-project/libc/test/src/string/memcpy_test.cpp (revision 5ff3ff33ff930e4ec49da7910612d8a41eb068cb)
16ca54e01SGuillaume Chatelet //===-- Unittests for memcpy ----------------------------------------------===//
204a309ddSGuillaume Chatelet //
304a309ddSGuillaume Chatelet // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
404a309ddSGuillaume Chatelet // See https://llvm.org/LICENSE.txt for license information.
504a309ddSGuillaume Chatelet // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
604a309ddSGuillaume Chatelet //
704a309ddSGuillaume Chatelet //===----------------------------------------------------------------------===//
804a309ddSGuillaume Chatelet 
93635195eSGuillaume Chatelet #include "memory_utils/memory_check_utils.h"
10*5ff3ff33SPetr Hosek #include "src/__support/macros/config.h"
11292b300cSGuillaume Chatelet #include "src/__support/macros/properties/os.h" // LIBC_TARGET_OS_IS_LINUX
126ca54e01SGuillaume Chatelet #include "src/string/memcpy.h"
13af1315c2SSiva Chandra Reddy #include "test/UnitTest/Test.h"
1404a309ddSGuillaume Chatelet 
15292b300cSGuillaume Chatelet #if !defined(LIBC_FULL_BUILD) && defined(LIBC_TARGET_OS_IS_LINUX)
16292b300cSGuillaume Chatelet #include "memory_utils/protected_pages.h"
17292b300cSGuillaume Chatelet #endif // !defined(LIBC_FULL_BUILD) && defined(LIBC_TARGET_OS_IS_LINUX)
18292b300cSGuillaume Chatelet 
19*5ff3ff33SPetr Hosek namespace LIBC_NAMESPACE_DECL {
2004a309ddSGuillaume Chatelet 
21298843cdSGuillaume Chatelet // Adapt CheckMemcpy signature to memcpy.
22298843cdSGuillaume Chatelet static inline void Adaptor(cpp::span<char> dst, cpp::span<char> src,
23298843cdSGuillaume Chatelet                            size_t size) {
24b6bc9d72SGuillaume Chatelet   LIBC_NAMESPACE::memcpy(dst.begin(), src.begin(), size);
2504a309ddSGuillaume Chatelet }
2604a309ddSGuillaume Chatelet 
273635195eSGuillaume Chatelet TEST(LlvmLibcMemcpyTest, SizeSweep) {
28298843cdSGuillaume Chatelet   static constexpr size_t kMaxSize = 400;
293635195eSGuillaume Chatelet   Buffer SrcBuffer(kMaxSize);
303635195eSGuillaume Chatelet   Buffer DstBuffer(kMaxSize);
313635195eSGuillaume Chatelet   Randomize(SrcBuffer.span());
323635195eSGuillaume Chatelet   for (size_t size = 0; size < kMaxSize; ++size) {
333635195eSGuillaume Chatelet     auto src = SrcBuffer.span().subspan(0, size);
343635195eSGuillaume Chatelet     auto dst = DstBuffer.span().subspan(0, size);
35298843cdSGuillaume Chatelet     ASSERT_TRUE(CheckMemcpy<Adaptor>(dst, src, size));
3604a309ddSGuillaume Chatelet   }
3704a309ddSGuillaume Chatelet }
3804a309ddSGuillaume Chatelet 
39292b300cSGuillaume Chatelet #if !defined(LIBC_FULL_BUILD) && defined(LIBC_TARGET_OS_IS_LINUX)
40292b300cSGuillaume Chatelet 
41292b300cSGuillaume Chatelet TEST(LlvmLibcMemcpyTest, CheckAccess) {
42292b300cSGuillaume Chatelet   static constexpr size_t MAX_SIZE = 1024;
43292b300cSGuillaume Chatelet   LIBC_ASSERT(MAX_SIZE < GetPageSize());
44292b300cSGuillaume Chatelet   ProtectedPages pages;
45292b300cSGuillaume Chatelet   const Page write_buffer = pages.GetPageA().WithAccess(PROT_WRITE);
46292b300cSGuillaume Chatelet   const Page read_buffer = [&]() {
47292b300cSGuillaume Chatelet     // We fetch page B in write mode.
48292b300cSGuillaume Chatelet     auto page = pages.GetPageB().WithAccess(PROT_WRITE);
49292b300cSGuillaume Chatelet     // And fill it with random numbers.
50292b300cSGuillaume Chatelet     for (size_t i = 0; i < page.page_size; ++i)
51292b300cSGuillaume Chatelet       page.page_ptr[i] = rand();
52292b300cSGuillaume Chatelet     // Then return it in read mode.
53292b300cSGuillaume Chatelet     return page.WithAccess(PROT_READ);
54292b300cSGuillaume Chatelet   }();
55292b300cSGuillaume Chatelet   for (size_t size = 0; size < MAX_SIZE; ++size) {
56292b300cSGuillaume Chatelet     // We cross-check the function with two sources and two destinations.
57292b300cSGuillaume Chatelet     //  - The first of them (bottom) is always page aligned and faults when
58292b300cSGuillaume Chatelet     //    accessing bytes before it.
59292b300cSGuillaume Chatelet     //  - The second one (top) is not necessarily aligned and faults when
60292b300cSGuillaume Chatelet     //    accessing bytes after it.
61292b300cSGuillaume Chatelet     const uint8_t *sources[2] = {read_buffer.bottom(size),
62292b300cSGuillaume Chatelet                                  read_buffer.top(size)};
63292b300cSGuillaume Chatelet     uint8_t *destinations[2] = {write_buffer.bottom(size),
64292b300cSGuillaume Chatelet                                 write_buffer.top(size)};
65292b300cSGuillaume Chatelet     for (const uint8_t *src : sources) {
66292b300cSGuillaume Chatelet       for (uint8_t *dst : destinations) {
67292b300cSGuillaume Chatelet         LIBC_NAMESPACE::memcpy(dst, src, size);
68292b300cSGuillaume Chatelet       }
69292b300cSGuillaume Chatelet     }
70292b300cSGuillaume Chatelet   }
71292b300cSGuillaume Chatelet }
72292b300cSGuillaume Chatelet 
73292b300cSGuillaume Chatelet #endif // !defined(LIBC_FULL_BUILD) && defined(LIBC_TARGET_OS_IS_LINUX)
74292b300cSGuillaume Chatelet 
75*5ff3ff33SPetr Hosek } // namespace LIBC_NAMESPACE_DECL
76