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. |
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. |
65 | static void CopyStringRef(char *Memory, StringRef Data) { |
66 | if (!Data.empty()) |
67 | memcpy(dest: Memory, src: Data.data(), n: Data.size()); |
68 | Memory[Data.size()] = 0; // Null terminate string. |
69 | } |
70 | |
71 | namespace { |
72 | struct NamedBufferAlloc { |
73 | const Twine &Name; |
74 | NamedBufferAlloc(const Twine &Name) : Name(Name) {} |
75 | }; |
76 | } // namespace |
77 | |
78 | void *operator new(size_t N, const NamedBufferAlloc &Alloc) { |
79 | SmallString<256> NameBuf; |
80 | StringRef NameRef = Alloc.Name.toStringRef(Out&: 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(size: N + sizeof(size_t) + NameRef.size() + 1)); |
90 | if (!Mem) |
91 | llvm::report_bad_alloc_error(Reason: "Allocation failed" ); |
92 | *reinterpret_cast<size_t *>(Mem + N) = NameRef.size(); |
93 | CopyStringRef(Memory: Mem + N + sizeof(size_t), Data: 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: |
102 | MemoryBufferMem(StringRef InputData, bool RequiresNullTerminator) { |
103 | MemoryBuffer::init(BufStart: InputData.begin(), BufEnd: InputData.end(), |
104 | RequiresNullTerminator); |
105 | } |
106 | |
107 | /// Disable sized deallocation for MemoryBufferMem, because it has |
108 | /// tail-allocated data. |
109 | void operator delete(void *p) { std::free(ptr: p); } |
110 | |
111 | 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 | |
117 | 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> |
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> |
138 | MemoryBuffer::getMemBuffer(MemoryBufferRef Ref, bool RequiresNullTerminator) { |
139 | return std::unique_ptr<MemoryBuffer>(getMemBuffer( |
140 | InputData: Ref.getBuffer(), BufferName: Ref.getBufferIdentifier(), RequiresNullTerminator)); |
141 | } |
142 | |
143 | static ErrorOr<std::unique_ptr<WritableMemoryBuffer>> |
144 | getMemBufferCopyImpl(StringRef InputData, const Twine &BufferName) { |
145 | auto Buf = |
146 | WritableMemoryBuffer::getNewUninitMemBuffer(Size: InputData.size(), BufferName); |
147 | if (!Buf) |
148 | return make_error_code(E: 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(Range&: InputData, Out: Buf->getBufferStart()); |
152 | return std::move(Buf); |
153 | } |
154 | |
155 | std::unique_ptr<MemoryBuffer> |
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>> |
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(Out&: 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>> |
177 | MemoryBuffer::getFileSlice(const Twine &FilePath, uint64_t MapSize, |
178 | uint64_t Offset, bool IsVolatile, |
179 | std::optional<Align> Alignment) { |
180 | return getFileAux<MemoryBuffer>(Filename: 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 | |
211 | static uint64_t getLegalMapOffset(uint64_t Offset) { |
212 | return Offset & ~(sys::fs::mapped_file_region::alignment() - 1); |
213 | } |
214 | |
215 | static uint64_t getLegalMapSize(uint64_t Len, uint64_t Offset) { |
216 | return Len + (Offset - getLegalMapOffset(Offset)); |
217 | } |
218 | |
219 | const char *getStart(uint64_t Len, uint64_t Offset) { |
220 | return MFR.const_data() + (Offset - getLegalMapOffset(Offset)); |
221 | } |
222 | |
223 | public: |
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(BufStart: Start, BufEnd: Start + Len, RequiresNullTerminator); |
231 | } |
232 | } |
233 | |
234 | /// Disable sized deallocation for MemoryBufferMMapFile, because it has |
235 | /// tail-allocated data. |
236 | void operator delete(void *p) { std::free(ptr: p); } |
237 | |
238 | 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 | |
244 | MemoryBuffer::BufferKind getBufferKind() const override { |
245 | return MemoryBuffer::MemoryBuffer_MMap; |
246 | } |
247 | |
248 | void dontNeedIfMmap() override { MFR.dontNeed(); } |
249 | }; |
250 | } // namespace |
251 | |
252 | static ErrorOr<std::unique_ptr<WritableMemoryBuffer>> |
253 | getMemoryBufferForStream(sys::fs::file_t FD, const Twine &BufferName) { |
254 | SmallString<sys::fs::DefaultReadChunkSize> Buffer; |
255 | if (Error E = sys::fs::readNativeFileToEOF(FileHandle: FD, Buffer)) |
256 | return errorToErrorCode(Err: std::move(E)); |
257 | return getMemBufferCopyImpl(InputData: Buffer, BufferName); |
258 | } |
259 | |
260 | ErrorOr<std::unique_ptr<MemoryBuffer>> |
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>> |
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 | Name: Filename, Flags: IsText ? sys::fs::OF_TextWithCRLF : sys::fs::OF_None); |
282 | if (!FDOrErr) |
283 | return errorToErrorCode(Err: 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(F&: FD); |
288 | return Ret; |
289 | } |
290 | |
291 | ErrorOr<std::unique_ptr<WritableMemoryBuffer>> |
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>> |
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> |
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(u: 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(Out&: 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(size: 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(Memory: Mem + sizeof(MemBuffer) + sizeof(size_t), Data: NameRef); |
340 | |
341 | // The buffer begins after the name and must be aligned. |
342 | char *Buf = (char *)alignAddr(Addr: Mem + StringLen, Alignment: 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> |
350 | WritableMemoryBuffer::getNewMemBuffer(size_t Size, const Twine &BufferName) { |
351 | auto SB = WritableMemoryBuffer::getNewUninitMemBuffer(Size, BufferName); |
352 | if (!SB) |
353 | return nullptr; |
354 | memset(s: SB->getBufferStart(), c: 0, n: Size); |
355 | return SB; |
356 | } |
357 | |
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, Result&: 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>> |
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 | Name: Filename, Disp: sys::fs::CD_OpenExisting, Flags: sys::fs::OF_None); |
418 | if (!FDOrErr) |
419 | return errorToErrorCode(Err: 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, Result&: 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(E: 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>> |
455 | WriteThroughMemoryBuffer::getFile(const Twine &Filename, int64_t FileSize) { |
456 | return getReadWriteFile(Filename, FileSize, MapSize: FileSize, Offset: 0); |
457 | } |
458 | |
459 | /// Map a subrange of the specified file as a WritableMemoryBuffer. |
460 | ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>> |
461 | WriteThroughMemoryBuffer::getFileSlice(const Twine &Filename, uint64_t MapSize, |
462 | uint64_t Offset) { |
463 | return getReadWriteFile(Filename, FileSize: -1, MapSize, Offset); |
464 | } |
465 | |
466 | template <typename MB> |
467 | static ErrorOr<std::unique_ptr<MB>> |
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, Result&: 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, BufferName: 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(Size: MapSize, BufferName: 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(E: 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(FileHandle: FD, Buf: ToRead, Offset); |
525 | if (!ReadBytes) |
526 | return errorToErrorCode(Err: ReadBytes.takeError()); |
527 | if (*ReadBytes == 0) { |
528 | std::memset(s: ToRead.data(), c: 0, n: ToRead.size()); |
529 | break; |
530 | } |
531 | ToRead = ToRead.drop_front(N: *ReadBytes); |
532 | Offset += *ReadBytes; |
533 | } |
534 | |
535 | return std::move(Buf); |
536 | } |
537 | |
538 | ErrorOr<std::unique_ptr<MemoryBuffer>> |
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, MapSize: FileSize, Offset: 0, |
543 | RequiresNullTerminator, IsVolatile, |
544 | Alignment); |
545 | } |
546 | |
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, FileSize: -1, MapSize, Offset, RequiresNullTerminator: false, |
552 | IsVolatile, Alignment); |
553 | } |
554 | |
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(Flags: sys::fs::OF_Text); |
561 | |
562 | return getMemoryBufferForStream(FD: sys::fs::getStdinHandle(), BufferName: "<stdin>" ); |
563 | } |
564 | |
565 | ErrorOr<std::unique_ptr<MemoryBuffer>> |
566 | MemoryBuffer::getFileAsStream(const Twine &Filename) { |
567 | Expected<sys::fs::file_t> FDOrErr = |
568 | sys::fs::openNativeFileForRead(Name: Filename, Flags: sys::fs::OF_None); |
569 | if (!FDOrErr) |
570 | return errorToErrorCode(Err: FDOrErr.takeError()); |
571 | sys::fs::file_t FD = *FDOrErr; |
572 | ErrorOr<std::unique_ptr<MemoryBuffer>> Ret = |
573 | getMemoryBufferForStream(FD, BufferName: Filename); |
574 | sys::fs::closeFile(F&: FD); |
575 | return Ret; |
576 | } |
577 | |
578 | MemoryBufferRef MemoryBuffer::getMemBufferRef() const { |
579 | StringRef Data = getBuffer(); |
580 | StringRef Identifier = getBufferIdentifier(); |
581 | return MemoryBufferRef(Data, Identifier); |
582 | } |
583 | |
584 | SmallVectorMemoryBuffer::~SmallVectorMemoryBuffer() = default; |
585 | |