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