1 //===--- MemoryBuffer.cpp - Memory Buffer implementation ------------------===// 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 the MemoryBuffer interface. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/Support/MemoryBuffer.h" 14 #include "llvm/ADT/STLExtras.h" 15 #include "llvm/ADT/SmallString.h" 16 #include "llvm/Config/config.h" 17 #include "llvm/Support/Alignment.h" 18 #include "llvm/Support/Errc.h" 19 #include "llvm/Support/Error.h" 20 #include "llvm/Support/ErrorHandling.h" 21 #include "llvm/Support/FileSystem.h" 22 #include "llvm/Support/Process.h" 23 #include "llvm/Support/Program.h" 24 #include "llvm/Support/SmallVectorMemoryBuffer.h" 25 #include <algorithm> 26 #include <cassert> 27 #include <cstring> 28 #include <new> 29 #include <sys/types.h> 30 #include <system_error> 31 #if !defined(_MSC_VER) && !defined(__MINGW32__) 32 #include <unistd.h> 33 #else 34 #include <io.h> 35 #endif 36 37 #ifdef __MVS__ 38 #include "llvm/Support/AutoConvert.h" 39 #endif 40 using namespace llvm; 41 42 //===----------------------------------------------------------------------===// 43 // MemoryBuffer implementation itself. 44 //===----------------------------------------------------------------------===// 45 46 MemoryBuffer::~MemoryBuffer() = default; 47 48 /// init - Initialize this MemoryBuffer as a reference to externally allocated 49 /// memory, memory that we know is already null terminated. 50 void MemoryBuffer::init(const char *BufStart, const char *BufEnd, 51 bool RequiresNullTerminator) { 52 assert((!RequiresNullTerminator || BufEnd[0] == 0) && 53 "Buffer is not null terminated!"); 54 BufferStart = BufStart; 55 BufferEnd = BufEnd; 56 } 57 58 //===----------------------------------------------------------------------===// 59 // MemoryBufferMem implementation. 60 //===----------------------------------------------------------------------===// 61 62 /// CopyStringRef - Copies contents of a StringRef into a block of memory and 63 /// null-terminates it. 64 static void CopyStringRef(char *Memory, StringRef Data) { 65 if (!Data.empty()) 66 memcpy(Memory, Data.data(), Data.size()); 67 Memory[Data.size()] = 0; // Null terminate string. 68 } 69 70 namespace { 71 struct NamedBufferAlloc { 72 const Twine &Name; 73 NamedBufferAlloc(const Twine &Name) : Name(Name) {} 74 }; 75 } // namespace 76 77 void *operator new(size_t N, const NamedBufferAlloc &Alloc) { 78 SmallString<256> NameBuf; 79 StringRef NameRef = Alloc.Name.toStringRef(NameBuf); 80 81 // We use malloc() and manually handle it returning null instead of calling 82 // operator new because we need all uses of NamedBufferAlloc to be 83 // deallocated with a call to free() due to needing to use malloc() in 84 // WritableMemoryBuffer::getNewUninitMemBuffer() to work around the out-of- 85 // memory handler installed by default in LLVM. See operator delete() member 86 // functions within this file for the paired call to free(). 87 char *Mem = 88 static_cast<char *>(std::malloc(N + sizeof(size_t) + NameRef.size() + 1)); 89 if (!Mem) 90 llvm::report_bad_alloc_error("Allocation failed"); 91 *reinterpret_cast<size_t *>(Mem + N) = NameRef.size(); 92 CopyStringRef(Mem + N + sizeof(size_t), NameRef); 93 return Mem; 94 } 95 96 namespace { 97 /// MemoryBufferMem - Named MemoryBuffer pointing to a block of memory. 98 template<typename MB> 99 class MemoryBufferMem : public MB { 100 public: 101 MemoryBufferMem(StringRef InputData, bool RequiresNullTerminator) { 102 MemoryBuffer::init(InputData.begin(), InputData.end(), 103 RequiresNullTerminator); 104 } 105 106 /// Disable sized deallocation for MemoryBufferMem, because it has 107 /// tail-allocated data. 108 void operator delete(void *p) { std::free(p); } 109 110 StringRef getBufferIdentifier() const override { 111 // The name is stored after the class itself. 112 return StringRef(reinterpret_cast<const char *>(this + 1) + sizeof(size_t), 113 *reinterpret_cast<const size_t *>(this + 1)); 114 } 115 116 MemoryBuffer::BufferKind getBufferKind() const override { 117 return MemoryBuffer::MemoryBuffer_Malloc; 118 } 119 }; 120 } // namespace 121 122 template <typename MB> 123 static ErrorOr<std::unique_ptr<MB>> 124 getFileAux(const Twine &Filename, uint64_t MapSize, uint64_t Offset, 125 bool IsText, bool RequiresNullTerminator, bool IsVolatile, 126 std::optional<Align> Alignment); 127 128 std::unique_ptr<MemoryBuffer> 129 MemoryBuffer::getMemBuffer(StringRef InputData, StringRef BufferName, 130 bool RequiresNullTerminator) { 131 auto *Ret = new (NamedBufferAlloc(BufferName)) 132 MemoryBufferMem<MemoryBuffer>(InputData, RequiresNullTerminator); 133 return std::unique_ptr<MemoryBuffer>(Ret); 134 } 135 136 std::unique_ptr<MemoryBuffer> 137 MemoryBuffer::getMemBuffer(MemoryBufferRef Ref, bool RequiresNullTerminator) { 138 return std::unique_ptr<MemoryBuffer>(getMemBuffer( 139 Ref.getBuffer(), Ref.getBufferIdentifier(), RequiresNullTerminator)); 140 } 141 142 static ErrorOr<std::unique_ptr<WritableMemoryBuffer>> 143 getMemBufferCopyImpl(StringRef InputData, const Twine &BufferName) { 144 auto Buf = 145 WritableMemoryBuffer::getNewUninitMemBuffer(InputData.size(), BufferName); 146 if (!Buf) 147 return make_error_code(errc::not_enough_memory); 148 // Calling memcpy with null src/dst is UB, and an empty StringRef is 149 // represented with {nullptr, 0}. 150 llvm::copy(InputData, Buf->getBufferStart()); 151 return std::move(Buf); 152 } 153 154 std::unique_ptr<MemoryBuffer> 155 MemoryBuffer::getMemBufferCopy(StringRef InputData, const Twine &BufferName) { 156 auto Buf = getMemBufferCopyImpl(InputData, BufferName); 157 if (Buf) 158 return std::move(*Buf); 159 return nullptr; 160 } 161 162 ErrorOr<std::unique_ptr<MemoryBuffer>> 163 MemoryBuffer::getFileOrSTDIN(const Twine &Filename, bool IsText, 164 bool RequiresNullTerminator, 165 std::optional<Align> Alignment) { 166 SmallString<256> NameBuf; 167 StringRef NameRef = Filename.toStringRef(NameBuf); 168 169 if (NameRef == "-") 170 return getSTDIN(); 171 return getFile(Filename, IsText, RequiresNullTerminator, 172 /*IsVolatile=*/false, Alignment); 173 } 174 175 ErrorOr<std::unique_ptr<MemoryBuffer>> 176 MemoryBuffer::getFileSlice(const Twine &FilePath, uint64_t MapSize, 177 uint64_t Offset, bool IsVolatile, 178 std::optional<Align> Alignment) { 179 return getFileAux<MemoryBuffer>(FilePath, MapSize, Offset, /*IsText=*/false, 180 /*RequiresNullTerminator=*/false, IsVolatile, 181 Alignment); 182 } 183 184 //===----------------------------------------------------------------------===// 185 // MemoryBuffer::getFile implementation. 186 //===----------------------------------------------------------------------===// 187 188 namespace { 189 190 template <typename MB> 191 constexpr sys::fs::mapped_file_region::mapmode Mapmode = 192 sys::fs::mapped_file_region::readonly; 193 template <> 194 constexpr sys::fs::mapped_file_region::mapmode Mapmode<MemoryBuffer> = 195 sys::fs::mapped_file_region::readonly; 196 template <> 197 constexpr sys::fs::mapped_file_region::mapmode Mapmode<WritableMemoryBuffer> = 198 sys::fs::mapped_file_region::priv; 199 template <> 200 constexpr sys::fs::mapped_file_region::mapmode 201 Mapmode<WriteThroughMemoryBuffer> = sys::fs::mapped_file_region::readwrite; 202 203 /// Memory maps a file descriptor using sys::fs::mapped_file_region. 204 /// 205 /// This handles converting the offset into a legal offset on the platform. 206 template<typename MB> 207 class MemoryBufferMMapFile : public MB { 208 sys::fs::mapped_file_region MFR; 209 210 static uint64_t getLegalMapOffset(uint64_t Offset) { 211 return Offset & ~(sys::fs::mapped_file_region::alignment() - 1); 212 } 213 214 static uint64_t getLegalMapSize(uint64_t Len, uint64_t Offset) { 215 return Len + (Offset - getLegalMapOffset(Offset)); 216 } 217 218 const char *getStart(uint64_t Len, uint64_t Offset) { 219 return MFR.const_data() + (Offset - getLegalMapOffset(Offset)); 220 } 221 222 public: 223 MemoryBufferMMapFile(bool RequiresNullTerminator, sys::fs::file_t FD, uint64_t Len, 224 uint64_t Offset, std::error_code &EC) 225 : MFR(FD, Mapmode<MB>, getLegalMapSize(Len, Offset), 226 getLegalMapOffset(Offset), EC) { 227 if (!EC) { 228 const char *Start = getStart(Len, Offset); 229 MemoryBuffer::init(Start, Start + Len, RequiresNullTerminator); 230 } 231 } 232 233 /// Disable sized deallocation for MemoryBufferMMapFile, because it has 234 /// tail-allocated data. 235 void operator delete(void *p) { std::free(p); } 236 237 StringRef getBufferIdentifier() const override { 238 // The name is stored after the class itself. 239 return StringRef(reinterpret_cast<const char *>(this + 1) + sizeof(size_t), 240 *reinterpret_cast<const size_t *>(this + 1)); 241 } 242 243 MemoryBuffer::BufferKind getBufferKind() const override { 244 return MemoryBuffer::MemoryBuffer_MMap; 245 } 246 247 void dontNeedIfMmap() override { MFR.dontNeed(); } 248 }; 249 } // namespace 250 251 static ErrorOr<std::unique_ptr<WritableMemoryBuffer>> 252 getMemoryBufferForStream(sys::fs::file_t FD, const Twine &BufferName) { 253 SmallString<sys::fs::DefaultReadChunkSize> Buffer; 254 if (Error E = sys::fs::readNativeFileToEOF(FD, Buffer)) 255 return errorToErrorCode(std::move(E)); 256 return getMemBufferCopyImpl(Buffer, BufferName); 257 } 258 259 ErrorOr<std::unique_ptr<MemoryBuffer>> 260 MemoryBuffer::getFile(const Twine &Filename, bool IsText, 261 bool RequiresNullTerminator, bool IsVolatile, 262 std::optional<Align> Alignment) { 263 return getFileAux<MemoryBuffer>(Filename, /*MapSize=*/-1, /*Offset=*/0, 264 IsText, RequiresNullTerminator, IsVolatile, 265 Alignment); 266 } 267 268 template <typename MB> 269 static ErrorOr<std::unique_ptr<MB>> 270 getOpenFileImpl(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize, 271 uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator, 272 bool IsVolatile, std::optional<Align> Alignment); 273 274 template <typename MB> 275 static ErrorOr<std::unique_ptr<MB>> 276 getFileAux(const Twine &Filename, uint64_t MapSize, uint64_t Offset, 277 bool IsText, bool RequiresNullTerminator, bool IsVolatile, 278 std::optional<Align> Alignment) { 279 Expected<sys::fs::file_t> FDOrErr = sys::fs::openNativeFileForRead( 280 Filename, IsText ? sys::fs::OF_TextWithCRLF : sys::fs::OF_None); 281 if (!FDOrErr) 282 return errorToErrorCode(FDOrErr.takeError()); 283 sys::fs::file_t FD = *FDOrErr; 284 auto Ret = getOpenFileImpl<MB>(FD, Filename, /*FileSize=*/-1, MapSize, Offset, 285 RequiresNullTerminator, IsVolatile, Alignment); 286 sys::fs::closeFile(FD); 287 return Ret; 288 } 289 290 ErrorOr<std::unique_ptr<WritableMemoryBuffer>> 291 WritableMemoryBuffer::getFile(const Twine &Filename, bool IsVolatile, 292 std::optional<Align> Alignment) { 293 return getFileAux<WritableMemoryBuffer>( 294 Filename, /*MapSize=*/-1, /*Offset=*/0, /*IsText=*/false, 295 /*RequiresNullTerminator=*/false, IsVolatile, Alignment); 296 } 297 298 ErrorOr<std::unique_ptr<WritableMemoryBuffer>> 299 WritableMemoryBuffer::getFileSlice(const Twine &Filename, uint64_t MapSize, 300 uint64_t Offset, bool IsVolatile, 301 std::optional<Align> Alignment) { 302 return getFileAux<WritableMemoryBuffer>( 303 Filename, MapSize, Offset, /*IsText=*/false, 304 /*RequiresNullTerminator=*/false, IsVolatile, Alignment); 305 } 306 307 std::unique_ptr<WritableMemoryBuffer> 308 WritableMemoryBuffer::getNewUninitMemBuffer(size_t Size, 309 const Twine &BufferName, 310 std::optional<Align> Alignment) { 311 using MemBuffer = MemoryBufferMem<WritableMemoryBuffer>; 312 313 // Use 16-byte alignment if no alignment is specified. 314 Align BufAlign = Alignment.value_or(Align(16)); 315 316 // Allocate space for the MemoryBuffer, the data and the name. It is important 317 // that MemoryBuffer and data are aligned so PointerIntPair works with them. 318 SmallString<256> NameBuf; 319 StringRef NameRef = BufferName.toStringRef(NameBuf); 320 321 size_t StringLen = sizeof(MemBuffer) + sizeof(size_t) + NameRef.size() + 1; 322 size_t RealLen = StringLen + Size + 1 + BufAlign.value(); 323 if (RealLen <= Size) // Check for rollover. 324 return nullptr; 325 // We use a call to malloc() rather than a call to a non-throwing operator 326 // new() because LLVM unconditionally installs an out of memory new handler 327 // when exceptions are disabled. This new handler intentionally crashes to 328 // aid with debugging, but that makes non-throwing new calls unhelpful. 329 // See MemoryBufferMem::operator delete() for the paired call to free(), and 330 // llvm::install_out_of_memory_new_handler() for the installation of the 331 // custom new handler. 332 char *Mem = static_cast<char *>(std::malloc(RealLen)); 333 if (!Mem) 334 return nullptr; 335 336 // The name is stored after the class itself. 337 *reinterpret_cast<size_t *>(Mem + sizeof(MemBuffer)) = NameRef.size(); 338 CopyStringRef(Mem + sizeof(MemBuffer) + sizeof(size_t), NameRef); 339 340 // The buffer begins after the name and must be aligned. 341 char *Buf = (char *)alignAddr(Mem + StringLen, BufAlign); 342 Buf[Size] = 0; // Null terminate buffer. 343 344 auto *Ret = new (Mem) MemBuffer(StringRef(Buf, Size), true); 345 return std::unique_ptr<WritableMemoryBuffer>(Ret); 346 } 347 348 std::unique_ptr<WritableMemoryBuffer> 349 WritableMemoryBuffer::getNewMemBuffer(size_t Size, const Twine &BufferName) { 350 auto SB = WritableMemoryBuffer::getNewUninitMemBuffer(Size, BufferName); 351 if (!SB) 352 return nullptr; 353 memset(SB->getBufferStart(), 0, Size); 354 return SB; 355 } 356 357 static bool shouldUseMmap(sys::fs::file_t FD, 358 size_t FileSize, 359 size_t MapSize, 360 off_t Offset, 361 bool RequiresNullTerminator, 362 int PageSize, 363 bool IsVolatile) { 364 // mmap may leave the buffer without null terminator if the file size changed 365 // by the time the last page is mapped in, so avoid it if the file size is 366 // likely to change. 367 if (IsVolatile && RequiresNullTerminator) 368 return false; 369 370 // We don't use mmap for small files because this can severely fragment our 371 // address space. 372 if (MapSize < 4 * 4096 || MapSize < (unsigned)PageSize) 373 return false; 374 375 if (!RequiresNullTerminator) 376 return true; 377 378 // If we don't know the file size, use fstat to find out. fstat on an open 379 // file descriptor is cheaper than stat on a random path. 380 // FIXME: this chunk of code is duplicated, but it avoids a fstat when 381 // RequiresNullTerminator = false and MapSize != -1. 382 if (FileSize == size_t(-1)) { 383 sys::fs::file_status Status; 384 if (sys::fs::status(FD, Status)) 385 return false; 386 FileSize = Status.getSize(); 387 } 388 389 // If we need a null terminator and the end of the map is inside the file, 390 // we cannot use mmap. 391 size_t End = Offset + MapSize; 392 assert(End <= FileSize); 393 if (End != FileSize) 394 return false; 395 396 // Don't try to map files that are exactly a multiple of the system page size 397 // if we need a null terminator. 398 if ((FileSize & (PageSize -1)) == 0) 399 return false; 400 401 #if defined(__CYGWIN__) 402 // Don't try to map files that are exactly a multiple of the physical page size 403 // if we need a null terminator. 404 // FIXME: We should reorganize again getPageSize() on Win32. 405 if ((FileSize & (4096 - 1)) == 0) 406 return false; 407 #endif 408 409 return true; 410 } 411 412 static ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>> 413 getReadWriteFile(const Twine &Filename, uint64_t FileSize, uint64_t MapSize, 414 uint64_t Offset) { 415 Expected<sys::fs::file_t> FDOrErr = sys::fs::openNativeFileForReadWrite( 416 Filename, sys::fs::CD_OpenExisting, sys::fs::OF_None); 417 if (!FDOrErr) 418 return errorToErrorCode(FDOrErr.takeError()); 419 sys::fs::file_t FD = *FDOrErr; 420 421 // Default is to map the full file. 422 if (MapSize == uint64_t(-1)) { 423 // If we don't know the file size, use fstat to find out. fstat on an open 424 // file descriptor is cheaper than stat on a random path. 425 if (FileSize == uint64_t(-1)) { 426 sys::fs::file_status Status; 427 std::error_code EC = sys::fs::status(FD, Status); 428 if (EC) 429 return EC; 430 431 // If this not a file or a block device (e.g. it's a named pipe 432 // or character device), we can't mmap it, so error out. 433 sys::fs::file_type Type = Status.type(); 434 if (Type != sys::fs::file_type::regular_file && 435 Type != sys::fs::file_type::block_file) 436 return make_error_code(errc::invalid_argument); 437 438 FileSize = Status.getSize(); 439 } 440 MapSize = FileSize; 441 } 442 443 std::error_code EC; 444 std::unique_ptr<WriteThroughMemoryBuffer> Result( 445 new (NamedBufferAlloc(Filename)) 446 MemoryBufferMMapFile<WriteThroughMemoryBuffer>(false, FD, MapSize, 447 Offset, EC)); 448 if (EC) 449 return EC; 450 return std::move(Result); 451 } 452 453 ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>> 454 WriteThroughMemoryBuffer::getFile(const Twine &Filename, int64_t FileSize) { 455 return getReadWriteFile(Filename, FileSize, FileSize, 0); 456 } 457 458 /// Map a subrange of the specified file as a WritableMemoryBuffer. 459 ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>> 460 WriteThroughMemoryBuffer::getFileSlice(const Twine &Filename, uint64_t MapSize, 461 uint64_t Offset) { 462 return getReadWriteFile(Filename, -1, MapSize, Offset); 463 } 464 465 template <typename MB> 466 static ErrorOr<std::unique_ptr<MB>> 467 getOpenFileImpl(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize, 468 uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator, 469 bool IsVolatile, std::optional<Align> Alignment) { 470 static int PageSize = sys::Process::getPageSizeEstimate(); 471 472 // Default is to map the full file. 473 if (MapSize == uint64_t(-1)) { 474 // If we don't know the file size, use fstat to find out. fstat on an open 475 // file descriptor is cheaper than stat on a random path. 476 if (FileSize == uint64_t(-1)) { 477 sys::fs::file_status Status; 478 std::error_code EC = sys::fs::status(FD, Status); 479 if (EC) 480 return EC; 481 482 // If this not a file or a block device (e.g. it's a named pipe 483 // or character device), we can't trust the size. Create the memory 484 // buffer by copying off the stream. 485 sys::fs::file_type Type = Status.type(); 486 if (Type != sys::fs::file_type::regular_file && 487 Type != sys::fs::file_type::block_file) 488 return getMemoryBufferForStream(FD, Filename); 489 490 FileSize = Status.getSize(); 491 } 492 MapSize = FileSize; 493 } 494 495 if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator, 496 PageSize, IsVolatile)) { 497 std::error_code EC; 498 std::unique_ptr<MB> Result( 499 new (NamedBufferAlloc(Filename)) MemoryBufferMMapFile<MB>( 500 RequiresNullTerminator, FD, MapSize, Offset, EC)); 501 if (!EC) 502 return std::move(Result); 503 } 504 505 #ifdef __MVS__ 506 // Set codepage auto-conversion for z/OS. 507 if (auto EC = llvm::enablezOSAutoConversion(FD)) 508 return EC; 509 #endif 510 511 auto Buf = 512 WritableMemoryBuffer::getNewUninitMemBuffer(MapSize, Filename, Alignment); 513 if (!Buf) { 514 // Failed to create a buffer. The only way it can fail is if 515 // new(std::nothrow) returns 0. 516 return make_error_code(errc::not_enough_memory); 517 } 518 519 // Read until EOF, zero-initialize the rest. 520 MutableArrayRef<char> ToRead = Buf->getBuffer(); 521 while (!ToRead.empty()) { 522 Expected<size_t> ReadBytes = 523 sys::fs::readNativeFileSlice(FD, ToRead, Offset); 524 if (!ReadBytes) 525 return errorToErrorCode(ReadBytes.takeError()); 526 if (*ReadBytes == 0) { 527 std::memset(ToRead.data(), 0, ToRead.size()); 528 break; 529 } 530 ToRead = ToRead.drop_front(*ReadBytes); 531 Offset += *ReadBytes; 532 } 533 534 return std::move(Buf); 535 } 536 537 ErrorOr<std::unique_ptr<MemoryBuffer>> 538 MemoryBuffer::getOpenFile(sys::fs::file_t FD, const Twine &Filename, 539 uint64_t FileSize, bool RequiresNullTerminator, 540 bool IsVolatile, std::optional<Align> Alignment) { 541 return getOpenFileImpl<MemoryBuffer>(FD, Filename, FileSize, FileSize, 0, 542 RequiresNullTerminator, IsVolatile, 543 Alignment); 544 } 545 546 ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getOpenFileSlice( 547 sys::fs::file_t FD, const Twine &Filename, uint64_t MapSize, int64_t Offset, 548 bool IsVolatile, std::optional<Align> Alignment) { 549 assert(MapSize != uint64_t(-1)); 550 return getOpenFileImpl<MemoryBuffer>(FD, Filename, -1, MapSize, Offset, false, 551 IsVolatile, Alignment); 552 } 553 554 ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getSTDIN() { 555 // Read in all of the data from stdin, we cannot mmap stdin. 556 // 557 // FIXME: That isn't necessarily true, we should try to mmap stdin and 558 // fallback if it fails. 559 sys::ChangeStdinMode(sys::fs::OF_Text); 560 561 return getMemoryBufferForStream(sys::fs::getStdinHandle(), "<stdin>"); 562 } 563 564 ErrorOr<std::unique_ptr<MemoryBuffer>> 565 MemoryBuffer::getFileAsStream(const Twine &Filename) { 566 Expected<sys::fs::file_t> FDOrErr = 567 sys::fs::openNativeFileForRead(Filename, sys::fs::OF_None); 568 if (!FDOrErr) 569 return errorToErrorCode(FDOrErr.takeError()); 570 sys::fs::file_t FD = *FDOrErr; 571 ErrorOr<std::unique_ptr<MemoryBuffer>> Ret = 572 getMemoryBufferForStream(FD, Filename); 573 sys::fs::closeFile(FD); 574 return Ret; 575 } 576 577 MemoryBufferRef MemoryBuffer::getMemBufferRef() const { 578 StringRef Data = getBuffer(); 579 StringRef Identifier = getBufferIdentifier(); 580 return MemoryBufferRef(Data, Identifier); 581 } 582 583 SmallVectorMemoryBuffer::~SmallVectorMemoryBuffer() = default; 584