1 //===- llvm/unittest/Support/MemoryBufferTest.cpp - MemoryBuffer tests ----===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This file implements unit tests for the MemoryBuffer support class.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #include "llvm/Support/FileSystem.h"
15 #include "llvm/Support/FileUtilities.h"
16 #include "llvm/Support/MemoryBuffer.h"
17 #include "llvm/Support/raw_ostream.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(MemoryBuffer::getNewUninitMemBuffer(0));
107   EXPECT_TRUE(nullptr != Zero.get());
108 
109   // uninitialized buffer with no name
110   OwningBuffer One(MemoryBuffer::getNewUninitMemBuffer(321));
111   EXPECT_TRUE(nullptr != One.get());
112 
113   // uninitialized buffer with name
114   OwningBuffer Two(MemoryBuffer::getNewUninitMemBuffer(123, "bla"));
115   EXPECT_TRUE(nullptr != Two.get());
116 
117   // 0-initialized buffer with no name
118   OwningBuffer Three(MemoryBuffer::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(MemoryBuffer::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