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