xref: /llvm-project/llvm/unittests/Support/MemoryBufferTest.cpp (revision 2946cd701067404b99c39fb29dc9c74bd7193eb3)
1 //===- llvm/unittest/Support/MemoryBufferTest.cpp - MemoryBuffer tests ----===//
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 // This file implements unit tests for the MemoryBuffer support class.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "llvm/Support/MemoryBuffer.h"
14 #include "llvm/Support/FileSystem.h"
15 #include "llvm/Support/FileUtilities.h"
16 #include "llvm/Support/raw_ostream.h"
17 #include "llvm/Testing/Support/Error.h"
18 #include "gtest/gtest.h"
19 
20 using namespace llvm;
21 
22 namespace {
23 
24 class MemoryBufferTest : public testing::Test {
25 protected:
26   MemoryBufferTest()
27   : data("this is some data")
28   { }
29 
30   void SetUp() override {}
31 
32   /// Common testing for different modes of getOpenFileSlice.
33   /// Creates a temporary file with known contents, and uses
34   /// MemoryBuffer::getOpenFileSlice to map it.
35   /// If \p Reopen is true, the file is closed after creating and reopened
36   /// anew before using MemoryBuffer.
37   void testGetOpenFileSlice(bool Reopen);
38 
39   typedef std::unique_ptr<MemoryBuffer> OwningBuffer;
40 
41   std::string data;
42 };
43 
44 TEST_F(MemoryBufferTest, get) {
45   // Default name and null-terminator flag
46   OwningBuffer MB1(MemoryBuffer::getMemBuffer(data));
47   EXPECT_TRUE(nullptr != MB1.get());
48 
49   // RequiresNullTerminator = false
50   OwningBuffer MB2(MemoryBuffer::getMemBuffer(data, "one", false));
51   EXPECT_TRUE(nullptr != MB2.get());
52 
53   // RequiresNullTerminator = true
54   OwningBuffer MB3(MemoryBuffer::getMemBuffer(data, "two", true));
55   EXPECT_TRUE(nullptr != MB3.get());
56 
57   // verify all 3 buffers point to the same address
58   EXPECT_EQ(MB1->getBufferStart(), MB2->getBufferStart());
59   EXPECT_EQ(MB2->getBufferStart(), MB3->getBufferStart());
60 
61   // verify the original data is unmodified after deleting the buffers
62   MB1.reset();
63   MB2.reset();
64   MB3.reset();
65   EXPECT_EQ("this is some data", data);
66 }
67 
68 TEST_F(MemoryBufferTest, NullTerminator4K) {
69   // Test that a file with size that is a multiple of the page size can be null
70   // terminated correctly by MemoryBuffer.
71   int TestFD;
72   SmallString<64> TestPath;
73   sys::fs::createTemporaryFile("MemoryBufferTest_NullTerminator4K", "temp",
74                                TestFD, TestPath);
75   FileRemover Cleanup(TestPath);
76   raw_fd_ostream OF(TestFD, true, /*unbuffered=*/true);
77   for (unsigned i = 0; i < 4096 / 16; ++i) {
78     OF << "0123456789abcdef";
79   }
80   OF.close();
81 
82   ErrorOr<OwningBuffer> MB = MemoryBuffer::getFile(TestPath.c_str());
83   std::error_code EC = MB.getError();
84   ASSERT_FALSE(EC);
85 
86   const char *BufData = MB.get()->getBufferStart();
87   EXPECT_EQ('f', BufData[4095]);
88   EXPECT_EQ('\0', BufData[4096]);
89 }
90 
91 TEST_F(MemoryBufferTest, copy) {
92   // copy with no name
93   OwningBuffer MBC1(MemoryBuffer::getMemBufferCopy(data));
94   EXPECT_TRUE(nullptr != MBC1.get());
95 
96   // copy with a name
97   OwningBuffer MBC2(MemoryBuffer::getMemBufferCopy(data, "copy"));
98   EXPECT_TRUE(nullptr != MBC2.get());
99 
100   // verify the two copies do not point to the same place
101   EXPECT_NE(MBC1->getBufferStart(), MBC2->getBufferStart());
102 }
103 
104 TEST_F(MemoryBufferTest, make_new) {
105   // 0-sized buffer
106   OwningBuffer Zero(WritableMemoryBuffer::getNewUninitMemBuffer(0));
107   EXPECT_TRUE(nullptr != Zero.get());
108 
109   // uninitialized buffer with no name
110   OwningBuffer One(WritableMemoryBuffer::getNewUninitMemBuffer(321));
111   EXPECT_TRUE(nullptr != One.get());
112 
113   // uninitialized buffer with name
114   OwningBuffer Two(WritableMemoryBuffer::getNewUninitMemBuffer(123, "bla"));
115   EXPECT_TRUE(nullptr != Two.get());
116 
117   // 0-initialized buffer with no name
118   OwningBuffer Three(WritableMemoryBuffer::getNewMemBuffer(321, data));
119   EXPECT_TRUE(nullptr != Three.get());
120   for (size_t i = 0; i < 321; ++i)
121     EXPECT_EQ(0, Three->getBufferStart()[0]);
122 
123   // 0-initialized buffer with name
124   OwningBuffer Four(WritableMemoryBuffer::getNewMemBuffer(123, "zeros"));
125   EXPECT_TRUE(nullptr != Four.get());
126   for (size_t i = 0; i < 123; ++i)
127     EXPECT_EQ(0, Four->getBufferStart()[0]);
128 }
129 
130 void MemoryBufferTest::testGetOpenFileSlice(bool Reopen) {
131   // Test that MemoryBuffer::getOpenFile works properly when no null
132   // terminator is requested and the size is large enough to trigger
133   // the usage of memory mapping.
134   int TestFD;
135   SmallString<64> TestPath;
136   // Create a temporary file and write data into it.
137   sys::fs::createTemporaryFile("prefix", "temp", TestFD, TestPath);
138   FileRemover Cleanup(TestPath);
139   // OF is responsible for closing the file; If the file is not
140   // reopened, it will be unbuffered so that the results are
141   // immediately visible through the fd.
142   raw_fd_ostream OF(TestFD, true, !Reopen);
143   for (int i = 0; i < 60000; ++i) {
144     OF << "0123456789";
145   }
146 
147   if (Reopen) {
148     OF.close();
149     EXPECT_FALSE(sys::fs::openFileForRead(TestPath.c_str(), TestFD));
150   }
151 
152   ErrorOr<OwningBuffer> Buf =
153       MemoryBuffer::getOpenFileSlice(TestFD, TestPath.c_str(),
154                                      40000, // Size
155                                      80000  // Offset
156                                      );
157 
158   std::error_code EC = Buf.getError();
159   EXPECT_FALSE(EC);
160 
161   StringRef BufData = Buf.get()->getBuffer();
162   EXPECT_EQ(BufData.size(), 40000U);
163   EXPECT_EQ(BufData[0], '0');
164   EXPECT_EQ(BufData[9], '9');
165 }
166 
167 TEST_F(MemoryBufferTest, getOpenFileNoReopen) {
168   testGetOpenFileSlice(false);
169 }
170 
171 TEST_F(MemoryBufferTest, getOpenFileReopened) {
172   testGetOpenFileSlice(true);
173 }
174 
175 TEST_F(MemoryBufferTest, reference) {
176   OwningBuffer MB(MemoryBuffer::getMemBuffer(data));
177   MemoryBufferRef MBR(*MB);
178 
179   EXPECT_EQ(MB->getBufferStart(), MBR.getBufferStart());
180   EXPECT_EQ(MB->getBufferIdentifier(), MBR.getBufferIdentifier());
181 }
182 
183 TEST_F(MemoryBufferTest, slice) {
184   // Create a file that is six pages long with different data on each page.
185   int FD;
186   SmallString<64> TestPath;
187   sys::fs::createTemporaryFile("MemoryBufferTest_Slice", "temp", FD, TestPath);
188   FileRemover Cleanup(TestPath);
189   raw_fd_ostream OF(FD, true, /*unbuffered=*/true);
190   for (unsigned i = 0; i < 0x2000 / 8; ++i) {
191     OF << "12345678";
192   }
193   for (unsigned i = 0; i < 0x2000 / 8; ++i) {
194     OF << "abcdefgh";
195   }
196   for (unsigned i = 0; i < 0x2000 / 8; ++i) {
197     OF << "ABCDEFGH";
198   }
199   OF.close();
200 
201   // Try offset of one page.
202   ErrorOr<OwningBuffer> MB = MemoryBuffer::getFileSlice(TestPath.str(),
203                                                         0x4000, 0x1000);
204   std::error_code EC = MB.getError();
205   ASSERT_FALSE(EC);
206   EXPECT_EQ(0x4000UL, MB.get()->getBufferSize());
207 
208   StringRef BufData = MB.get()->getBuffer();
209   EXPECT_TRUE(BufData.substr(0x0000,8).equals("12345678"));
210   EXPECT_TRUE(BufData.substr(0x0FF8,8).equals("12345678"));
211   EXPECT_TRUE(BufData.substr(0x1000,8).equals("abcdefgh"));
212   EXPECT_TRUE(BufData.substr(0x2FF8,8).equals("abcdefgh"));
213   EXPECT_TRUE(BufData.substr(0x3000,8).equals("ABCDEFGH"));
214   EXPECT_TRUE(BufData.substr(0x3FF8,8).equals("ABCDEFGH"));
215 
216   // Try non-page aligned.
217   ErrorOr<OwningBuffer> MB2 = MemoryBuffer::getFileSlice(TestPath.str(),
218                                                          0x3000, 0x0800);
219   EC = MB2.getError();
220   ASSERT_FALSE(EC);
221   EXPECT_EQ(0x3000UL, MB2.get()->getBufferSize());
222 
223   StringRef BufData2 = MB2.get()->getBuffer();
224   EXPECT_TRUE(BufData2.substr(0x0000,8).equals("12345678"));
225   EXPECT_TRUE(BufData2.substr(0x17F8,8).equals("12345678"));
226   EXPECT_TRUE(BufData2.substr(0x1800,8).equals("abcdefgh"));
227   EXPECT_TRUE(BufData2.substr(0x2FF8,8).equals("abcdefgh"));
228 }
229 
230 TEST_F(MemoryBufferTest, writableSlice) {
231   // Create a file initialized with some data
232   int FD;
233   SmallString<64> TestPath;
234   sys::fs::createTemporaryFile("MemoryBufferTest_WritableSlice", "temp", FD,
235                                TestPath);
236   FileRemover Cleanup(TestPath);
237   raw_fd_ostream OF(FD, true);
238   for (unsigned i = 0; i < 0x1000; ++i)
239     OF << "0123456789abcdef";
240   OF.close();
241 
242   {
243     auto MBOrError =
244         WritableMemoryBuffer::getFileSlice(TestPath.str(), 0x6000, 0x2000);
245     ASSERT_FALSE(MBOrError.getError());
246     // Write some data.  It should be mapped private, so that upon completion
247     // the original file contents are not modified.
248     WritableMemoryBuffer &MB = **MBOrError;
249     ASSERT_EQ(0x6000u, MB.getBufferSize());
250     char *Start = MB.getBufferStart();
251     ASSERT_EQ(MB.getBufferEnd(), MB.getBufferStart() + MB.getBufferSize());
252     ::memset(Start, 'x', MB.getBufferSize());
253   }
254 
255   auto MBOrError = MemoryBuffer::getFile(TestPath);
256   ASSERT_FALSE(MBOrError.getError());
257   auto &MB = **MBOrError;
258   ASSERT_EQ(0x10000u, MB.getBufferSize());
259   for (size_t i = 0; i < MB.getBufferSize(); i += 0x10)
260     EXPECT_EQ("0123456789abcdef", MB.getBuffer().substr(i, 0x10)) << "i: " << i;
261 }
262 
263 TEST_F(MemoryBufferTest, writeThroughFile) {
264   // Create a file initialized with some data
265   int FD;
266   SmallString<64> TestPath;
267   sys::fs::createTemporaryFile("MemoryBufferTest_WriteThrough", "temp", FD,
268                                TestPath);
269   FileRemover Cleanup(TestPath);
270   raw_fd_ostream OF(FD, true);
271   OF << "0123456789abcdef";
272   OF.close();
273   {
274     auto MBOrError = WriteThroughMemoryBuffer::getFile(TestPath);
275     ASSERT_FALSE(MBOrError.getError());
276     // Write some data.  It should be mapped readwrite, so that upon completion
277     // the original file contents are modified.
278     WriteThroughMemoryBuffer &MB = **MBOrError;
279     ASSERT_EQ(16u, MB.getBufferSize());
280     char *Start = MB.getBufferStart();
281     ASSERT_EQ(MB.getBufferEnd(), MB.getBufferStart() + MB.getBufferSize());
282     ::memset(Start, 'x', MB.getBufferSize());
283   }
284 
285   auto MBOrError = MemoryBuffer::getFile(TestPath);
286   ASSERT_FALSE(MBOrError.getError());
287   auto &MB = **MBOrError;
288   ASSERT_EQ(16u, MB.getBufferSize());
289   EXPECT_EQ("xxxxxxxxxxxxxxxx", MB.getBuffer());
290 }
291 }
292