1 //===- llvm/unittest/Support/MemoryBufferTest.cpp - MemoryBuffer tests ----===//
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 // This file implements unit tests for the MemoryBuffer support class.
11 //===----------------------------------------------------------------------===//
13 #include "llvm/Support/MemoryBuffer.h"
14 #include "llvm/ADT/ScopeExit.h"
15 #include "llvm/Support/FileSystem.h"
16 #include "llvm/Support/FileUtilities.h"
17 #include "llvm/Support/raw_ostream.h"
18 #include "llvm/Testing/Support/Error.h"
19 #include "gtest/gtest.h"
20 #if LLVM_ENABLE_THREADS
32 #define ASSERT_NO_ERROR(x) \
33 if (std::error_code ASSERT_NO_ERROR_ec = x) { \
34 SmallString<128> MessageStorage; \
35 raw_svector_ostream Message(MessageStorage); \
36 Message << #x ": did not return errc::success.\n" \
37 << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n" \
38 << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n"; \
39 GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \
43 #define ASSERT_ERROR(x) \
45 SmallString<128> MessageStorage; \
46 raw_svector_ostream Message(MessageStorage); \
47 Message << #x ": did not return a failure error code.\n"; \
48 GTEST_FATAL_FAILURE_(MessageStorage.c_str()); \
53 class MemoryBufferTest
: public testing::Test
{
56 : data("this is some data")
59 void SetUp() override
{}
61 /// Common testing for different modes of getOpenFileSlice.
62 /// Creates a temporary file with known contents, and uses
63 /// MemoryBuffer::getOpenFileSlice to map it.
64 /// If \p Reopen is true, the file is closed after creating and reopened
65 /// anew before using MemoryBuffer.
66 void testGetOpenFileSlice(bool Reopen
);
68 typedef std::unique_ptr
<MemoryBuffer
> OwningBuffer
;
73 TEST_F(MemoryBufferTest
, get
) {
74 // Default name and null-terminator flag
75 OwningBuffer
MB1(MemoryBuffer::getMemBuffer(data
));
76 EXPECT_TRUE(nullptr != MB1
.get());
78 // RequiresNullTerminator = false
79 OwningBuffer
MB2(MemoryBuffer::getMemBuffer(data
, "one", false));
80 EXPECT_TRUE(nullptr != MB2
.get());
82 // RequiresNullTerminator = true
83 OwningBuffer
MB3(MemoryBuffer::getMemBuffer(data
, "two", true));
84 EXPECT_TRUE(nullptr != MB3
.get());
86 // verify all 3 buffers point to the same address
87 EXPECT_EQ(MB1
->getBufferStart(), MB2
->getBufferStart());
88 EXPECT_EQ(MB2
->getBufferStart(), MB3
->getBufferStart());
90 // verify the original data is unmodified after deleting the buffers
94 EXPECT_EQ("this is some data", data
);
97 TEST_F(MemoryBufferTest
, getOpenFile
) {
99 SmallString
<64> TestPath
;
100 ASSERT_EQ(sys::fs::createTemporaryFile("MemoryBufferTest_getOpenFile", "temp",
104 FileRemover
Cleanup(TestPath
);
105 raw_fd_ostream
OF(FD
, /*shouldClose*/ true);
110 Expected
<sys::fs::file_t
> File
= sys::fs::openNativeFileForRead(TestPath
);
111 ASSERT_THAT_EXPECTED(File
, Succeeded());
113 make_scope_exit([&] { ASSERT_NO_ERROR(sys::fs::closeFile(*File
)); });
114 ErrorOr
<OwningBuffer
> MB
= MemoryBuffer::getOpenFile(*File
, TestPath
, 6);
115 ASSERT_NO_ERROR(MB
.getError());
116 EXPECT_EQ("123456", MB
.get()->getBuffer());
119 Expected
<sys::fs::file_t
> File
= sys::fs::openNativeFileForWrite(
120 TestPath
, sys::fs::CD_OpenExisting
, sys::fs::OF_None
);
121 ASSERT_THAT_EXPECTED(File
, Succeeded());
123 make_scope_exit([&] { ASSERT_NO_ERROR(sys::fs::closeFile(*File
)); });
124 ASSERT_ERROR(MemoryBuffer::getOpenFile(*File
, TestPath
, 6).getError());
128 TEST_F(MemoryBufferTest
, NullTerminator4K
) {
129 // Test that a file with size that is a multiple of the page size can be null
130 // terminated correctly by MemoryBuffer.
132 SmallString
<64> TestPath
;
133 sys::fs::createTemporaryFile("MemoryBufferTest_NullTerminator4K", "temp",
135 FileRemover
Cleanup(TestPath
);
136 raw_fd_ostream
OF(TestFD
, true, /*unbuffered=*/true);
137 for (unsigned i
= 0; i
< 4096 / 16; ++i
) {
138 OF
<< "0123456789abcdef";
142 ErrorOr
<OwningBuffer
> MB
= MemoryBuffer::getFile(TestPath
.c_str());
143 std::error_code EC
= MB
.getError();
146 const char *BufData
= MB
.get()->getBufferStart();
147 EXPECT_EQ('f', BufData
[4095]);
148 EXPECT_EQ('\0', BufData
[4096]);
151 TEST_F(MemoryBufferTest
, copy
) {
153 OwningBuffer
MBC1(MemoryBuffer::getMemBufferCopy(data
));
154 EXPECT_TRUE(nullptr != MBC1
.get());
157 OwningBuffer
MBC2(MemoryBuffer::getMemBufferCopy(data
, "copy"));
158 EXPECT_TRUE(nullptr != MBC2
.get());
160 // verify the two copies do not point to the same place
161 EXPECT_NE(MBC1
->getBufferStart(), MBC2
->getBufferStart());
164 #if LLVM_ENABLE_THREADS
165 TEST_F(MemoryBufferTest
, createFromPipe
) {
166 sys::fs::file_t pipes
[2];
168 ASSERT_EQ(::pipe(pipes
), 0) << strerror(errno
);
170 ASSERT_TRUE(::CreatePipe(&pipes
[0], &pipes
[1], nullptr, 0))
173 auto ReadCloser
= make_scope_exit([&] { sys::fs::closeFile(pipes
[0]); });
174 std::thread
Writer([&] {
175 auto WriteCloser
= make_scope_exit([&] { sys::fs::closeFile(pipes
[1]); });
176 for (unsigned i
= 0; i
< 5; ++i
) {
177 std::this_thread::sleep_for(std::chrono::milliseconds(10));
179 ASSERT_EQ(::write(pipes
[1], "foo", 3), 3) << strerror(errno
);
182 ASSERT_TRUE(::WriteFile(pipes
[1], "foo", 3, &Written
, nullptr))
184 ASSERT_EQ(Written
, 3u);
188 ErrorOr
<OwningBuffer
> MB
=
189 MemoryBuffer::getOpenFile(pipes
[0], "pipe", /*FileSize*/ -1);
191 ASSERT_NO_ERROR(MB
.getError());
192 EXPECT_EQ(MB
.get()->getBuffer(), "foofoofoofoofoo");
196 TEST_F(MemoryBufferTest
, make_new
) {
198 OwningBuffer
Zero(WritableMemoryBuffer::getNewUninitMemBuffer(0));
199 EXPECT_TRUE(nullptr != Zero
.get());
201 // uninitialized buffer with no name
202 OwningBuffer
One(WritableMemoryBuffer::getNewUninitMemBuffer(321));
203 EXPECT_TRUE(nullptr != One
.get());
205 // uninitialized buffer with name
206 OwningBuffer
Two(WritableMemoryBuffer::getNewUninitMemBuffer(123, "bla"));
207 EXPECT_TRUE(nullptr != Two
.get());
209 // 0-initialized buffer with no name
210 OwningBuffer
Three(WritableMemoryBuffer::getNewMemBuffer(321, data
));
211 EXPECT_TRUE(nullptr != Three
.get());
212 for (size_t i
= 0; i
< 321; ++i
)
213 EXPECT_EQ(0, Three
->getBufferStart()[0]);
215 // 0-initialized buffer with name
216 OwningBuffer
Four(WritableMemoryBuffer::getNewMemBuffer(123, "zeros"));
217 EXPECT_TRUE(nullptr != Four
.get());
218 for (size_t i
= 0; i
< 123; ++i
)
219 EXPECT_EQ(0, Four
->getBufferStart()[0]);
222 void MemoryBufferTest::testGetOpenFileSlice(bool Reopen
) {
223 // Test that MemoryBuffer::getOpenFile works properly when no null
224 // terminator is requested and the size is large enough to trigger
225 // the usage of memory mapping.
227 SmallString
<64> TestPath
;
228 // Create a temporary file and write data into it.
229 sys::fs::createTemporaryFile("prefix", "temp", TestFD
, TestPath
);
230 FileRemover
Cleanup(TestPath
);
231 // OF is responsible for closing the file; If the file is not
232 // reopened, it will be unbuffered so that the results are
233 // immediately visible through the fd.
234 raw_fd_ostream
OF(TestFD
, true, !Reopen
);
235 for (int i
= 0; i
< 60000; ++i
) {
241 EXPECT_FALSE(sys::fs::openFileForRead(TestPath
.c_str(), TestFD
));
244 ErrorOr
<OwningBuffer
> Buf
= MemoryBuffer::getOpenFileSlice(
245 sys::fs::convertFDToNativeFile(TestFD
), TestPath
.c_str(),
250 std::error_code EC
= Buf
.getError();
253 StringRef BufData
= Buf
.get()->getBuffer();
254 EXPECT_EQ(BufData
.size(), 40000U);
255 EXPECT_EQ(BufData
[0], '0');
256 EXPECT_EQ(BufData
[9], '9');
259 TEST_F(MemoryBufferTest
, getOpenFileNoReopen
) {
260 testGetOpenFileSlice(false);
263 TEST_F(MemoryBufferTest
, getOpenFileReopened
) {
264 testGetOpenFileSlice(true);
267 TEST_F(MemoryBufferTest
, reference
) {
268 OwningBuffer
MB(MemoryBuffer::getMemBuffer(data
));
269 MemoryBufferRef
MBR(*MB
);
271 EXPECT_EQ(MB
->getBufferStart(), MBR
.getBufferStart());
272 EXPECT_EQ(MB
->getBufferIdentifier(), MBR
.getBufferIdentifier());
275 TEST_F(MemoryBufferTest
, slice
) {
276 // Create a file that is six pages long with different data on each page.
278 SmallString
<64> TestPath
;
279 sys::fs::createTemporaryFile("MemoryBufferTest_Slice", "temp", FD
, TestPath
);
280 FileRemover
Cleanup(TestPath
);
281 raw_fd_ostream
OF(FD
, true, /*unbuffered=*/true);
282 for (unsigned i
= 0; i
< 0x2000 / 8; ++i
) {
285 for (unsigned i
= 0; i
< 0x2000 / 8; ++i
) {
288 for (unsigned i
= 0; i
< 0x2000 / 8; ++i
) {
293 // Try offset of one page.
294 ErrorOr
<OwningBuffer
> MB
= MemoryBuffer::getFileSlice(TestPath
.str(),
296 std::error_code EC
= MB
.getError();
298 EXPECT_EQ(0x4000UL
, MB
.get()->getBufferSize());
300 StringRef BufData
= MB
.get()->getBuffer();
301 EXPECT_TRUE(BufData
.substr(0x0000,8).equals("12345678"));
302 EXPECT_TRUE(BufData
.substr(0x0FF8,8).equals("12345678"));
303 EXPECT_TRUE(BufData
.substr(0x1000,8).equals("abcdefgh"));
304 EXPECT_TRUE(BufData
.substr(0x2FF8,8).equals("abcdefgh"));
305 EXPECT_TRUE(BufData
.substr(0x3000,8).equals("ABCDEFGH"));
306 EXPECT_TRUE(BufData
.substr(0x3FF8,8).equals("ABCDEFGH"));
308 // Try non-page aligned.
309 ErrorOr
<OwningBuffer
> MB2
= MemoryBuffer::getFileSlice(TestPath
.str(),
313 EXPECT_EQ(0x3000UL
, MB2
.get()->getBufferSize());
315 StringRef BufData2
= MB2
.get()->getBuffer();
316 EXPECT_TRUE(BufData2
.substr(0x0000,8).equals("12345678"));
317 EXPECT_TRUE(BufData2
.substr(0x17F8,8).equals("12345678"));
318 EXPECT_TRUE(BufData2
.substr(0x1800,8).equals("abcdefgh"));
319 EXPECT_TRUE(BufData2
.substr(0x2FF8,8).equals("abcdefgh"));
322 TEST_F(MemoryBufferTest
, writableSlice
) {
323 // Create a file initialized with some data
325 SmallString
<64> TestPath
;
326 sys::fs::createTemporaryFile("MemoryBufferTest_WritableSlice", "temp", FD
,
328 FileRemover
Cleanup(TestPath
);
329 raw_fd_ostream
OF(FD
, true);
330 for (unsigned i
= 0; i
< 0x1000; ++i
)
331 OF
<< "0123456789abcdef";
336 WritableMemoryBuffer::getFileSlice(TestPath
.str(), 0x6000, 0x2000);
337 ASSERT_FALSE(MBOrError
.getError());
338 // Write some data. It should be mapped private, so that upon completion
339 // the original file contents are not modified.
340 WritableMemoryBuffer
&MB
= **MBOrError
;
341 ASSERT_EQ(0x6000u
, MB
.getBufferSize());
342 char *Start
= MB
.getBufferStart();
343 ASSERT_EQ(MB
.getBufferEnd(), MB
.getBufferStart() + MB
.getBufferSize());
344 ::memset(Start
, 'x', MB
.getBufferSize());
347 auto MBOrError
= MemoryBuffer::getFile(TestPath
);
348 ASSERT_FALSE(MBOrError
.getError());
349 auto &MB
= **MBOrError
;
350 ASSERT_EQ(0x10000u
, MB
.getBufferSize());
351 for (size_t i
= 0; i
< MB
.getBufferSize(); i
+= 0x10)
352 EXPECT_EQ("0123456789abcdef", MB
.getBuffer().substr(i
, 0x10)) << "i: " << i
;
355 TEST_F(MemoryBufferTest
, writeThroughFile
) {
356 // Create a file initialized with some data
358 SmallString
<64> TestPath
;
359 sys::fs::createTemporaryFile("MemoryBufferTest_WriteThrough", "temp", FD
,
361 FileRemover
Cleanup(TestPath
);
362 raw_fd_ostream
OF(FD
, true);
363 OF
<< "0123456789abcdef";
366 auto MBOrError
= WriteThroughMemoryBuffer::getFile(TestPath
);
367 ASSERT_FALSE(MBOrError
.getError());
368 // Write some data. It should be mapped readwrite, so that upon completion
369 // the original file contents are modified.
370 WriteThroughMemoryBuffer
&MB
= **MBOrError
;
371 ASSERT_EQ(16u, MB
.getBufferSize());
372 char *Start
= MB
.getBufferStart();
373 ASSERT_EQ(MB
.getBufferEnd(), MB
.getBufferStart() + MB
.getBufferSize());
374 ::memset(Start
, 'x', MB
.getBufferSize());
377 auto MBOrError
= MemoryBuffer::getFile(TestPath
);
378 ASSERT_FALSE(MBOrError
.getError());
379 auto &MB
= **MBOrError
;
380 ASSERT_EQ(16u, MB
.getBufferSize());
381 EXPECT_EQ("xxxxxxxxxxxxxxxx", MB
.getBuffer());