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/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" 20 21 using namespace llvm; 22 23 namespace { 24 25 class MemoryBufferTest : public testing::Test { 26 protected: 27 MemoryBufferTest() 28 : data("this is some data") 29 { } 30 31 void SetUp() override {} 32 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); 39 40 typedef std::unique_ptr<MemoryBuffer> OwningBuffer; 41 42 std::string data; 43 }; 44 45 TEST_F(MemoryBufferTest, get) { 46 // Default name and null-terminator flag 47 OwningBuffer MB1(MemoryBuffer::getMemBuffer(data)); 48 EXPECT_TRUE(nullptr != MB1.get()); 49 50 // RequiresNullTerminator = false 51 OwningBuffer MB2(MemoryBuffer::getMemBuffer(data, "one", false)); 52 EXPECT_TRUE(nullptr != MB2.get()); 53 54 // RequiresNullTerminator = true 55 OwningBuffer MB3(MemoryBuffer::getMemBuffer(data, "two", true)); 56 EXPECT_TRUE(nullptr != MB3.get()); 57 58 // verify all 3 buffers point to the same address 59 EXPECT_EQ(MB1->getBufferStart(), MB2->getBufferStart()); 60 EXPECT_EQ(MB2->getBufferStart(), MB3->getBufferStart()); 61 62 // verify the original data is unmodified after deleting the buffers 63 MB1.reset(); 64 MB2.reset(); 65 MB3.reset(); 66 EXPECT_EQ("this is some data", data); 67 } 68 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. 72 int TestFD; 73 SmallString<64> TestPath; 74 sys::fs::createTemporaryFile("MemoryBufferTest_NullTerminator4K", "temp", 75 TestFD, TestPath); 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"; 80 } 81 OF.close(); 82 83 ErrorOr<OwningBuffer> MB = MemoryBuffer::getFile(TestPath.c_str()); 84 std::error_code EC = MB.getError(); 85 ASSERT_FALSE(EC); 86 87 const char *BufData = MB.get()->getBufferStart(); 88 EXPECT_EQ('f', BufData[4095]); 89 EXPECT_EQ('\0', BufData[4096]); 90 } 91 92 TEST_F(MemoryBufferTest, copy) { 93 // copy with no name 94 OwningBuffer MBC1(MemoryBuffer::getMemBufferCopy(data)); 95 EXPECT_TRUE(nullptr != MBC1.get()); 96 97 // copy with a name 98 OwningBuffer MBC2(MemoryBuffer::getMemBufferCopy(data, "copy")); 99 EXPECT_TRUE(nullptr != MBC2.get()); 100 101 // verify the two copies do not point to the same place 102 EXPECT_NE(MBC1->getBufferStart(), MBC2->getBufferStart()); 103 } 104 105 TEST_F(MemoryBufferTest, make_new) { 106 // 0-sized buffer 107 OwningBuffer Zero(WritableMemoryBuffer::getNewUninitMemBuffer(0)); 108 EXPECT_TRUE(nullptr != Zero.get()); 109 110 // uninitialized buffer with no name 111 OwningBuffer One(WritableMemoryBuffer::getNewUninitMemBuffer(321)); 112 EXPECT_TRUE(nullptr != One.get()); 113 114 // uninitialized buffer with name 115 OwningBuffer Two(WritableMemoryBuffer::getNewUninitMemBuffer(123, "bla")); 116 EXPECT_TRUE(nullptr != Two.get()); 117 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]); 123 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]); 129 } 130 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. 135 int TestFD; 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) { 145 OF << "0123456789"; 146 } 147 148 if (Reopen) { 149 OF.close(); 150 EXPECT_FALSE(sys::fs::openFileForRead(TestPath.c_str(), TestFD)); 151 } 152 153 ErrorOr<OwningBuffer> Buf = 154 MemoryBuffer::getOpenFileSlice(TestFD, TestPath.c_str(), 155 40000, // Size 156 80000 // Offset 157 ); 158 159 std::error_code EC = Buf.getError(); 160 EXPECT_FALSE(EC); 161 162 StringRef BufData = Buf.get()->getBuffer(); 163 EXPECT_EQ(BufData.size(), 40000U); 164 EXPECT_EQ(BufData[0], '0'); 165 EXPECT_EQ(BufData[9], '9'); 166 } 167 168 TEST_F(MemoryBufferTest, getOpenFileNoReopen) { 169 testGetOpenFileSlice(false); 170 } 171 172 TEST_F(MemoryBufferTest, getOpenFileReopened) { 173 testGetOpenFileSlice(true); 174 } 175 176 TEST_F(MemoryBufferTest, reference) { 177 OwningBuffer MB(MemoryBuffer::getMemBuffer(data)); 178 MemoryBufferRef MBR(*MB); 179 180 EXPECT_EQ(MB->getBufferStart(), MBR.getBufferStart()); 181 EXPECT_EQ(MB->getBufferIdentifier(), MBR.getBufferIdentifier()); 182 } 183 184 TEST_F(MemoryBufferTest, slice) { 185 // Create a file that is six pages long with different data on each page. 186 int FD; 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) { 192 OF << "12345678"; 193 } 194 for (unsigned i = 0; i < 0x2000 / 8; ++i) { 195 OF << "abcdefgh"; 196 } 197 for (unsigned i = 0; i < 0x2000 / 8; ++i) { 198 OF << "ABCDEFGH"; 199 } 200 OF.close(); 201 202 // Try offset of one page. 203 ErrorOr<OwningBuffer> MB = MemoryBuffer::getFileSlice(TestPath.str(), 204 0x4000, 0x1000); 205 std::error_code EC = MB.getError(); 206 ASSERT_FALSE(EC); 207 EXPECT_EQ(0x4000UL, MB.get()->getBufferSize()); 208 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")); 216 217 // Try non-page aligned. 218 ErrorOr<OwningBuffer> MB2 = MemoryBuffer::getFileSlice(TestPath.str(), 219 0x3000, 0x0800); 220 EC = MB2.getError(); 221 ASSERT_FALSE(EC); 222 EXPECT_EQ(0x3000UL, MB2.get()->getBufferSize()); 223 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")); 229 } 230 231 TEST_F(MemoryBufferTest, writableSlice) { 232 // Create a file initialized with some data 233 int FD; 234 SmallString<64> TestPath; 235 sys::fs::createTemporaryFile("MemoryBufferTest_WritableSlice", "temp", FD, 236 TestPath); 237 FileRemover Cleanup(TestPath); 238 raw_fd_ostream OF(FD, true); 239 for (unsigned i = 0; i < 0x1000; ++i) 240 OF << "0123456789abcdef"; 241 OF.close(); 242 243 { 244 auto MBOrError = 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()); 254 } 255 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; 262 } 263 264 TEST_F(MemoryBufferTest, writeThroughFile) { 265 // Create a file initialized with some data 266 int FD; 267 SmallString<64> TestPath; 268 sys::fs::createTemporaryFile("MemoryBufferTest_WriteThrough", "temp", FD, 269 TestPath); 270 FileRemover Cleanup(TestPath); 271 raw_fd_ostream OF(FD, true); 272 OF << "0123456789abcdef"; 273 OF.close(); 274 { 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()); 284 } 285 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()); 291 } 292 } 293