brintos

brintos / llvm-project-archived public Read only

0
0
Text · 15.9 KiB · 2cc20c0 Raw
462 lines · cpp
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-exception6//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/ADT/ScopeExit.h"15#include "llvm/Config/llvm-config.h" // for LLVM_ENABLE_THREADS, LLVM_ON_UNIX16#include "llvm/Support/FileSystem.h"17#include "llvm/Support/FileUtilities.h"18#include "llvm/Support/Process.h"19#include "llvm/Support/SmallVectorMemoryBuffer.h"20#include "llvm/Support/raw_ostream.h"21#include "llvm/Testing/Support/Error.h"22#include "gtest/gtest.h"23#if LLVM_ENABLE_THREADS24#include <thread>25#endif26#if LLVM_ON_UNIX27#include <unistd.h>28#endif29#if _WIN3230#include <windows.h>31#endif32 33using namespace llvm;34 35#define ASSERT_NO_ERROR(x)                                                     \36  if (std::error_code ASSERT_NO_ERROR_ec = x) {                                \37    SmallString<128> MessageStorage;                                           \38    raw_svector_ostream Message(MessageStorage);                               \39    Message << #x ": did not return errc::success.\n"                          \40            << "error number: " << ASSERT_NO_ERROR_ec.value() << "\n"          \41            << "error message: " << ASSERT_NO_ERROR_ec.message() << "\n";      \42    GTEST_FATAL_FAILURE_(MessageStorage.c_str());                              \43  } else {                                                                     \44  }45 46#define ASSERT_ERROR(x)                                                        \47  if (!x) {                                                                    \48    SmallString<128> MessageStorage;                                           \49    raw_svector_ostream Message(MessageStorage);                               \50    Message << #x ": did not return a failure error code.\n";                  \51    GTEST_FATAL_FAILURE_(MessageStorage.c_str());                              \52  }53 54namespace {55 56class MemoryBufferTest : public testing::Test {57protected:58  MemoryBufferTest()59  : data("this is some data")60  { }61 62  void SetUp() override {}63 64  /// Common testing for different modes of getOpenFileSlice.65  /// Creates a temporary file with known contents, and uses66  /// MemoryBuffer::getOpenFileSlice to map it.67  /// If \p Reopen is true, the file is closed after creating and reopened68  /// anew before using MemoryBuffer.69  void testGetOpenFileSlice(bool Reopen);70 71  typedef std::unique_ptr<MemoryBuffer> OwningBuffer;72 73  std::string data;74};75 76TEST_F(MemoryBufferTest, get) {77  // Default name and null-terminator flag78  OwningBuffer MB1(MemoryBuffer::getMemBuffer(data));79  EXPECT_NE(nullptr, MB1.get());80 81  // RequiresNullTerminator = false82  OwningBuffer MB2(MemoryBuffer::getMemBuffer(data, "one", false));83  EXPECT_NE(nullptr, MB2.get());84 85  // RequiresNullTerminator = true86  OwningBuffer MB3(MemoryBuffer::getMemBuffer(data, "two", true));87  EXPECT_NE(nullptr, MB3.get());88 89  // verify all 3 buffers point to the same address90  EXPECT_EQ(MB1->getBufferStart(), MB2->getBufferStart());91  EXPECT_EQ(MB2->getBufferStart(), MB3->getBufferStart());92 93  // verify the original data is unmodified after deleting the buffers94  MB1.reset();95  MB2.reset();96  MB3.reset();97  EXPECT_EQ("this is some data", data);98}99 100TEST_F(MemoryBufferTest, getOpenFile) {101  int FD;102  SmallString<64> TestPath;103  ASSERT_EQ(sys::fs::createTemporaryFile("MemoryBufferTest_getOpenFile", "temp",104                                         FD, TestPath),105            std::error_code());106 107  FileRemover Cleanup(TestPath);108  raw_fd_ostream OF(FD, /*shouldClose*/ true);109  OF << "12345678";110  OF.close();111 112  {113    Expected<sys::fs::file_t> File = sys::fs::openNativeFileForRead(TestPath);114    ASSERT_THAT_EXPECTED(File, Succeeded());115    auto OnExit =116        make_scope_exit([&] { ASSERT_NO_ERROR(sys::fs::closeFile(*File)); });117    ErrorOr<OwningBuffer> MB = MemoryBuffer::getOpenFile(*File, TestPath, 6);118    ASSERT_NO_ERROR(MB.getError());119    EXPECT_EQ("123456", MB.get()->getBuffer());120  }121  {122    Expected<sys::fs::file_t> File = sys::fs::openNativeFileForWrite(123        TestPath, sys::fs::CD_OpenExisting, sys::fs::OF_None);124    ASSERT_THAT_EXPECTED(File, Succeeded());125    auto OnExit =126        make_scope_exit([&] { ASSERT_NO_ERROR(sys::fs::closeFile(*File)); });127    ASSERT_ERROR(MemoryBuffer::getOpenFile(*File, TestPath, 6).getError());128  }129}130 131TEST_F(MemoryBufferTest, NullTerminator4K) {132  // Test that a file with size that is a multiple of the page size can be null133  // terminated correctly by MemoryBuffer.134  int TestFD;135  SmallString<64> TestPath;136  sys::fs::createTemporaryFile("MemoryBufferTest_NullTerminator4K", "temp",137                               TestFD, TestPath);138  FileRemover Cleanup(TestPath);139  raw_fd_ostream OF(TestFD, true, /*unbuffered=*/true);140  for (unsigned i = 0; i < 4096 / 16; ++i) {141    OF << "0123456789abcdef";142  }143  OF.close();144 145  ErrorOr<OwningBuffer> MB = MemoryBuffer::getFile(TestPath.c_str());146  std::error_code EC = MB.getError();147  ASSERT_FALSE(EC);148 149  const char *BufData = MB.get()->getBufferStart();150  EXPECT_EQ('f', BufData[4095]);151  EXPECT_EQ('\0', BufData[4096]);152}153 154TEST_F(MemoryBufferTest, copy) {155  // copy with no name156  OwningBuffer MBC1(MemoryBuffer::getMemBufferCopy(data));157  EXPECT_NE(nullptr, MBC1.get());158 159  // copy with a name160  OwningBuffer MBC2(MemoryBuffer::getMemBufferCopy(data, "copy"));161  EXPECT_NE(nullptr, MBC2.get());162 163  // verify the two copies do not point to the same place164  EXPECT_NE(MBC1->getBufferStart(), MBC2->getBufferStart());165 166  // check that copies from defaulted stringrefs don't trigger UB.167  OwningBuffer MBC3(MemoryBuffer::getMemBufferCopy(StringRef{}));168  EXPECT_NE(nullptr, MBC3.get());169}170 171#if LLVM_ENABLE_THREADS172TEST_F(MemoryBufferTest, createFromPipe) {173  sys::fs::file_t pipes[2];174#if LLVM_ON_UNIX175  ASSERT_EQ(::pipe(pipes), 0) << strerror(errno);176#else177  ASSERT_TRUE(::CreatePipe(&pipes[0], &pipes[1], nullptr, 0))178      << ::GetLastError();179#endif180  auto ReadCloser = make_scope_exit([&] { sys::fs::closeFile(pipes[0]); });181  std::thread Writer([&] {182    auto WriteCloser = make_scope_exit([&] { sys::fs::closeFile(pipes[1]); });183    for (unsigned i = 0; i < 5; ++i) {184      std::this_thread::sleep_for(std::chrono::milliseconds(10));185#if LLVM_ON_UNIX186      ASSERT_EQ(::write(pipes[1], "foo", 3), 3) << strerror(errno);187#else188      DWORD Written;189      ASSERT_TRUE(::WriteFile(pipes[1], "foo", 3, &Written, nullptr))190          << ::GetLastError();191      ASSERT_EQ(Written, 3u);192#endif193    }194  });195  ErrorOr<OwningBuffer> MB =196      MemoryBuffer::getOpenFile(pipes[0], "pipe", /*FileSize*/ -1);197  Writer.join();198  ASSERT_NO_ERROR(MB.getError());199  EXPECT_EQ(MB.get()->getBuffer(), "foofoofoofoofoo");200}201#endif202 203TEST_F(MemoryBufferTest, make_new) {204  // 0-sized buffer205  OwningBuffer Zero(WritableMemoryBuffer::getNewUninitMemBuffer(0));206  EXPECT_NE(nullptr, Zero.get());207 208  // uninitialized buffer with no name209  OwningBuffer One(WritableMemoryBuffer::getNewUninitMemBuffer(321));210  EXPECT_NE(nullptr, One.get());211 212  // uninitialized buffer with name213  OwningBuffer Two(WritableMemoryBuffer::getNewUninitMemBuffer(123, "bla"));214  EXPECT_NE(nullptr, Two.get());215 216  // 0-initialized buffer with no name217  OwningBuffer Three(WritableMemoryBuffer::getNewMemBuffer(321, data));218  EXPECT_NE(nullptr, Three.get());219  for (size_t i = 0; i < 321; ++i)220    EXPECT_EQ(0, Three->getBufferStart()[0]);221 222  // 0-initialized buffer with name223  OwningBuffer Four(WritableMemoryBuffer::getNewMemBuffer(123, "zeros"));224  EXPECT_NE(nullptr, Four.get());225  for (size_t i = 0; i < 123; ++i)226    EXPECT_EQ(0, Four->getBufferStart()[0]);227 228  // uninitialized buffer with rollover size229  OwningBuffer Five(230      WritableMemoryBuffer::getNewUninitMemBuffer(SIZE_MAX, "huge"));231  EXPECT_EQ(nullptr, Five.get());232}233 234TEST_F(MemoryBufferTest, getNewAligned) {235  auto CheckAlignment = [](size_t AlignmentValue) {236    Align Alignment(AlignmentValue);237    OwningBuffer AlignedBuffer =238        WritableMemoryBuffer::getNewUninitMemBuffer(0, "", Alignment);239    EXPECT_TRUE(isAddrAligned(Alignment, AlignedBuffer->getBufferStart()));240  };241 242  // Test allocation with different alignments.243  CheckAlignment(16);244  CheckAlignment(32);245  CheckAlignment(64);246  CheckAlignment(128);247  CheckAlignment(256);248}249 250void MemoryBufferTest::testGetOpenFileSlice(bool Reopen) {251  // Test that MemoryBuffer::getOpenFile works properly when no null252  // terminator is requested and the size is large enough to trigger253  // the usage of memory mapping.254  int TestFD;255  SmallString<64> TestPath;256  // Create a temporary file and write data into it.257  sys::fs::createTemporaryFile("prefix", "temp", TestFD, TestPath);258  FileRemover Cleanup(TestPath);259  // OF is responsible for closing the file; If the file is not260  // reopened, it will be unbuffered so that the results are261  // immediately visible through the fd.262  raw_fd_ostream OF(TestFD, true, !Reopen);263  for (int i = 0; i < 60000; ++i) {264    OF << "0123456789";265  }266 267  if (Reopen) {268    OF.close();269    EXPECT_FALSE(sys::fs::openFileForRead(TestPath.c_str(), TestFD));270  }271 272  ErrorOr<OwningBuffer> Buf = MemoryBuffer::getOpenFileSlice(273      sys::fs::convertFDToNativeFile(TestFD), TestPath.c_str(),274      40000, // Size275      80000  // Offset276  );277 278  std::error_code EC = Buf.getError();279  EXPECT_FALSE(EC);280 281  StringRef BufData = Buf.get()->getBuffer();282  EXPECT_EQ(BufData.size(), 40000U);283  EXPECT_EQ(BufData[0], '0');284  EXPECT_EQ(BufData[9], '9');285}286 287TEST_F(MemoryBufferTest, getOpenFileNoReopen) {288  testGetOpenFileSlice(false);289}290 291TEST_F(MemoryBufferTest, getOpenFileReopened) {292  testGetOpenFileSlice(true);293}294 295TEST_F(MemoryBufferTest, slice) {296  // Create a file that is six pages long with different data on each page.297  int FD;298  SmallString<64> TestPath;299  sys::fs::createTemporaryFile("MemoryBufferTest_Slice", "temp", FD, TestPath);300  FileRemover Cleanup(TestPath);301  raw_fd_ostream OF(FD, true, /*unbuffered=*/true);302  for (unsigned i = 0; i < 0x2000 / 8; ++i) {303    OF << "12345678";304  }305  for (unsigned i = 0; i < 0x2000 / 8; ++i) {306    OF << "abcdefgh";307  }308  for (unsigned i = 0; i < 0x2000 / 8; ++i) {309    OF << "ABCDEFGH";310  }311  OF.close();312 313  // Try offset of one page.314  ErrorOr<OwningBuffer> MB = MemoryBuffer::getFileSlice(TestPath.str(),315                                                        0x4000, 0x1000);316  std::error_code EC = MB.getError();317  ASSERT_FALSE(EC);318  EXPECT_EQ(0x4000UL, MB.get()->getBufferSize());319 320  StringRef BufData = MB.get()->getBuffer();321  EXPECT_TRUE(BufData.substr(0x0000, 8) == "12345678");322  EXPECT_TRUE(BufData.substr(0x0FF8, 8) == "12345678");323  EXPECT_TRUE(BufData.substr(0x1000, 8) == "abcdefgh");324  EXPECT_TRUE(BufData.substr(0x2FF8, 8) == "abcdefgh");325  EXPECT_TRUE(BufData.substr(0x3000, 8) == "ABCDEFGH");326  EXPECT_TRUE(BufData.substr(0x3FF8, 8) == "ABCDEFGH");327 328  // Try non-page aligned.329  ErrorOr<OwningBuffer> MB2 = MemoryBuffer::getFileSlice(TestPath.str(),330                                                         0x3000, 0x0800);331  EC = MB2.getError();332  ASSERT_FALSE(EC);333  EXPECT_EQ(0x3000UL, MB2.get()->getBufferSize());334  335  StringRef BufData2 = MB2.get()->getBuffer();336  EXPECT_TRUE(BufData2.substr(0x0000, 8) == "12345678");337  EXPECT_TRUE(BufData2.substr(0x17F8, 8) == "12345678");338  EXPECT_TRUE(BufData2.substr(0x1800, 8) == "abcdefgh");339  EXPECT_TRUE(BufData2.substr(0x2FF8, 8) == "abcdefgh");340}341 342TEST_F(MemoryBufferTest, writableSlice) {343  // Create a file initialized with some data344  int FD;345  SmallString<64> TestPath;346  sys::fs::createTemporaryFile("MemoryBufferTest_WritableSlice", "temp", FD,347                               TestPath);348  FileRemover Cleanup(TestPath);349  raw_fd_ostream OF(FD, true);350  for (unsigned i = 0; i < 0x1000; ++i)351    OF << "0123456789abcdef";352  OF.close();353 354  {355    auto MBOrError =356        WritableMemoryBuffer::getFileSlice(TestPath.str(), 0x6000, 0x2000);357    ASSERT_FALSE(MBOrError.getError());358    // Write some data.  It should be mapped private, so that upon completion359    // the original file contents are not modified.360    WritableMemoryBuffer &MB = **MBOrError;361    ASSERT_EQ(0x6000u, MB.getBufferSize());362    char *Start = MB.getBufferStart();363    ASSERT_EQ(MB.getBufferEnd(), MB.getBufferStart() + MB.getBufferSize());364    ::memset(Start, 'x', MB.getBufferSize());365  }366 367  auto MBOrError = MemoryBuffer::getFile(TestPath);368  ASSERT_FALSE(MBOrError.getError());369  auto &MB = **MBOrError;370  ASSERT_EQ(0x10000u, MB.getBufferSize());371  for (size_t i = 0; i < MB.getBufferSize(); i += 0x10)372    EXPECT_EQ("0123456789abcdef", MB.getBuffer().substr(i, 0x10)) << "i: " << i;373}374 375TEST_F(MemoryBufferTest, writeThroughFile) {376  // Create a file initialized with some data377  int FD;378  SmallString<64> TestPath;379  sys::fs::createTemporaryFile("MemoryBufferTest_WriteThrough", "temp", FD,380                               TestPath);381  FileRemover Cleanup(TestPath);382  raw_fd_ostream OF(FD, true);383  OF << "0123456789abcdef";384  OF.close();385  {386    auto MBOrError = WriteThroughMemoryBuffer::getFile(TestPath);387    ASSERT_FALSE(MBOrError.getError());388    // Write some data.  It should be mapped readwrite, so that upon completion389    // the original file contents are modified.390    WriteThroughMemoryBuffer &MB = **MBOrError;391    ASSERT_EQ(16u, MB.getBufferSize());392    char *Start = MB.getBufferStart();393    ASSERT_EQ(MB.getBufferEnd(), MB.getBufferStart() + MB.getBufferSize());394    ::memset(Start, 'x', MB.getBufferSize());395  }396 397  auto MBOrError = MemoryBuffer::getFile(TestPath);398  ASSERT_FALSE(MBOrError.getError());399  auto &MB = **MBOrError;400  ASSERT_EQ(16u, MB.getBufferSize());401  EXPECT_EQ("xxxxxxxxxxxxxxxx", MB.getBuffer());402}403 404TEST_F(MemoryBufferTest, mmapVolatileNoNull) {405  // Verify that `MemoryBuffer::getOpenFile` will use mmap when406  // `RequiresNullTerminator = false`, `IsVolatile = true`, and the file is407  // large enough to use mmap.408  //409  // This is done because Clang should use this mode to open module files, and410  // falling back to malloc for them causes a huge memory usage increase.411 412  int FD;413  SmallString<64> TestPath;414  ASSERT_NO_ERROR(sys::fs::createTemporaryFile(415      "MemoryBufferTest_mmapVolatileNoNull", "temp", FD, TestPath));416  FileRemover Cleanup(TestPath);417  raw_fd_ostream OF(FD, true);418  // Create a file large enough to mmap. 4 pages should be enough.419  unsigned PageSize = sys::Process::getPageSizeEstimate();420  unsigned FileWrites = (PageSize * 4) / 8;421  for (unsigned i = 0; i < FileWrites; ++i)422    OF << "01234567";423  OF.close();424 425  Expected<sys::fs::file_t> File = sys::fs::openNativeFileForRead(TestPath);426  ASSERT_THAT_EXPECTED(File, Succeeded());427  auto OnExit =428      make_scope_exit([&] { ASSERT_NO_ERROR(sys::fs::closeFile(*File)); });429 430  auto MBOrError = MemoryBuffer::getOpenFile(*File, TestPath,431      /*FileSize=*/-1, /*RequiresNullTerminator=*/false, /*IsVolatile=*/true);432  ASSERT_NO_ERROR(MBOrError.getError())433  OwningBuffer MB = std::move(*MBOrError);434  EXPECT_EQ(MB->getBufferKind(), MemoryBuffer::MemoryBuffer_MMap);435  EXPECT_EQ(MB->getBufferSize(), std::size_t(FileWrites * 8));436  EXPECT_TRUE(MB->getBuffer().starts_with("01234567"));437}438 439// Test that SmallVector without a null terminator gets one.440TEST(SmallVectorMemoryBufferTest, WithoutNullTerminatorRequiresNullTerminator) {441  SmallString<0> Data("some data");442 443  SmallVectorMemoryBuffer MB(std::move(Data),444                             /*RequiresNullTerminator=*/true);445  EXPECT_EQ(MB.getBufferSize(), 9u);446  EXPECT_EQ(MB.getBufferEnd()[0], '\0');447}448 449// Test that SmallVector with a null terminator keeps it.450TEST(SmallVectorMemoryBufferTest, WithNullTerminatorRequiresNullTerminator) {451  SmallString<0> Data("some data");452  Data.push_back('\0');453  Data.pop_back();454 455  SmallVectorMemoryBuffer MB(std::move(Data),456                             /*RequiresNullTerminator=*/true);457  EXPECT_EQ(MB.getBufferSize(), 9u);458  EXPECT_EQ(MB.getBufferEnd()[0], '\0');459}460 461} // namespace462