xref: /src/contrib/llvm-project/llvm/lib/Support/MemoryBuffer.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1009b1c42SEd Schouten //===--- MemoryBuffer.cpp - Memory Buffer implementation ------------------===//
2009b1c42SEd Schouten //
3e6d15924SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4e6d15924SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5e6d15924SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6009b1c42SEd Schouten //
7009b1c42SEd Schouten //===----------------------------------------------------------------------===//
8009b1c42SEd Schouten //
9009b1c42SEd Schouten //  This file implements the MemoryBuffer interface.
10009b1c42SEd Schouten //
11009b1c42SEd Schouten //===----------------------------------------------------------------------===//
12009b1c42SEd Schouten 
13009b1c42SEd Schouten #include "llvm/Support/MemoryBuffer.h"
147fa27ce4SDimitry Andric #include "llvm/ADT/STLExtras.h"
15009b1c42SEd Schouten #include "llvm/ADT/SmallString.h"
1663faed5bSDimitry Andric #include "llvm/Config/config.h"
17e3b55780SDimitry Andric #include "llvm/Support/Alignment.h"
18145449b1SDimitry Andric #include "llvm/Support/Errc.h"
196f8fc217SDimitry Andric #include "llvm/Support/Error.h"
206f8fc217SDimitry Andric #include "llvm/Support/ErrorHandling.h"
2158b69754SDimitry Andric #include "llvm/Support/FileSystem.h"
224a16efa3SDimitry Andric #include "llvm/Support/MathExtras.h"
23cf099d11SDimitry Andric #include "llvm/Support/Process.h"
24cf099d11SDimitry Andric #include "llvm/Support/Program.h"
25eb11fae6SDimitry Andric #include "llvm/Support/SmallVectorMemoryBuffer.h"
267fa27ce4SDimitry Andric #include <algorithm>
27009b1c42SEd Schouten #include <cassert>
28009b1c42SEd Schouten #include <cstring>
29cf099d11SDimitry Andric #include <new>
304a16efa3SDimitry Andric #include <sys/types.h>
315ca98fd9SDimitry Andric #include <system_error>
32009b1c42SEd Schouten #if !defined(_MSC_VER) && !defined(__MINGW32__)
33009b1c42SEd Schouten #include <unistd.h>
34009b1c42SEd Schouten #else
35009b1c42SEd Schouten #include <io.h>
36009b1c42SEd Schouten #endif
37145449b1SDimitry Andric 
38145449b1SDimitry Andric #ifdef __MVS__
39145449b1SDimitry Andric #include "llvm/Support/AutoConvert.h"
40145449b1SDimitry Andric #endif
41009b1c42SEd Schouten using namespace llvm;
42009b1c42SEd Schouten 
43009b1c42SEd Schouten //===----------------------------------------------------------------------===//
44009b1c42SEd Schouten // MemoryBuffer implementation itself.
45009b1c42SEd Schouten //===----------------------------------------------------------------------===//
46009b1c42SEd Schouten 
47145449b1SDimitry Andric MemoryBuffer::~MemoryBuffer() = default;
48009b1c42SEd Schouten 
49009b1c42SEd Schouten /// init - Initialize this MemoryBuffer as a reference to externally allocated
50009b1c42SEd Schouten /// memory, memory that we know is already null terminated.
init(const char * BufStart,const char * BufEnd,bool RequiresNullTerminator)516b943ff3SDimitry Andric void MemoryBuffer::init(const char *BufStart, const char *BufEnd,
526b943ff3SDimitry Andric                         bool RequiresNullTerminator) {
536b943ff3SDimitry Andric   assert((!RequiresNullTerminator || BufEnd[0] == 0) &&
546b943ff3SDimitry Andric          "Buffer is not null terminated!");
55009b1c42SEd Schouten   BufferStart = BufStart;
56009b1c42SEd Schouten   BufferEnd = BufEnd;
57009b1c42SEd Schouten }
58009b1c42SEd Schouten 
59009b1c42SEd Schouten //===----------------------------------------------------------------------===//
60009b1c42SEd Schouten // MemoryBufferMem implementation.
61009b1c42SEd Schouten //===----------------------------------------------------------------------===//
62009b1c42SEd Schouten 
6366e41e3cSRoman Divacky /// CopyStringRef - Copies contents of a StringRef into a block of memory and
6466e41e3cSRoman Divacky /// null-terminates it.
CopyStringRef(char * Memory,StringRef Data)6566e41e3cSRoman Divacky static void CopyStringRef(char *Memory, StringRef Data) {
6669156b4cSDimitry Andric   if (!Data.empty())
6766e41e3cSRoman Divacky     memcpy(Memory, Data.data(), Data.size());
6866e41e3cSRoman Divacky   Memory[Data.size()] = 0; // Null terminate string.
6966e41e3cSRoman Divacky }
7066e41e3cSRoman Divacky 
714a16efa3SDimitry Andric namespace {
724a16efa3SDimitry Andric struct NamedBufferAlloc {
7367c32a98SDimitry Andric   const Twine &Name;
NamedBufferAlloc__anon53ba17640111::NamedBufferAlloc7467c32a98SDimitry Andric   NamedBufferAlloc(const Twine &Name) : Name(Name) {}
754a16efa3SDimitry Andric };
76344a3780SDimitry Andric } // namespace
774a16efa3SDimitry Andric 
operator new(size_t N,const NamedBufferAlloc & Alloc)784a16efa3SDimitry Andric void *operator new(size_t N, const NamedBufferAlloc &Alloc) {
7967c32a98SDimitry Andric   SmallString<256> NameBuf;
8067c32a98SDimitry Andric   StringRef NameRef = Alloc.Name.toStringRef(NameBuf);
8167c32a98SDimitry Andric 
82ac9a064cSDimitry Andric   // We use malloc() and manually handle it returning null instead of calling
83ac9a064cSDimitry Andric   // operator new because we need all uses of NamedBufferAlloc to be
84ac9a064cSDimitry Andric   // deallocated with a call to free() due to needing to use malloc() in
85ac9a064cSDimitry Andric   // WritableMemoryBuffer::getNewUninitMemBuffer() to work around the out-of-
86ac9a064cSDimitry Andric   // memory handler installed by default in LLVM. See operator delete() member
87ac9a064cSDimitry Andric   // functions within this file for the paired call to free().
88ac9a064cSDimitry Andric   char *Mem =
89ac9a064cSDimitry Andric       static_cast<char *>(std::malloc(N + sizeof(size_t) + NameRef.size() + 1));
90ac9a064cSDimitry Andric   if (!Mem)
91ac9a064cSDimitry Andric     llvm::report_bad_alloc_error("Allocation failed");
92e3b55780SDimitry Andric   *reinterpret_cast<size_t *>(Mem + N) = NameRef.size();
93e3b55780SDimitry Andric   CopyStringRef(Mem + N + sizeof(size_t), NameRef);
944a16efa3SDimitry Andric   return Mem;
9566e41e3cSRoman Divacky }
9666e41e3cSRoman Divacky 
97009b1c42SEd Schouten namespace {
9866e41e3cSRoman Divacky /// MemoryBufferMem - Named MemoryBuffer pointing to a block of memory.
99c7dac04cSDimitry Andric template<typename MB>
100c7dac04cSDimitry Andric class MemoryBufferMem : public MB {
101009b1c42SEd Schouten public:
MemoryBufferMem(StringRef InputData,bool RequiresNullTerminator)1026b943ff3SDimitry Andric   MemoryBufferMem(StringRef InputData, bool RequiresNullTerminator) {
103c7dac04cSDimitry Andric     MemoryBuffer::init(InputData.begin(), InputData.end(),
104c7dac04cSDimitry Andric                        RequiresNullTerminator);
105009b1c42SEd Schouten   }
106009b1c42SEd Schouten 
10701095a5dSDimitry Andric   /// Disable sized deallocation for MemoryBufferMem, because it has
10801095a5dSDimitry Andric   /// tail-allocated data.
operator delete(void * p)109ac9a064cSDimitry Andric   void operator delete(void *p) { std::free(p); }
11001095a5dSDimitry Andric 
getBufferIdentifier() const111b915e9e0SDimitry Andric   StringRef getBufferIdentifier() const override {
11266e41e3cSRoman Divacky     // The name is stored after the class itself.
113e3b55780SDimitry Andric     return StringRef(reinterpret_cast<const char *>(this + 1) + sizeof(size_t),
114e3b55780SDimitry Andric                      *reinterpret_cast<const size_t *>(this + 1));
115009b1c42SEd Schouten   }
1166b943ff3SDimitry Andric 
getBufferKind() const117c7dac04cSDimitry Andric   MemoryBuffer::BufferKind getBufferKind() const override {
118c7dac04cSDimitry Andric     return MemoryBuffer::MemoryBuffer_Malloc;
1196b943ff3SDimitry Andric   }
120009b1c42SEd Schouten };
121344a3780SDimitry Andric } // namespace
122009b1c42SEd Schouten 
123c7dac04cSDimitry Andric template <typename MB>
124c7dac04cSDimitry Andric static ErrorOr<std::unique_ptr<MB>>
125344a3780SDimitry Andric getFileAux(const Twine &Filename, uint64_t MapSize, uint64_t Offset,
126e3b55780SDimitry Andric            bool IsText, bool RequiresNullTerminator, bool IsVolatile,
127e3b55780SDimitry Andric            std::optional<Align> Alignment);
12867c32a98SDimitry Andric 
12967c32a98SDimitry Andric std::unique_ptr<MemoryBuffer>
getMemBuffer(StringRef InputData,StringRef BufferName,bool RequiresNullTerminator)13067c32a98SDimitry Andric MemoryBuffer::getMemBuffer(StringRef InputData, StringRef BufferName,
1316b943ff3SDimitry Andric                            bool RequiresNullTerminator) {
13267c32a98SDimitry Andric   auto *Ret = new (NamedBufferAlloc(BufferName))
133c7dac04cSDimitry Andric       MemoryBufferMem<MemoryBuffer>(InputData, RequiresNullTerminator);
13467c32a98SDimitry Andric   return std::unique_ptr<MemoryBuffer>(Ret);
135009b1c42SEd Schouten }
136009b1c42SEd Schouten 
13767c32a98SDimitry Andric std::unique_ptr<MemoryBuffer>
getMemBuffer(MemoryBufferRef Ref,bool RequiresNullTerminator)13867c32a98SDimitry Andric MemoryBuffer::getMemBuffer(MemoryBufferRef Ref, bool RequiresNullTerminator) {
13967c32a98SDimitry Andric   return std::unique_ptr<MemoryBuffer>(getMemBuffer(
14067c32a98SDimitry Andric       Ref.getBuffer(), Ref.getBufferIdentifier(), RequiresNullTerminator));
14167c32a98SDimitry Andric }
14267c32a98SDimitry Andric 
143c7dac04cSDimitry Andric static ErrorOr<std::unique_ptr<WritableMemoryBuffer>>
getMemBufferCopyImpl(StringRef InputData,const Twine & BufferName)144c7dac04cSDimitry Andric getMemBufferCopyImpl(StringRef InputData, const Twine &BufferName) {
1457fa27ce4SDimitry Andric   auto Buf =
1467fa27ce4SDimitry Andric       WritableMemoryBuffer::getNewUninitMemBuffer(InputData.size(), BufferName);
14767c32a98SDimitry Andric   if (!Buf)
148c7dac04cSDimitry Andric     return make_error_code(errc::not_enough_memory);
1497fa27ce4SDimitry Andric   // Calling memcpy with null src/dst is UB, and an empty StringRef is
1507fa27ce4SDimitry Andric   // represented with {nullptr, 0}.
1517fa27ce4SDimitry Andric   llvm::copy(InputData, Buf->getBufferStart());
152c7dac04cSDimitry Andric   return std::move(Buf);
153009b1c42SEd Schouten }
154009b1c42SEd Schouten 
15567c32a98SDimitry Andric std::unique_ptr<MemoryBuffer>
getMemBufferCopy(StringRef InputData,const Twine & BufferName)156c7dac04cSDimitry Andric MemoryBuffer::getMemBufferCopy(StringRef InputData, const Twine &BufferName) {
157c7dac04cSDimitry Andric   auto Buf = getMemBufferCopyImpl(InputData, BufferName);
158c7dac04cSDimitry Andric   if (Buf)
159c7dac04cSDimitry Andric     return std::move(*Buf);
16067c32a98SDimitry Andric   return nullptr;
161009b1c42SEd Schouten }
162009b1c42SEd Schouten 
1635ca98fd9SDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>>
getFileOrSTDIN(const Twine & Filename,bool IsText,bool RequiresNullTerminator,std::optional<Align> Alignment)164344a3780SDimitry Andric MemoryBuffer::getFileOrSTDIN(const Twine &Filename, bool IsText,
165e3b55780SDimitry Andric                              bool RequiresNullTerminator,
166e3b55780SDimitry Andric                              std::optional<Align> Alignment) {
16767c32a98SDimitry Andric   SmallString<256> NameBuf;
16867c32a98SDimitry Andric   StringRef NameRef = Filename.toStringRef(NameBuf);
16967c32a98SDimitry Andric 
17067c32a98SDimitry Andric   if (NameRef == "-")
1715ca98fd9SDimitry Andric     return getSTDIN();
172344a3780SDimitry Andric   return getFile(Filename, IsText, RequiresNullTerminator,
173e3b55780SDimitry Andric                  /*IsVolatile=*/false, Alignment);
17466e41e3cSRoman Divacky }
17566e41e3cSRoman Divacky 
17667c32a98SDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>>
getFileSlice(const Twine & FilePath,uint64_t MapSize,uint64_t Offset,bool IsVolatile,std::optional<Align> Alignment)17767c32a98SDimitry Andric MemoryBuffer::getFileSlice(const Twine &FilePath, uint64_t MapSize,
178e3b55780SDimitry Andric                            uint64_t Offset, bool IsVolatile,
179e3b55780SDimitry Andric                            std::optional<Align> Alignment) {
180344a3780SDimitry Andric   return getFileAux<MemoryBuffer>(FilePath, MapSize, Offset, /*IsText=*/false,
181e3b55780SDimitry Andric                                   /*RequiresNullTerminator=*/false, IsVolatile,
182e3b55780SDimitry Andric                                   Alignment);
18367c32a98SDimitry Andric }
18467c32a98SDimitry Andric 
185009b1c42SEd Schouten //===----------------------------------------------------------------------===//
186009b1c42SEd Schouten // MemoryBuffer::getFile implementation.
187009b1c42SEd Schouten //===----------------------------------------------------------------------===//
188009b1c42SEd Schouten 
189009b1c42SEd Schouten namespace {
190cfca06d7SDimitry Andric 
191cfca06d7SDimitry Andric template <typename MB>
192cfca06d7SDimitry Andric constexpr sys::fs::mapped_file_region::mapmode Mapmode =
193cfca06d7SDimitry Andric     sys::fs::mapped_file_region::readonly;
194cfca06d7SDimitry Andric template <>
195cfca06d7SDimitry Andric constexpr sys::fs::mapped_file_region::mapmode Mapmode<MemoryBuffer> =
196cfca06d7SDimitry Andric     sys::fs::mapped_file_region::readonly;
197cfca06d7SDimitry Andric template <>
198cfca06d7SDimitry Andric constexpr sys::fs::mapped_file_region::mapmode Mapmode<WritableMemoryBuffer> =
199cfca06d7SDimitry Andric     sys::fs::mapped_file_region::priv;
200cfca06d7SDimitry Andric template <>
201cfca06d7SDimitry Andric constexpr sys::fs::mapped_file_region::mapmode
202cfca06d7SDimitry Andric     Mapmode<WriteThroughMemoryBuffer> = sys::fs::mapped_file_region::readwrite;
203cfca06d7SDimitry Andric 
204eb11fae6SDimitry Andric /// Memory maps a file descriptor using sys::fs::mapped_file_region.
2054a16efa3SDimitry Andric ///
2064a16efa3SDimitry Andric /// This handles converting the offset into a legal offset on the platform.
207c7dac04cSDimitry Andric template<typename MB>
208c7dac04cSDimitry Andric class MemoryBufferMMapFile : public MB {
2094a16efa3SDimitry Andric   sys::fs::mapped_file_region MFR;
2104a16efa3SDimitry Andric 
getLegalMapOffset(uint64_t Offset)2114a16efa3SDimitry Andric   static uint64_t getLegalMapOffset(uint64_t Offset) {
2124a16efa3SDimitry Andric     return Offset & ~(sys::fs::mapped_file_region::alignment() - 1);
2134a16efa3SDimitry Andric   }
2144a16efa3SDimitry Andric 
getLegalMapSize(uint64_t Len,uint64_t Offset)2154a16efa3SDimitry Andric   static uint64_t getLegalMapSize(uint64_t Len, uint64_t Offset) {
2164a16efa3SDimitry Andric     return Len + (Offset - getLegalMapOffset(Offset));
2174a16efa3SDimitry Andric   }
2184a16efa3SDimitry Andric 
getStart(uint64_t Len,uint64_t Offset)2194a16efa3SDimitry Andric   const char *getStart(uint64_t Len, uint64_t Offset) {
2204a16efa3SDimitry Andric     return MFR.const_data() + (Offset - getLegalMapOffset(Offset));
2214a16efa3SDimitry Andric   }
2224a16efa3SDimitry Andric 
223009b1c42SEd Schouten public:
MemoryBufferMMapFile(bool RequiresNullTerminator,sys::fs::file_t FD,uint64_t Len,uint64_t Offset,std::error_code & EC)224e6d15924SDimitry Andric   MemoryBufferMMapFile(bool RequiresNullTerminator, sys::fs::file_t FD, uint64_t Len,
22567c32a98SDimitry Andric                        uint64_t Offset, std::error_code &EC)
226cfca06d7SDimitry Andric       : MFR(FD, Mapmode<MB>, getLegalMapSize(Len, Offset),
227eb11fae6SDimitry Andric             getLegalMapOffset(Offset), EC) {
2284a16efa3SDimitry Andric     if (!EC) {
2294a16efa3SDimitry Andric       const char *Start = getStart(Len, Offset);
230c7dac04cSDimitry Andric       MemoryBuffer::init(Start, Start + Len, RequiresNullTerminator);
2314a16efa3SDimitry Andric     }
2324a16efa3SDimitry Andric   }
233009b1c42SEd Schouten 
23401095a5dSDimitry Andric   /// Disable sized deallocation for MemoryBufferMMapFile, because it has
23501095a5dSDimitry Andric   /// tail-allocated data.
operator delete(void * p)236ac9a064cSDimitry Andric   void operator delete(void *p) { std::free(p); }
23701095a5dSDimitry Andric 
getBufferIdentifier() const238b915e9e0SDimitry Andric   StringRef getBufferIdentifier() const override {
2394a16efa3SDimitry Andric     // The name is stored after the class itself.
240e3b55780SDimitry Andric     return StringRef(reinterpret_cast<const char *>(this + 1) + sizeof(size_t),
241e3b55780SDimitry Andric                      *reinterpret_cast<const size_t *>(this + 1));
2426b943ff3SDimitry Andric   }
2436b943ff3SDimitry Andric 
getBufferKind() const244c7dac04cSDimitry Andric   MemoryBuffer::BufferKind getBufferKind() const override {
245c7dac04cSDimitry Andric     return MemoryBuffer::MemoryBuffer_MMap;
246009b1c42SEd Schouten   }
2476f8fc217SDimitry Andric 
dontNeedIfMmap()2486f8fc217SDimitry Andric   void dontNeedIfMmap() override { MFR.dontNeed(); }
249009b1c42SEd Schouten };
250344a3780SDimitry Andric } // namespace
251009b1c42SEd Schouten 
252c7dac04cSDimitry Andric static ErrorOr<std::unique_ptr<WritableMemoryBuffer>>
getMemoryBufferForStream(sys::fs::file_t FD,const Twine & BufferName)253e6d15924SDimitry Andric getMemoryBufferForStream(sys::fs::file_t FD, const Twine &BufferName) {
2546f8fc217SDimitry Andric   SmallString<sys::fs::DefaultReadChunkSize> Buffer;
2556f8fc217SDimitry Andric   if (Error E = sys::fs::readNativeFileToEOF(FD, Buffer))
2566f8fc217SDimitry Andric     return errorToErrorCode(std::move(E));
257c7dac04cSDimitry Andric   return getMemBufferCopyImpl(Buffer, BufferName);
258522600a2SDimitry Andric }
259522600a2SDimitry Andric 
2605ca98fd9SDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>>
getFile(const Twine & Filename,bool IsText,bool RequiresNullTerminator,bool IsVolatile,std::optional<Align> Alignment)261344a3780SDimitry Andric MemoryBuffer::getFile(const Twine &Filename, bool IsText,
262e3b55780SDimitry Andric                       bool RequiresNullTerminator, bool IsVolatile,
263e3b55780SDimitry Andric                       std::optional<Align> Alignment) {
264344a3780SDimitry Andric   return getFileAux<MemoryBuffer>(Filename, /*MapSize=*/-1, /*Offset=*/0,
265e3b55780SDimitry Andric                                   IsText, RequiresNullTerminator, IsVolatile,
266e3b55780SDimitry Andric                                   Alignment);
26766e41e3cSRoman Divacky }
26866e41e3cSRoman Divacky 
269c7dac04cSDimitry Andric template <typename MB>
270c7dac04cSDimitry Andric static ErrorOr<std::unique_ptr<MB>>
271e6d15924SDimitry Andric getOpenFileImpl(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize,
2725ca98fd9SDimitry Andric                 uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator,
273e3b55780SDimitry Andric                 bool IsVolatile, std::optional<Align> Alignment);
274f8af5cf6SDimitry Andric 
275c7dac04cSDimitry Andric template <typename MB>
276c7dac04cSDimitry Andric 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)277344a3780SDimitry Andric getFileAux(const Twine &Filename, uint64_t MapSize, uint64_t Offset,
278e3b55780SDimitry Andric            bool IsText, bool RequiresNullTerminator, bool IsVolatile,
279e3b55780SDimitry Andric            std::optional<Align> Alignment) {
280344a3780SDimitry Andric   Expected<sys::fs::file_t> FDOrErr = sys::fs::openNativeFileForRead(
281344a3780SDimitry Andric       Filename, IsText ? sys::fs::OF_TextWithCRLF : sys::fs::OF_None);
282e6d15924SDimitry Andric   if (!FDOrErr)
283e6d15924SDimitry Andric     return errorToErrorCode(FDOrErr.takeError());
284e6d15924SDimitry Andric   sys::fs::file_t FD = *FDOrErr;
285344a3780SDimitry Andric   auto Ret = getOpenFileImpl<MB>(FD, Filename, /*FileSize=*/-1, MapSize, Offset,
286e3b55780SDimitry Andric                                  RequiresNullTerminator, IsVolatile, Alignment);
287e6d15924SDimitry Andric   sys::fs::closeFile(FD);
2885ca98fd9SDimitry Andric   return Ret;
289cf099d11SDimitry Andric }
290009b1c42SEd Schouten 
291c7dac04cSDimitry Andric ErrorOr<std::unique_ptr<WritableMemoryBuffer>>
getFile(const Twine & Filename,bool IsVolatile,std::optional<Align> Alignment)292e3b55780SDimitry Andric WritableMemoryBuffer::getFile(const Twine &Filename, bool IsVolatile,
293e3b55780SDimitry Andric                               std::optional<Align> Alignment) {
294344a3780SDimitry Andric   return getFileAux<WritableMemoryBuffer>(
295344a3780SDimitry Andric       Filename, /*MapSize=*/-1, /*Offset=*/0, /*IsText=*/false,
296e3b55780SDimitry Andric       /*RequiresNullTerminator=*/false, IsVolatile, Alignment);
297c7dac04cSDimitry Andric }
298c7dac04cSDimitry Andric 
299c7dac04cSDimitry Andric ErrorOr<std::unique_ptr<WritableMemoryBuffer>>
getFileSlice(const Twine & Filename,uint64_t MapSize,uint64_t Offset,bool IsVolatile,std::optional<Align> Alignment)300c7dac04cSDimitry Andric WritableMemoryBuffer::getFileSlice(const Twine &Filename, uint64_t MapSize,
301e3b55780SDimitry Andric                                    uint64_t Offset, bool IsVolatile,
302e3b55780SDimitry Andric                                    std::optional<Align> Alignment) {
303344a3780SDimitry Andric   return getFileAux<WritableMemoryBuffer>(
304344a3780SDimitry Andric       Filename, MapSize, Offset, /*IsText=*/false,
305e3b55780SDimitry Andric       /*RequiresNullTerminator=*/false, IsVolatile, Alignment);
306c7dac04cSDimitry Andric }
307c7dac04cSDimitry Andric 
308c7dac04cSDimitry Andric std::unique_ptr<WritableMemoryBuffer>
getNewUninitMemBuffer(size_t Size,const Twine & BufferName,std::optional<Align> Alignment)309e3b55780SDimitry Andric WritableMemoryBuffer::getNewUninitMemBuffer(size_t Size,
310e3b55780SDimitry Andric                                             const Twine &BufferName,
311e3b55780SDimitry Andric                                             std::optional<Align> Alignment) {
312c7dac04cSDimitry Andric   using MemBuffer = MemoryBufferMem<WritableMemoryBuffer>;
313e3b55780SDimitry Andric 
314e3b55780SDimitry Andric   // Use 16-byte alignment if no alignment is specified.
315e3b55780SDimitry Andric   Align BufAlign = Alignment.value_or(Align(16));
316e3b55780SDimitry Andric 
317c7dac04cSDimitry Andric   // Allocate space for the MemoryBuffer, the data and the name. It is important
318c7dac04cSDimitry Andric   // that MemoryBuffer and data are aligned so PointerIntPair works with them.
319c7dac04cSDimitry Andric   SmallString<256> NameBuf;
320c7dac04cSDimitry Andric   StringRef NameRef = BufferName.toStringRef(NameBuf);
321e3b55780SDimitry Andric 
322e3b55780SDimitry Andric   size_t StringLen = sizeof(MemBuffer) + sizeof(size_t) + NameRef.size() + 1;
323e3b55780SDimitry Andric   size_t RealLen = StringLen + Size + 1 + BufAlign.value();
324145449b1SDimitry Andric   if (RealLen <= Size) // Check for rollover.
325145449b1SDimitry Andric     return nullptr;
326ac9a064cSDimitry Andric   // We use a call to malloc() rather than a call to a non-throwing operator
327ac9a064cSDimitry Andric   // new() because LLVM unconditionally installs an out of memory new handler
328ac9a064cSDimitry Andric   // when exceptions are disabled. This new handler intentionally crashes to
329ac9a064cSDimitry Andric   // aid with debugging, but that makes non-throwing new calls unhelpful.
330ac9a064cSDimitry Andric   // See MemoryBufferMem::operator delete() for the paired call to free(), and
331ac9a064cSDimitry Andric   // llvm::install_out_of_memory_new_handler() for the installation of the
332ac9a064cSDimitry Andric   // custom new handler.
333ac9a064cSDimitry Andric   char *Mem = static_cast<char *>(std::malloc(RealLen));
334c7dac04cSDimitry Andric   if (!Mem)
335c7dac04cSDimitry Andric     return nullptr;
336c7dac04cSDimitry Andric 
337c7dac04cSDimitry Andric   // The name is stored after the class itself.
338e3b55780SDimitry Andric   *reinterpret_cast<size_t *>(Mem + sizeof(MemBuffer)) = NameRef.size();
339e3b55780SDimitry Andric   CopyStringRef(Mem + sizeof(MemBuffer) + sizeof(size_t), NameRef);
340c7dac04cSDimitry Andric 
341c7dac04cSDimitry Andric   // The buffer begins after the name and must be aligned.
342e3b55780SDimitry Andric   char *Buf = (char *)alignAddr(Mem + StringLen, BufAlign);
343c7dac04cSDimitry Andric   Buf[Size] = 0; // Null terminate buffer.
344c7dac04cSDimitry Andric 
345c7dac04cSDimitry Andric   auto *Ret = new (Mem) MemBuffer(StringRef(Buf, Size), true);
346c7dac04cSDimitry Andric   return std::unique_ptr<WritableMemoryBuffer>(Ret);
347c7dac04cSDimitry Andric }
348c7dac04cSDimitry Andric 
349eb11fae6SDimitry Andric std::unique_ptr<WritableMemoryBuffer>
getNewMemBuffer(size_t Size,const Twine & BufferName)350eb11fae6SDimitry Andric WritableMemoryBuffer::getNewMemBuffer(size_t Size, const Twine &BufferName) {
351eb11fae6SDimitry Andric   auto SB = WritableMemoryBuffer::getNewUninitMemBuffer(Size, BufferName);
352eb11fae6SDimitry Andric   if (!SB)
353eb11fae6SDimitry Andric     return nullptr;
354eb11fae6SDimitry Andric   memset(SB->getBufferStart(), 0, Size);
355eb11fae6SDimitry Andric   return SB;
356eb11fae6SDimitry Andric }
357eb11fae6SDimitry Andric 
shouldUseMmap(sys::fs::file_t FD,size_t FileSize,size_t MapSize,off_t Offset,bool RequiresNullTerminator,int PageSize,bool IsVolatile)358e6d15924SDimitry Andric static bool shouldUseMmap(sys::fs::file_t FD,
3596b943ff3SDimitry Andric                           size_t FileSize,
3606b943ff3SDimitry Andric                           size_t MapSize,
3616b943ff3SDimitry Andric                           off_t Offset,
3626b943ff3SDimitry Andric                           bool RequiresNullTerminator,
3635ca98fd9SDimitry Andric                           int PageSize,
36471d5a254SDimitry Andric                           bool IsVolatile) {
3655ca98fd9SDimitry Andric   // mmap may leave the buffer without null terminator if the file size changed
3665ca98fd9SDimitry Andric   // by the time the last page is mapped in, so avoid it if the file size is
3675ca98fd9SDimitry Andric   // likely to change.
368cfca06d7SDimitry Andric   if (IsVolatile && RequiresNullTerminator)
3695ca98fd9SDimitry Andric     return false;
3705ca98fd9SDimitry Andric 
3716b943ff3SDimitry Andric   // We don't use mmap for small files because this can severely fragment our
3726b943ff3SDimitry Andric   // address space.
373f8af5cf6SDimitry Andric   if (MapSize < 4 * 4096 || MapSize < (unsigned)PageSize)
3746b943ff3SDimitry Andric     return false;
3756b943ff3SDimitry Andric 
3766b943ff3SDimitry Andric   if (!RequiresNullTerminator)
3776b943ff3SDimitry Andric     return true;
3786b943ff3SDimitry Andric 
379009b1c42SEd Schouten   // If we don't know the file size, use fstat to find out.  fstat on an open
380009b1c42SEd Schouten   // file descriptor is cheaper than stat on a random path.
3816b943ff3SDimitry Andric   // FIXME: this chunk of code is duplicated, but it avoids a fstat when
3826b943ff3SDimitry Andric   // RequiresNullTerminator = false and MapSize != -1.
3836b943ff3SDimitry Andric   if (FileSize == size_t(-1)) {
384f8af5cf6SDimitry Andric     sys::fs::file_status Status;
3855ca98fd9SDimitry Andric     if (sys::fs::status(FD, Status))
3865ca98fd9SDimitry Andric       return false;
387f8af5cf6SDimitry Andric     FileSize = Status.getSize();
388009b1c42SEd Schouten   }
389009b1c42SEd Schouten 
3906b943ff3SDimitry Andric   // If we need a null terminator and the end of the map is inside the file,
3916b943ff3SDimitry Andric   // we cannot use mmap.
3926b943ff3SDimitry Andric   size_t End = Offset + MapSize;
3936b943ff3SDimitry Andric   assert(End <= FileSize);
3946b943ff3SDimitry Andric   if (End != FileSize)
3956b943ff3SDimitry Andric     return false;
396009b1c42SEd Schouten 
3976b943ff3SDimitry Andric   // Don't try to map files that are exactly a multiple of the system page size
3986b943ff3SDimitry Andric   // if we need a null terminator.
3996b943ff3SDimitry Andric   if ((FileSize & (PageSize -1)) == 0)
4006b943ff3SDimitry Andric     return false;
4016b943ff3SDimitry Andric 
40267c32a98SDimitry Andric #if defined(__CYGWIN__)
40367c32a98SDimitry Andric   // Don't try to map files that are exactly a multiple of the physical page size
40467c32a98SDimitry Andric   // if we need a null terminator.
40567c32a98SDimitry Andric   // FIXME: We should reorganize again getPageSize() on Win32.
40667c32a98SDimitry Andric   if ((FileSize & (4096 - 1)) == 0)
40767c32a98SDimitry Andric     return false;
40867c32a98SDimitry Andric #endif
40967c32a98SDimitry Andric 
4106b943ff3SDimitry Andric   return true;
4116b943ff3SDimitry Andric }
4126b943ff3SDimitry Andric 
413eb11fae6SDimitry Andric static ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>>
getReadWriteFile(const Twine & Filename,uint64_t FileSize,uint64_t MapSize,uint64_t Offset)414eb11fae6SDimitry Andric getReadWriteFile(const Twine &Filename, uint64_t FileSize, uint64_t MapSize,
415eb11fae6SDimitry Andric                  uint64_t Offset) {
416e6d15924SDimitry Andric   Expected<sys::fs::file_t> FDOrErr = sys::fs::openNativeFileForReadWrite(
417e6d15924SDimitry Andric       Filename, sys::fs::CD_OpenExisting, sys::fs::OF_None);
418e6d15924SDimitry Andric   if (!FDOrErr)
419e6d15924SDimitry Andric     return errorToErrorCode(FDOrErr.takeError());
420e6d15924SDimitry Andric   sys::fs::file_t FD = *FDOrErr;
421eb11fae6SDimitry Andric 
422eb11fae6SDimitry Andric   // Default is to map the full file.
423eb11fae6SDimitry Andric   if (MapSize == uint64_t(-1)) {
424eb11fae6SDimitry Andric     // If we don't know the file size, use fstat to find out.  fstat on an open
425eb11fae6SDimitry Andric     // file descriptor is cheaper than stat on a random path.
426eb11fae6SDimitry Andric     if (FileSize == uint64_t(-1)) {
427eb11fae6SDimitry Andric       sys::fs::file_status Status;
428eb11fae6SDimitry Andric       std::error_code EC = sys::fs::status(FD, Status);
429eb11fae6SDimitry Andric       if (EC)
430eb11fae6SDimitry Andric         return EC;
431eb11fae6SDimitry Andric 
432eb11fae6SDimitry Andric       // If this not a file or a block device (e.g. it's a named pipe
433eb11fae6SDimitry Andric       // or character device), we can't mmap it, so error out.
434eb11fae6SDimitry Andric       sys::fs::file_type Type = Status.type();
435eb11fae6SDimitry Andric       if (Type != sys::fs::file_type::regular_file &&
436eb11fae6SDimitry Andric           Type != sys::fs::file_type::block_file)
437eb11fae6SDimitry Andric         return make_error_code(errc::invalid_argument);
438eb11fae6SDimitry Andric 
439eb11fae6SDimitry Andric       FileSize = Status.getSize();
440eb11fae6SDimitry Andric     }
441eb11fae6SDimitry Andric     MapSize = FileSize;
442eb11fae6SDimitry Andric   }
443eb11fae6SDimitry Andric 
444e6d15924SDimitry Andric   std::error_code EC;
445eb11fae6SDimitry Andric   std::unique_ptr<WriteThroughMemoryBuffer> Result(
446eb11fae6SDimitry Andric       new (NamedBufferAlloc(Filename))
447eb11fae6SDimitry Andric           MemoryBufferMMapFile<WriteThroughMemoryBuffer>(false, FD, MapSize,
448eb11fae6SDimitry Andric                                                          Offset, EC));
449eb11fae6SDimitry Andric   if (EC)
450eb11fae6SDimitry Andric     return EC;
451eb11fae6SDimitry Andric   return std::move(Result);
452eb11fae6SDimitry Andric }
453eb11fae6SDimitry Andric 
454eb11fae6SDimitry Andric ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>>
getFile(const Twine & Filename,int64_t FileSize)455eb11fae6SDimitry Andric WriteThroughMemoryBuffer::getFile(const Twine &Filename, int64_t FileSize) {
456eb11fae6SDimitry Andric   return getReadWriteFile(Filename, FileSize, FileSize, 0);
457eb11fae6SDimitry Andric }
458eb11fae6SDimitry Andric 
459eb11fae6SDimitry Andric /// Map a subrange of the specified file as a WritableMemoryBuffer.
460eb11fae6SDimitry Andric ErrorOr<std::unique_ptr<WriteThroughMemoryBuffer>>
getFileSlice(const Twine & Filename,uint64_t MapSize,uint64_t Offset)461eb11fae6SDimitry Andric WriteThroughMemoryBuffer::getFileSlice(const Twine &Filename, uint64_t MapSize,
462eb11fae6SDimitry Andric                                        uint64_t Offset) {
463eb11fae6SDimitry Andric   return getReadWriteFile(Filename, -1, MapSize, Offset);
464eb11fae6SDimitry Andric }
465eb11fae6SDimitry Andric 
466c7dac04cSDimitry Andric template <typename MB>
467c7dac04cSDimitry Andric 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)468e6d15924SDimitry Andric getOpenFileImpl(sys::fs::file_t FD, const Twine &Filename, uint64_t FileSize,
4695ca98fd9SDimitry Andric                 uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator,
470e3b55780SDimitry Andric                 bool IsVolatile, std::optional<Align> Alignment) {
471e6d15924SDimitry Andric   static int PageSize = sys::Process::getPageSizeEstimate();
4726b943ff3SDimitry Andric 
4736b943ff3SDimitry Andric   // Default is to map the full file.
47430815c53SDimitry Andric   if (MapSize == uint64_t(-1)) {
4756b943ff3SDimitry Andric     // If we don't know the file size, use fstat to find out.  fstat on an open
4766b943ff3SDimitry Andric     // file descriptor is cheaper than stat on a random path.
47730815c53SDimitry Andric     if (FileSize == uint64_t(-1)) {
478f8af5cf6SDimitry Andric       sys::fs::file_status Status;
4795ca98fd9SDimitry Andric       std::error_code EC = sys::fs::status(FD, Status);
480f8af5cf6SDimitry Andric       if (EC)
481f8af5cf6SDimitry Andric         return EC;
482522600a2SDimitry Andric 
4834a16efa3SDimitry Andric       // If this not a file or a block device (e.g. it's a named pipe
4844a16efa3SDimitry Andric       // or character device), we can't trust the size. Create the memory
485522600a2SDimitry Andric       // buffer by copying off the stream.
486f8af5cf6SDimitry Andric       sys::fs::file_type Type = Status.type();
487f8af5cf6SDimitry Andric       if (Type != sys::fs::file_type::regular_file &&
488f8af5cf6SDimitry Andric           Type != sys::fs::file_type::block_file)
4895ca98fd9SDimitry Andric         return getMemoryBufferForStream(FD, Filename);
490522600a2SDimitry Andric 
491f8af5cf6SDimitry Andric       FileSize = Status.getSize();
4926b943ff3SDimitry Andric     }
4936b943ff3SDimitry Andric     MapSize = FileSize;
4946b943ff3SDimitry Andric   }
4956b943ff3SDimitry Andric 
4966b943ff3SDimitry Andric   if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator,
49771d5a254SDimitry Andric                     PageSize, IsVolatile)) {
4985ca98fd9SDimitry Andric     std::error_code EC;
499c7dac04cSDimitry Andric     std::unique_ptr<MB> Result(
500c7dac04cSDimitry Andric         new (NamedBufferAlloc(Filename)) MemoryBufferMMapFile<MB>(
501c7dac04cSDimitry Andric             RequiresNullTerminator, FD, MapSize, Offset, EC));
5024a16efa3SDimitry Andric     if (!EC)
5035ca98fd9SDimitry Andric       return std::move(Result);
504009b1c42SEd Schouten   }
505009b1c42SEd Schouten 
506344a3780SDimitry Andric #ifdef __MVS__
507344a3780SDimitry Andric   // Set codepage auto-conversion for z/OS.
508344a3780SDimitry Andric   if (auto EC = llvm::enableAutoConversion(FD))
509344a3780SDimitry Andric     return EC;
510344a3780SDimitry Andric #endif
511344a3780SDimitry Andric 
512e3b55780SDimitry Andric   auto Buf =
513e3b55780SDimitry Andric       WritableMemoryBuffer::getNewUninitMemBuffer(MapSize, Filename, Alignment);
514009b1c42SEd Schouten   if (!Buf) {
515cf099d11SDimitry Andric     // Failed to create a buffer. The only way it can fail is if
516cf099d11SDimitry Andric     // new(std::nothrow) returns 0.
517cf099d11SDimitry Andric     return make_error_code(errc::not_enough_memory);
518009b1c42SEd Schouten   }
519009b1c42SEd Schouten 
5201d5ae102SDimitry Andric   // Read until EOF, zero-initialize the rest.
5211d5ae102SDimitry Andric   MutableArrayRef<char> ToRead = Buf->getBuffer();
5221d5ae102SDimitry Andric   while (!ToRead.empty()) {
5231d5ae102SDimitry Andric     Expected<size_t> ReadBytes =
5241d5ae102SDimitry Andric         sys::fs::readNativeFileSlice(FD, ToRead, Offset);
5251d5ae102SDimitry Andric     if (!ReadBytes)
5261d5ae102SDimitry Andric       return errorToErrorCode(ReadBytes.takeError());
5271d5ae102SDimitry Andric     if (*ReadBytes == 0) {
5281d5ae102SDimitry Andric       std::memset(ToRead.data(), 0, ToRead.size());
5291d5ae102SDimitry Andric       break;
5301d5ae102SDimitry Andric     }
5311d5ae102SDimitry Andric     ToRead = ToRead.drop_front(*ReadBytes);
5321d5ae102SDimitry Andric     Offset += *ReadBytes;
5331d5ae102SDimitry Andric   }
534009b1c42SEd Schouten 
53567c32a98SDimitry Andric   return std::move(Buf);
536009b1c42SEd Schouten }
537009b1c42SEd Schouten 
5385ca98fd9SDimitry Andric 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)539e3b55780SDimitry Andric MemoryBuffer::getOpenFile(sys::fs::file_t FD, const Twine &Filename,
540e3b55780SDimitry Andric                           uint64_t FileSize, bool RequiresNullTerminator,
541e3b55780SDimitry Andric                           bool IsVolatile, std::optional<Align> Alignment) {
542c7dac04cSDimitry Andric   return getOpenFileImpl<MemoryBuffer>(FD, Filename, FileSize, FileSize, 0,
543e3b55780SDimitry Andric                                        RequiresNullTerminator, IsVolatile,
544e3b55780SDimitry Andric                                        Alignment);
545f8af5cf6SDimitry Andric }
546f8af5cf6SDimitry Andric 
getOpenFileSlice(sys::fs::file_t FD,const Twine & Filename,uint64_t MapSize,int64_t Offset,bool IsVolatile,std::optional<Align> Alignment)547e3b55780SDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getOpenFileSlice(
548e3b55780SDimitry Andric     sys::fs::file_t FD, const Twine &Filename, uint64_t MapSize, int64_t Offset,
549e3b55780SDimitry Andric     bool IsVolatile, std::optional<Align> Alignment) {
55067c32a98SDimitry Andric   assert(MapSize != uint64_t(-1));
551c7dac04cSDimitry Andric   return getOpenFileImpl<MemoryBuffer>(FD, Filename, -1, MapSize, Offset, false,
552e3b55780SDimitry Andric                                        IsVolatile, Alignment);
553f8af5cf6SDimitry Andric }
554f8af5cf6SDimitry Andric 
getSTDIN()5555ca98fd9SDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getSTDIN() {
556009b1c42SEd Schouten   // Read in all of the data from stdin, we cannot mmap stdin.
557907da171SRoman Divacky   //
558907da171SRoman Divacky   // FIXME: That isn't necessarily true, we should try to mmap stdin and
559907da171SRoman Divacky   // fallback if it fails.
560344a3780SDimitry Andric   sys::ChangeStdinMode(sys::fs::OF_Text);
561009b1c42SEd Schouten 
562e6d15924SDimitry Andric   return getMemoryBufferForStream(sys::fs::getStdinHandle(), "<stdin>");
563009b1c42SEd Schouten }
56467c32a98SDimitry Andric 
565b915e9e0SDimitry Andric ErrorOr<std::unique_ptr<MemoryBuffer>>
getFileAsStream(const Twine & Filename)566b915e9e0SDimitry Andric MemoryBuffer::getFileAsStream(const Twine &Filename) {
567e6d15924SDimitry Andric   Expected<sys::fs::file_t> FDOrErr =
568e6d15924SDimitry Andric       sys::fs::openNativeFileForRead(Filename, sys::fs::OF_None);
569e6d15924SDimitry Andric   if (!FDOrErr)
570e6d15924SDimitry Andric     return errorToErrorCode(FDOrErr.takeError());
571e6d15924SDimitry Andric   sys::fs::file_t FD = *FDOrErr;
572b915e9e0SDimitry Andric   ErrorOr<std::unique_ptr<MemoryBuffer>> Ret =
573b915e9e0SDimitry Andric       getMemoryBufferForStream(FD, Filename);
574e6d15924SDimitry Andric   sys::fs::closeFile(FD);
575b915e9e0SDimitry Andric   return Ret;
576b915e9e0SDimitry Andric }
577b915e9e0SDimitry Andric 
getMemBufferRef() const57867c32a98SDimitry Andric MemoryBufferRef MemoryBuffer::getMemBufferRef() const {
57967c32a98SDimitry Andric   StringRef Data = getBuffer();
58067c32a98SDimitry Andric   StringRef Identifier = getBufferIdentifier();
58167c32a98SDimitry Andric   return MemoryBufferRef(Data, Identifier);
58267c32a98SDimitry Andric }
583eb11fae6SDimitry Andric 
584145449b1SDimitry Andric SmallVectorMemoryBuffer::~SmallVectorMemoryBuffer() = default;
585