Skip to content

Commit 3635195

Browse files
committed
[libc] Improve testing of mem functions
This patch extracts the testing logic from `op_tests.cpp` into `memory_check_utils.h` so we can reuse it for mem* function integration tests. This makes testing consistent and thorough. For instance this catches a bug that got unnoticed during submission of D136595 and D135134. Integration test for memcmp was only testing a single size. This also leverages ASAN to make sure that data is not read / written outside permitted boundaries Differential Revision: https://reviews.llvm.org/D136865
1 parent be369ea commit 3635195

File tree

8 files changed

+310
-318
lines changed

8 files changed

+310
-318
lines changed

libc/test/src/string/bcmp_test.cpp

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
#include "memory_utils/memory_check_utils.h"
910
#include "src/string/bcmp.h"
1011
#include "utils/UnitTest/Test.h"
1112

13+
namespace __llvm_libc {
14+
1215
TEST(LlvmLibcBcmpTest, CmpZeroByte) {
1316
const char *lhs = "ab";
1417
const char *rhs = "bc";
@@ -33,26 +36,23 @@ TEST(LlvmLibcBcmpTest, LhsAfterRhsLexically) {
3336
ASSERT_NE(__llvm_libc::bcmp(lhs, rhs, 2), 0);
3437
}
3538

36-
TEST(LlvmLibcBcmpTest, Sweep) {
37-
static constexpr size_t K_MAX_SIZE = 1024;
38-
char lhs[K_MAX_SIZE];
39-
char rhs[K_MAX_SIZE];
40-
41-
const auto reset = [](char *const ptr) {
42-
for (size_t i = 0; i < K_MAX_SIZE; ++i)
43-
ptr[i] = 'a';
44-
};
45-
46-
reset(lhs);
47-
reset(rhs);
48-
for (size_t i = 0; i < K_MAX_SIZE; ++i)
49-
ASSERT_EQ(__llvm_libc::bcmp(lhs, rhs, i), 0);
50-
51-
reset(lhs);
52-
reset(rhs);
53-
for (size_t i = 0; i < K_MAX_SIZE; ++i) {
54-
rhs[i] = 'b';
55-
ASSERT_NE(__llvm_libc::bcmp(lhs, rhs, K_MAX_SIZE), 0);
56-
rhs[i] = 'a';
39+
// Adapt CheckBcmp signature to op implementation signatures.
40+
template <auto FnImpl>
41+
int CmpAdaptor(cpp::span<char> p1, cpp::span<char> p2, size_t size) {
42+
return FnImpl(p1.begin(), p2.begin(), size);
43+
}
44+
45+
TEST(LlvmLibcBcmpTest, SizeSweep) {
46+
static constexpr size_t kMaxSize = 1024;
47+
static constexpr auto Impl = CmpAdaptor<__llvm_libc::bcmp>;
48+
Buffer Buffer1(kMaxSize);
49+
Buffer Buffer2(kMaxSize);
50+
Randomize(Buffer1.span());
51+
for (size_t size = 0; size < kMaxSize; ++size) {
52+
auto span1 = Buffer1.span().subspan(0, size);
53+
auto span2 = Buffer2.span().subspan(0, size);
54+
ASSERT_TRUE((CheckBcmp<Impl>(span1, span2, size)));
5755
}
5856
}
57+
58+
} // namespace __llvm_libc

libc/test/src/string/bzero_test.cpp

Lines changed: 15 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,44 +6,27 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9-
#include "src/__support/CPP/span.h"
9+
#include "memory_utils/memory_check_utils.h"
1010
#include "src/string/bzero.h"
1111
#include "utils/UnitTest/Test.h"
1212

13-
using __llvm_libc::cpp::array;
14-
using __llvm_libc::cpp::span;
15-
using Data = array<char, 2048>;
13+
namespace __llvm_libc {
1614

17-
static const span<const char> k_deadcode("DEADC0DE", 8);
18-
19-
// Returns a Data object filled with a repetition of `filler`.
20-
Data get_data(span<const char> filler) {
21-
Data out;
22-
for (size_t i = 0; i < out.size(); ++i)
23-
out[i] = filler[i % filler.size()];
24-
return out;
15+
// Adapt CheckMemset signature to op implementation signatures.
16+
template <auto FnImpl>
17+
void BzeroAdaptor(cpp::span<char> p1, uint8_t value, size_t size) {
18+
assert(value == 0);
19+
FnImpl(p1.begin(), size);
2520
}
2621

27-
TEST(LlvmLibcBzeroTest, Thorough) {
28-
const Data dirty = get_data(k_deadcode);
29-
for (size_t count = 0; count < 1024; ++count) {
30-
for (size_t align = 0; align < 64; ++align) {
31-
auto buffer = dirty;
32-
char *const dst = &buffer[align];
33-
__llvm_libc::bzero(dst, count);
34-
// Everything before copy is untouched.
35-
for (size_t i = 0; i < align; ++i)
36-
ASSERT_EQ(buffer[i], dirty[i]);
37-
// Everything in between is copied.
38-
for (size_t i = 0; i < count; ++i)
39-
ASSERT_EQ(buffer[align + i], char(0));
40-
// Everything after copy is untouched.
41-
for (size_t i = align + count; i < dirty.size(); ++i)
42-
ASSERT_EQ(buffer[i], dirty[i]);
43-
}
22+
TEST(LlvmLibcBzeroTest, SizeSweep) {
23+
static constexpr size_t kMaxSize = 1024;
24+
static constexpr auto Impl = BzeroAdaptor<__llvm_libc::bzero>;
25+
Buffer DstBuffer(kMaxSize);
26+
for (size_t size = 0; size < kMaxSize; ++size) {
27+
auto dst = DstBuffer.span().subspan(0, size);
28+
ASSERT_TRUE((CheckMemset<Impl>(dst, 0, size)));
4429
}
4530
}
4631

47-
// FIXME: Add tests with reads and writes on the boundary of a read/write
48-
// protected page to check we're not reading nor writing prior/past the allowed
49-
// regions.
32+
} // namespace __llvm_libc

libc/test/src/string/memcmp_test.cpp

Lines changed: 21 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,12 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9+
#include "memory_utils/memory_check_utils.h"
910
#include "src/string/memcmp.h"
1011
#include "utils/UnitTest/Test.h"
1112

13+
namespace __llvm_libc {
14+
1215
TEST(LlvmLibcMemcmpTest, CmpZeroByte) {
1316
const char *lhs = "ab";
1417
const char *rhs = "yz";
@@ -33,26 +36,23 @@ TEST(LlvmLibcMemcmpTest, LhsAfterRhsLexically) {
3336
EXPECT_GT(__llvm_libc::memcmp(lhs, rhs, 2), 0);
3437
}
3538

36-
TEST(LlvmLibcMemcmpTest, Sweep) {
37-
static constexpr size_t K_MAX_SIZE = 1024;
38-
char lhs[K_MAX_SIZE];
39-
char rhs[K_MAX_SIZE];
40-
41-
const auto reset = [](char *const ptr) {
42-
for (size_t i = 0; i < K_MAX_SIZE; ++i)
43-
ptr[i] = 'a';
44-
};
45-
46-
reset(lhs);
47-
reset(rhs);
48-
for (size_t i = 0; i < K_MAX_SIZE; ++i)
49-
ASSERT_EQ(__llvm_libc::memcmp(lhs, rhs, i), 0);
50-
51-
reset(lhs);
52-
reset(rhs);
53-
for (size_t i = 0; i < K_MAX_SIZE; ++i) {
54-
rhs[i] = 'z';
55-
ASSERT_LT(__llvm_libc::memcmp(lhs, rhs, K_MAX_SIZE), 0);
56-
rhs[i] = 'a';
39+
// Adapt CheckMemcmp signature to op implementation signatures.
40+
template <auto FnImpl>
41+
int CmpAdaptor(cpp::span<char> p1, cpp::span<char> p2, size_t size) {
42+
return FnImpl(p1.begin(), p2.begin(), size);
43+
}
44+
45+
TEST(LlvmLibcMemcmpTest, SizeSweep) {
46+
static constexpr size_t kMaxSize = 1024;
47+
static constexpr auto Impl = CmpAdaptor<__llvm_libc::memcmp>;
48+
Buffer Buffer1(kMaxSize);
49+
Buffer Buffer2(kMaxSize);
50+
Randomize(Buffer1.span());
51+
for (size_t size = 0; size < kMaxSize; ++size) {
52+
auto span1 = Buffer1.span().subspan(0, size);
53+
auto span2 = Buffer2.span().subspan(0, size);
54+
ASSERT_TRUE((CheckMemcmp<Impl>(span1, span2, size)));
5755
}
5856
}
57+
58+
} // namespace __llvm_libc

libc/test/src/string/memcpy_test.cpp

Lines changed: 17 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -6,49 +6,29 @@
66
//
77
//===----------------------------------------------------------------------===//
88

9-
#include "src/__support/CPP/span.h"
9+
#include "memory_utils/memory_check_utils.h"
1010
#include "src/string/memcpy.h"
1111
#include "utils/UnitTest/Test.h"
1212

13-
using __llvm_libc::cpp::array;
14-
using __llvm_libc::cpp::span;
15-
using Data = array<char, 2048>;
13+
namespace __llvm_libc {
1614

17-
static const span<const char> k_numbers("0123456789", 10);
18-
static const span<const char> k_deadcode("DEADC0DE", 8);
19-
20-
// Returns a Data object filled with a repetition of `filler`.
21-
Data get_data(span<const char> filler) {
22-
Data out;
23-
for (size_t i = 0; i < out.size(); ++i)
24-
out[i] = filler[i % filler.size()];
25-
return out;
15+
// Adapt CheckMemcpy signature to op implementation signatures.
16+
template <auto FnImpl>
17+
void CopyAdaptor(cpp::span<char> dst, cpp::span<char> src, size_t size) {
18+
FnImpl(dst.begin(), src.begin(), size);
2619
}
2720

28-
TEST(LlvmLibcMemcpyTest, Thorough) {
29-
const Data groundtruth = get_data(k_numbers);
30-
const Data dirty = get_data(k_deadcode);
31-
for (size_t count = 0; count < 1024; ++count) {
32-
for (size_t align = 0; align < 64; ++align) {
33-
auto buffer = dirty;
34-
const char *const src = groundtruth.data();
35-
void *const dst = &buffer[align];
36-
void *const ret = __llvm_libc::memcpy(dst, src, count);
37-
// Return value is `dst`.
38-
ASSERT_EQ(ret, dst);
39-
// Everything before copy is untouched.
40-
for (size_t i = 0; i < align; ++i)
41-
ASSERT_EQ(buffer[i], dirty[i]);
42-
// Everything in between is copied.
43-
for (size_t i = 0; i < count; ++i)
44-
ASSERT_EQ(buffer[align + i], groundtruth[i]);
45-
// Everything after copy is untouched.
46-
for (size_t i = align + count; i < dirty.size(); ++i)
47-
ASSERT_EQ(buffer[i], dirty[i]);
48-
}
21+
TEST(LlvmLibcMemcpyTest, SizeSweep) {
22+
static constexpr size_t kMaxSize = 1024;
23+
static constexpr auto Impl = CopyAdaptor<__llvm_libc::memcpy>;
24+
Buffer SrcBuffer(kMaxSize);
25+
Buffer DstBuffer(kMaxSize);
26+
Randomize(SrcBuffer.span());
27+
for (size_t size = 0; size < kMaxSize; ++size) {
28+
auto src = SrcBuffer.span().subspan(0, size);
29+
auto dst = DstBuffer.span().subspan(0, size);
30+
ASSERT_TRUE(CheckMemcpy<Impl>(dst, src, size));
4931
}
5032
}
5133

52-
// FIXME: Add tests with reads and writes on the boundary of a read/write
53-
// protected page to check we're not reading nor writing prior/past the allowed
54-
// regions.
34+
} // namespace __llvm_libc

libc/test/src/string/memmove_test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ void Randomize(span<char> Buffer) {
9090
current = GetRandomChar();
9191
}
9292

93-
TEST(LlvmLibcMemmoveTest, Thorough) {
93+
TEST(LlvmLibcMemmoveTest, SizeSweep) {
9494
using LargeBuffer = array<char, 3 * kMaxSize>;
9595
LargeBuffer GroundTruth;
9696
Randomize(GroundTruth);

0 commit comments

Comments
 (0)