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