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