1 //===- llvm/unittest/Support/MemoryBufferTest.cpp - MemoryBuffer tests ----===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file implements unit tests for the MemoryBuffer support class.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/Support/MemoryBuffer.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"
25 class MemoryBufferTest
: public testing::Test
{
28 : data("this is some data")
31 void SetUp() override
{}
33 /// Common testing for different modes of getOpenFileSlice.
34 /// Creates a temporary file with known contents, and uses
35 /// MemoryBuffer::getOpenFileSlice to map it.
36 /// If \p Reopen is true, the file is closed after creating and reopened
37 /// anew before using MemoryBuffer.
38 void testGetOpenFileSlice(bool Reopen
);
40 typedef std::unique_ptr
<MemoryBuffer
> OwningBuffer
;
45 TEST_F(MemoryBufferTest
, get
) {
46 // Default name and null-terminator flag
47 OwningBuffer
MB1(MemoryBuffer::getMemBuffer(data
));
48 EXPECT_TRUE(nullptr != MB1
.get());
50 // RequiresNullTerminator = false
51 OwningBuffer
MB2(MemoryBuffer::getMemBuffer(data
, "one", false));
52 EXPECT_TRUE(nullptr != MB2
.get());
54 // RequiresNullTerminator = true
55 OwningBuffer
MB3(MemoryBuffer::getMemBuffer(data
, "two", true));
56 EXPECT_TRUE(nullptr != MB3
.get());
58 // verify all 3 buffers point to the same address
59 EXPECT_EQ(MB1
->getBufferStart(), MB2
->getBufferStart());
60 EXPECT_EQ(MB2
->getBufferStart(), MB3
->getBufferStart());
62 // verify the original data is unmodified after deleting the buffers
66 EXPECT_EQ("this is some data", data
);
69 TEST_F(MemoryBufferTest
, NullTerminator4K
) {
70 // Test that a file with size that is a multiple of the page size can be null
71 // terminated correctly by MemoryBuffer.
73 SmallString
<64> TestPath
;
74 sys::fs::createTemporaryFile("MemoryBufferTest_NullTerminator4K", "temp",
76 FileRemover
Cleanup(TestPath
);
77 raw_fd_ostream
OF(TestFD
, true, /*unbuffered=*/true);
78 for (unsigned i
= 0; i
< 4096 / 16; ++i
) {
79 OF
<< "0123456789abcdef";
83 ErrorOr
<OwningBuffer
> MB
= MemoryBuffer::getFile(TestPath
.c_str());
84 std::error_code EC
= MB
.getError();
87 const char *BufData
= MB
.get()->getBufferStart();
88 EXPECT_EQ('f', BufData
[4095]);
89 EXPECT_EQ('\0', BufData
[4096]);
92 TEST_F(MemoryBufferTest
, copy
) {
94 OwningBuffer
MBC1(MemoryBuffer::getMemBufferCopy(data
));
95 EXPECT_TRUE(nullptr != MBC1
.get());
98 OwningBuffer
MBC2(MemoryBuffer::getMemBufferCopy(data
, "copy"));
99 EXPECT_TRUE(nullptr != MBC2
.get());
101 // verify the two copies do not point to the same place
102 EXPECT_NE(MBC1
->getBufferStart(), MBC2
->getBufferStart());
105 TEST_F(MemoryBufferTest
, make_new
) {
107 OwningBuffer
Zero(WritableMemoryBuffer::getNewUninitMemBuffer(0));
108 EXPECT_TRUE(nullptr != Zero
.get());
110 // uninitialized buffer with no name
111 OwningBuffer
One(WritableMemoryBuffer::getNewUninitMemBuffer(321));
112 EXPECT_TRUE(nullptr != One
.get());
114 // uninitialized buffer with name
115 OwningBuffer
Two(WritableMemoryBuffer::getNewUninitMemBuffer(123, "bla"));
116 EXPECT_TRUE(nullptr != Two
.get());
118 // 0-initialized buffer with no name
119 OwningBuffer
Three(WritableMemoryBuffer::getNewMemBuffer(321, data
));
120 EXPECT_TRUE(nullptr != Three
.get());
121 for (size_t i
= 0; i
< 321; ++i
)
122 EXPECT_EQ(0, Three
->getBufferStart()[0]);
124 // 0-initialized buffer with name
125 OwningBuffer
Four(WritableMemoryBuffer::getNewMemBuffer(123, "zeros"));
126 EXPECT_TRUE(nullptr != Four
.get());
127 for (size_t i
= 0; i
< 123; ++i
)
128 EXPECT_EQ(0, Four
->getBufferStart()[0]);
131 void MemoryBufferTest::testGetOpenFileSlice(bool Reopen
) {
132 // Test that MemoryBuffer::getOpenFile works properly when no null
133 // terminator is requested and the size is large enough to trigger
134 // the usage of memory mapping.
136 SmallString
<64> TestPath
;
137 // Create a temporary file and write data into it.
138 sys::fs::createTemporaryFile("prefix", "temp", TestFD
, TestPath
);
139 FileRemover
Cleanup(TestPath
);
140 // OF is responsible for closing the file; If the file is not
141 // reopened, it will be unbuffered so that the results are
142 // immediately visible through the fd.
143 raw_fd_ostream
OF(TestFD
, true, !Reopen
);
144 for (int i
= 0; i
< 60000; ++i
) {
150 EXPECT_FALSE(sys::fs::openFileForRead(TestPath
.c_str(), TestFD
));
153 ErrorOr
<OwningBuffer
> Buf
=
154 MemoryBuffer::getOpenFileSlice(TestFD
, TestPath
.c_str(),
159 std::error_code EC
= Buf
.getError();
162 StringRef BufData
= Buf
.get()->getBuffer();
163 EXPECT_EQ(BufData
.size(), 40000U);
164 EXPECT_EQ(BufData
[0], '0');
165 EXPECT_EQ(BufData
[9], '9');
168 TEST_F(MemoryBufferTest
, getOpenFileNoReopen
) {
169 testGetOpenFileSlice(false);
172 TEST_F(MemoryBufferTest
, getOpenFileReopened
) {
173 testGetOpenFileSlice(true);
176 TEST_F(MemoryBufferTest
, reference
) {
177 OwningBuffer
MB(MemoryBuffer::getMemBuffer(data
));
178 MemoryBufferRef
MBR(*MB
);
180 EXPECT_EQ(MB
->getBufferStart(), MBR
.getBufferStart());
181 EXPECT_EQ(MB
->getBufferIdentifier(), MBR
.getBufferIdentifier());
184 TEST_F(MemoryBufferTest
, slice
) {
185 // Create a file that is six pages long with different data on each page.
187 SmallString
<64> TestPath
;
188 sys::fs::createTemporaryFile("MemoryBufferTest_Slice", "temp", FD
, TestPath
);
189 FileRemover
Cleanup(TestPath
);
190 raw_fd_ostream
OF(FD
, true, /*unbuffered=*/true);
191 for (unsigned i
= 0; i
< 0x2000 / 8; ++i
) {
194 for (unsigned i
= 0; i
< 0x2000 / 8; ++i
) {
197 for (unsigned i
= 0; i
< 0x2000 / 8; ++i
) {
202 // Try offset of one page.
203 ErrorOr
<OwningBuffer
> MB
= MemoryBuffer::getFileSlice(TestPath
.str(),
205 std::error_code EC
= MB
.getError();
207 EXPECT_EQ(0x4000UL
, MB
.get()->getBufferSize());
209 StringRef BufData
= MB
.get()->getBuffer();
210 EXPECT_TRUE(BufData
.substr(0x0000,8).equals("12345678"));
211 EXPECT_TRUE(BufData
.substr(0x0FF8,8).equals("12345678"));
212 EXPECT_TRUE(BufData
.substr(0x1000,8).equals("abcdefgh"));
213 EXPECT_TRUE(BufData
.substr(0x2FF8,8).equals("abcdefgh"));
214 EXPECT_TRUE(BufData
.substr(0x3000,8).equals("ABCDEFGH"));
215 EXPECT_TRUE(BufData
.substr(0x3FF8,8).equals("ABCDEFGH"));
217 // Try non-page aligned.
218 ErrorOr
<OwningBuffer
> MB2
= MemoryBuffer::getFileSlice(TestPath
.str(),
222 EXPECT_EQ(0x3000UL
, MB2
.get()->getBufferSize());
224 StringRef BufData2
= MB2
.get()->getBuffer();
225 EXPECT_TRUE(BufData2
.substr(0x0000,8).equals("12345678"));
226 EXPECT_TRUE(BufData2
.substr(0x17F8,8).equals("12345678"));
227 EXPECT_TRUE(BufData2
.substr(0x1800,8).equals("abcdefgh"));
228 EXPECT_TRUE(BufData2
.substr(0x2FF8,8).equals("abcdefgh"));
231 TEST_F(MemoryBufferTest
, writableSlice
) {
232 // Create a file initialized with some data
234 SmallString
<64> TestPath
;
235 sys::fs::createTemporaryFile("MemoryBufferTest_WritableSlice", "temp", FD
,
237 FileRemover
Cleanup(TestPath
);
238 raw_fd_ostream
OF(FD
, true);
239 for (unsigned i
= 0; i
< 0x1000; ++i
)
240 OF
<< "0123456789abcdef";
245 WritableMemoryBuffer::getFileSlice(TestPath
.str(), 0x6000, 0x2000);
246 ASSERT_FALSE(MBOrError
.getError());
247 // Write some data. It should be mapped private, so that upon completion
248 // the original file contents are not modified.
249 WritableMemoryBuffer
&MB
= **MBOrError
;
250 ASSERT_EQ(0x6000u
, MB
.getBufferSize());
251 char *Start
= MB
.getBufferStart();
252 ASSERT_EQ(MB
.getBufferEnd(), MB
.getBufferStart() + MB
.getBufferSize());
253 ::memset(Start
, 'x', MB
.getBufferSize());
256 auto MBOrError
= MemoryBuffer::getFile(TestPath
);
257 ASSERT_FALSE(MBOrError
.getError());
258 auto &MB
= **MBOrError
;
259 ASSERT_EQ(0x10000u
, MB
.getBufferSize());
260 for (size_t i
= 0; i
< MB
.getBufferSize(); i
+= 0x10)
261 EXPECT_EQ("0123456789abcdef", MB
.getBuffer().substr(i
, 0x10)) << "i: " << i
;
264 TEST_F(MemoryBufferTest
, writeThroughFile
) {
265 // Create a file initialized with some data
267 SmallString
<64> TestPath
;
268 sys::fs::createTemporaryFile("MemoryBufferTest_WriteThrough", "temp", FD
,
270 FileRemover
Cleanup(TestPath
);
271 raw_fd_ostream
OF(FD
, true);
272 OF
<< "0123456789abcdef";
275 auto MBOrError
= WriteThroughMemoryBuffer::getFile(TestPath
);
276 ASSERT_FALSE(MBOrError
.getError());
277 // Write some data. It should be mapped readwrite, so that upon completion
278 // the original file contents are modified.
279 WriteThroughMemoryBuffer
&MB
= **MBOrError
;
280 ASSERT_EQ(16u, MB
.getBufferSize());
281 char *Start
= MB
.getBufferStart();
282 ASSERT_EQ(MB
.getBufferEnd(), MB
.getBufferStart() + MB
.getBufferSize());
283 ::memset(Start
, 'x', MB
.getBufferSize());
286 auto MBOrError
= MemoryBuffer::getFile(TestPath
);
287 ASSERT_FALSE(MBOrError
.getError());
288 auto &MB
= **MBOrError
;
289 ASSERT_EQ(16u, MB
.getBufferSize());
290 EXPECT_EQ("xxxxxxxxxxxxxxxx", MB
.getBuffer());