1 //===-- Unittests for memmove ---------------------------------------------===//
2 //
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
6 //
7 //===----------------------------------------------------------------------===//
8
9 #include "src/__support/macros/config.h"
10 #include "src/string/memmove.h"
11
12 #include "memory_utils/memory_check_utils.h"
13 #include "src/__support/CPP/span.h"
14 #include "test/UnitTest/MemoryMatcher.h"
15 #include "test/UnitTest/Test.h"
16
17 using LIBC_NAMESPACE::cpp::array;
18 using LIBC_NAMESPACE::cpp::span;
19
20 namespace LIBC_NAMESPACE_DECL {
21
TEST(LlvmLibcMemmoveTest,MoveZeroByte)22 TEST(LlvmLibcMemmoveTest, MoveZeroByte) {
23 char Buffer[] = {'a', 'b', 'y', 'z'};
24 const char Expected[] = {'a', 'b', 'y', 'z'};
25 void *const Dst = Buffer;
26 void *const Ret = LIBC_NAMESPACE::memmove(Dst, Buffer + 2, 0);
27 EXPECT_EQ(Ret, Dst);
28 ASSERT_MEM_EQ(Buffer, testing::MemoryView(Expected));
29 }
30
TEST(LlvmLibcMemmoveTest,DstAndSrcPointToSameAddress)31 TEST(LlvmLibcMemmoveTest, DstAndSrcPointToSameAddress) {
32 char Buffer[] = {'a', 'b'};
33 const char Expected[] = {'a', 'b'};
34 void *const Dst = Buffer;
35 void *const Ret = LIBC_NAMESPACE::memmove(Dst, Buffer, 1);
36 EXPECT_EQ(Ret, Dst);
37 ASSERT_MEM_EQ(Buffer, testing::MemoryView(Expected));
38 }
39
TEST(LlvmLibcMemmoveTest,DstStartsBeforeSrc)40 TEST(LlvmLibcMemmoveTest, DstStartsBeforeSrc) {
41 // Set boundary at beginning and end for not overstepping when
42 // copy forward or backward.
43 char Buffer[] = {'z', 'a', 'b', 'c', 'z'};
44 const char Expected[] = {'z', 'b', 'c', 'c', 'z'};
45 void *const Dst = Buffer + 1;
46 void *const Ret = LIBC_NAMESPACE::memmove(Dst, Buffer + 2, 2);
47 EXPECT_EQ(Ret, Dst);
48 ASSERT_MEM_EQ(Buffer, testing::MemoryView(Expected));
49 }
50
TEST(LlvmLibcMemmoveTest,DstStartsAfterSrc)51 TEST(LlvmLibcMemmoveTest, DstStartsAfterSrc) {
52 char Buffer[] = {'z', 'a', 'b', 'c', 'z'};
53 const char Expected[] = {'z', 'a', 'a', 'b', 'z'};
54 void *const Dst = Buffer + 2;
55 void *const Ret = LIBC_NAMESPACE::memmove(Dst, Buffer + 1, 2);
56 EXPECT_EQ(Ret, Dst);
57 ASSERT_MEM_EQ(Buffer, testing::MemoryView(Expected));
58 }
59
60 // e.g. `Dst` follow `src`.
61 // str: [abcdefghij]
62 // [__src_____]
63 // [_____Dst__]
TEST(LlvmLibcMemmoveTest,SrcFollowDst)64 TEST(LlvmLibcMemmoveTest, SrcFollowDst) {
65 char Buffer[] = {'z', 'a', 'b', 'z'};
66 const char Expected[] = {'z', 'b', 'b', 'z'};
67 void *const Dst = Buffer + 1;
68 void *const Ret = LIBC_NAMESPACE::memmove(Dst, Buffer + 2, 1);
69 EXPECT_EQ(Ret, Dst);
70 ASSERT_MEM_EQ(Buffer, testing::MemoryView(Expected));
71 }
72
TEST(LlvmLibcMemmoveTest,DstFollowSrc)73 TEST(LlvmLibcMemmoveTest, DstFollowSrc) {
74 char Buffer[] = {'z', 'a', 'b', 'z'};
75 const char Expected[] = {'z', 'a', 'a', 'z'};
76 void *const Dst = Buffer + 2;
77 void *const Ret = LIBC_NAMESPACE::memmove(Dst, Buffer + 1, 1);
78 EXPECT_EQ(Ret, Dst);
79 ASSERT_MEM_EQ(Buffer, testing::MemoryView(Expected));
80 }
81
82 // Adapt CheckMemmove signature to op implementation signatures.
Adaptor(cpp::span<char> dst,cpp::span<char> src,size_t size)83 static inline void Adaptor(cpp::span<char> dst, cpp::span<char> src,
84 size_t size) {
85 LIBC_NAMESPACE::memmove(dst.begin(), src.begin(), size);
86 }
87
TEST(LlvmLibcMemmoveTest,SizeSweep)88 TEST(LlvmLibcMemmoveTest, SizeSweep) {
89 static constexpr int kMaxSize = 400;
90 static constexpr int kDenseOverlap = 15;
91 using LargeBuffer = array<char, 2 * kMaxSize + 1>;
92 LargeBuffer Buffer;
93 Randomize(Buffer);
94 for (int Size = 0; Size < kMaxSize; ++Size)
95 for (int Overlap = -1; Overlap < Size;) {
96 ASSERT_TRUE(CheckMemmove<Adaptor>(Buffer, Size, Overlap));
97 // Prevent quadratic behavior by skipping offset above kDenseOverlap.
98 if (Overlap > kDenseOverlap)
99 Overlap *= 2;
100 else
101 ++Overlap;
102 }
103 }
104
105 } // namespace LIBC_NAMESPACE_DECL
106