1 //===-- Unittests for memcpy ----------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "memory_utils/memory_check_utils.h"
10 #include "src/__support/macros/config.h"
11 #include "src/__support/macros/properties/os.h" // LIBC_TARGET_OS_IS_LINUX
12 #include "src/string/memcpy.h"
13 #include "test/UnitTest/Test.h"
15 #if !defined(LIBC_FULL_BUILD) && defined(LIBC_TARGET_OS_IS_LINUX)
16 #include "memory_utils/protected_pages.h"
17 #endif // !defined(LIBC_FULL_BUILD) && defined(LIBC_TARGET_OS_IS_LINUX)
19 namespace LIBC_NAMESPACE_DECL
{
21 // Adapt CheckMemcpy signature to memcpy.
22 static inline void Adaptor(cpp::span
<char> dst
, cpp::span
<char> src
,
24 LIBC_NAMESPACE::memcpy(dst
.begin(), src
.begin(), size
);
27 TEST(LlvmLibcMemcpyTest
, SizeSweep
) {
28 static constexpr size_t kMaxSize
= 400;
29 Buffer
SrcBuffer(kMaxSize
);
30 Buffer
DstBuffer(kMaxSize
);
31 Randomize(SrcBuffer
.span());
32 for (size_t size
= 0; size
< kMaxSize
; ++size
) {
33 auto src
= SrcBuffer
.span().subspan(0, size
);
34 auto dst
= DstBuffer
.span().subspan(0, size
);
35 ASSERT_TRUE(CheckMemcpy
<Adaptor
>(dst
, src
, size
));
39 #if !defined(LIBC_FULL_BUILD) && defined(LIBC_TARGET_OS_IS_LINUX)
41 TEST(LlvmLibcMemcpyTest
, CheckAccess
) {
42 static constexpr size_t MAX_SIZE
= 1024;
43 LIBC_ASSERT(MAX_SIZE
< GetPageSize());
45 const Page write_buffer
= pages
.GetPageA().WithAccess(PROT_WRITE
);
46 const Page read_buffer
= [&]() {
47 // We fetch page B in write mode.
48 auto page
= pages
.GetPageB().WithAccess(PROT_WRITE
);
49 // And fill it with random numbers.
50 for (size_t i
= 0; i
< page
.page_size
; ++i
)
51 page
.page_ptr
[i
] = rand();
52 // Then return it in read mode.
53 return page
.WithAccess(PROT_READ
);
55 for (size_t size
= 0; size
< MAX_SIZE
; ++size
) {
56 // We cross-check the function with two sources and two destinations.
57 // - The first of them (bottom) is always page aligned and faults when
58 // accessing bytes before it.
59 // - The second one (top) is not necessarily aligned and faults when
60 // accessing bytes after it.
61 const uint8_t *sources
[2] = {read_buffer
.bottom(size
),
62 read_buffer
.top(size
)};
63 uint8_t *destinations
[2] = {write_buffer
.bottom(size
),
64 write_buffer
.top(size
)};
65 for (const uint8_t *src
: sources
) {
66 for (uint8_t *dst
: destinations
) {
67 LIBC_NAMESPACE::memcpy(dst
, src
, size
);
73 #endif // !defined(LIBC_FULL_BUILD) && defined(LIBC_TARGET_OS_IS_LINUX)
75 } // namespace LIBC_NAMESPACE_DECL