]>
Commit | Line | Data |
---|---|---|
223e47cc LB |
1 | //===--- MemoryBuffer.cpp - Memory Buffer implementation ------------------===// |
2 | // | |
3 | // The LLVM Compiler Infrastructure | |
4 | // | |
5 | // This file is distributed under the University of Illinois Open Source | |
6 | // License. See LICENSE.TXT for details. | |
7 | // | |
8 | //===----------------------------------------------------------------------===// | |
9 | // | |
10 | // This file implements the MemoryBuffer interface. | |
11 | // | |
12 | //===----------------------------------------------------------------------===// | |
13 | ||
14 | #include "llvm/Support/MemoryBuffer.h" | |
223e47cc LB |
15 | #include "llvm/ADT/SmallString.h" |
16 | #include "llvm/Config/config.h" | |
1a4d82fc | 17 | #include "llvm/Support/Errc.h" |
223e47cc LB |
18 | #include "llvm/Support/Errno.h" |
19 | #include "llvm/Support/FileSystem.h" | |
970d7e83 | 20 | #include "llvm/Support/MathExtras.h" |
223e47cc LB |
21 | #include "llvm/Support/Path.h" |
22 | #include "llvm/Support/Process.h" | |
23 | #include "llvm/Support/Program.h" | |
223e47cc | 24 | #include <cassert> |
970d7e83 | 25 | #include <cerrno> |
223e47cc LB |
26 | #include <cstdio> |
27 | #include <cstring> | |
223e47cc | 28 | #include <new> |
970d7e83 | 29 | #include <sys/types.h> |
1a4d82fc | 30 | #include <system_error> |
223e47cc LB |
31 | #if !defined(_MSC_VER) && !defined(__MINGW32__) |
32 | #include <unistd.h> | |
33 | #else | |
34 | #include <io.h> | |
970d7e83 | 35 | #endif |
223e47cc LB |
36 | using namespace llvm; |
37 | ||
38 | //===----------------------------------------------------------------------===// | |
39 | // MemoryBuffer implementation itself. | |
40 | //===----------------------------------------------------------------------===// | |
41 | ||
42 | MemoryBuffer::~MemoryBuffer() { } | |
43 | ||
44 | /// init - Initialize this MemoryBuffer as a reference to externally allocated | |
45 | /// memory, memory that we know is already null terminated. | |
46 | void MemoryBuffer::init(const char *BufStart, const char *BufEnd, | |
47 | bool RequiresNullTerminator) { | |
48 | assert((!RequiresNullTerminator || BufEnd[0] == 0) && | |
49 | "Buffer is not null terminated!"); | |
50 | BufferStart = BufStart; | |
51 | BufferEnd = BufEnd; | |
52 | } | |
53 | ||
54 | //===----------------------------------------------------------------------===// | |
55 | // MemoryBufferMem implementation. | |
56 | //===----------------------------------------------------------------------===// | |
57 | ||
58 | /// CopyStringRef - Copies contents of a StringRef into a block of memory and | |
59 | /// null-terminates it. | |
60 | static void CopyStringRef(char *Memory, StringRef Data) { | |
61 | memcpy(Memory, Data.data(), Data.size()); | |
62 | Memory[Data.size()] = 0; // Null terminate string. | |
63 | } | |
64 | ||
1a4d82fc | 65 | namespace { |
970d7e83 | 66 | struct NamedBufferAlloc { |
85aaf69f SL |
67 | const Twine &Name; |
68 | NamedBufferAlloc(const Twine &Name) : Name(Name) {} | |
970d7e83 | 69 | }; |
1a4d82fc | 70 | } |
970d7e83 LB |
71 | |
72 | void *operator new(size_t N, const NamedBufferAlloc &Alloc) { | |
85aaf69f SL |
73 | SmallString<256> NameBuf; |
74 | StringRef NameRef = Alloc.Name.toStringRef(NameBuf); | |
75 | ||
76 | char *Mem = static_cast<char *>(operator new(N + NameRef.size() + 1)); | |
77 | CopyStringRef(Mem + N, NameRef); | |
970d7e83 | 78 | return Mem; |
223e47cc LB |
79 | } |
80 | ||
81 | namespace { | |
82 | /// MemoryBufferMem - Named MemoryBuffer pointing to a block of memory. | |
83 | class MemoryBufferMem : public MemoryBuffer { | |
84 | public: | |
85 | MemoryBufferMem(StringRef InputData, bool RequiresNullTerminator) { | |
86 | init(InputData.begin(), InputData.end(), RequiresNullTerminator); | |
87 | } | |
88 | ||
1a4d82fc | 89 | const char *getBufferIdentifier() const override { |
223e47cc LB |
90 | // The name is stored after the class itself. |
91 | return reinterpret_cast<const char*>(this + 1); | |
92 | } | |
93 | ||
1a4d82fc | 94 | BufferKind getBufferKind() const override { |
223e47cc LB |
95 | return MemoryBuffer_Malloc; |
96 | } | |
97 | }; | |
98 | } | |
99 | ||
85aaf69f SL |
100 | static ErrorOr<std::unique_ptr<MemoryBuffer>> |
101 | getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize, | |
102 | uint64_t Offset, bool RequiresNullTerminator, bool IsVolatileSize); | |
103 | ||
1a4d82fc JJ |
104 | std::unique_ptr<MemoryBuffer> |
105 | MemoryBuffer::getMemBuffer(StringRef InputData, StringRef BufferName, | |
106 | bool RequiresNullTerminator) { | |
107 | auto *Ret = new (NamedBufferAlloc(BufferName)) | |
970d7e83 | 108 | MemoryBufferMem(InputData, RequiresNullTerminator); |
1a4d82fc | 109 | return std::unique_ptr<MemoryBuffer>(Ret); |
223e47cc LB |
110 | } |
111 | ||
1a4d82fc JJ |
112 | std::unique_ptr<MemoryBuffer> |
113 | MemoryBuffer::getMemBuffer(MemoryBufferRef Ref, bool RequiresNullTerminator) { | |
114 | return std::unique_ptr<MemoryBuffer>(getMemBuffer( | |
115 | Ref.getBuffer(), Ref.getBufferIdentifier(), RequiresNullTerminator)); | |
116 | } | |
117 | ||
118 | std::unique_ptr<MemoryBuffer> | |
85aaf69f | 119 | MemoryBuffer::getMemBufferCopy(StringRef InputData, const Twine &BufferName) { |
1a4d82fc JJ |
120 | std::unique_ptr<MemoryBuffer> Buf = |
121 | getNewUninitMemBuffer(InputData.size(), BufferName); | |
122 | if (!Buf) | |
123 | return nullptr; | |
223e47cc LB |
124 | memcpy(const_cast<char*>(Buf->getBufferStart()), InputData.data(), |
125 | InputData.size()); | |
126 | return Buf; | |
127 | } | |
128 | ||
1a4d82fc | 129 | std::unique_ptr<MemoryBuffer> |
85aaf69f | 130 | MemoryBuffer::getNewUninitMemBuffer(size_t Size, const Twine &BufferName) { |
223e47cc LB |
131 | // Allocate space for the MemoryBuffer, the data and the name. It is important |
132 | // that MemoryBuffer and data are aligned so PointerIntPair works with them. | |
1a4d82fc JJ |
133 | // TODO: Is 16-byte alignment enough? We copy small object files with large |
134 | // alignment expectations into this buffer. | |
85aaf69f SL |
135 | SmallString<256> NameBuf; |
136 | StringRef NameRef = BufferName.toStringRef(NameBuf); | |
223e47cc | 137 | size_t AlignedStringLen = |
85aaf69f | 138 | RoundUpToAlignment(sizeof(MemoryBufferMem) + NameRef.size() + 1, 16); |
223e47cc LB |
139 | size_t RealLen = AlignedStringLen + Size + 1; |
140 | char *Mem = static_cast<char*>(operator new(RealLen, std::nothrow)); | |
1a4d82fc JJ |
141 | if (!Mem) |
142 | return nullptr; | |
223e47cc LB |
143 | |
144 | // The name is stored after the class itself. | |
85aaf69f | 145 | CopyStringRef(Mem + sizeof(MemoryBufferMem), NameRef); |
223e47cc LB |
146 | |
147 | // The buffer begins after the name and must be aligned. | |
148 | char *Buf = Mem + AlignedStringLen; | |
149 | Buf[Size] = 0; // Null terminate buffer. | |
150 | ||
1a4d82fc JJ |
151 | auto *Ret = new (Mem) MemoryBufferMem(StringRef(Buf, Size), true); |
152 | return std::unique_ptr<MemoryBuffer>(Ret); | |
223e47cc LB |
153 | } |
154 | ||
1a4d82fc JJ |
155 | std::unique_ptr<MemoryBuffer> |
156 | MemoryBuffer::getNewMemBuffer(size_t Size, StringRef BufferName) { | |
157 | std::unique_ptr<MemoryBuffer> SB = getNewUninitMemBuffer(Size, BufferName); | |
158 | if (!SB) | |
159 | return nullptr; | |
223e47cc LB |
160 | memset(const_cast<char*>(SB->getBufferStart()), 0, Size); |
161 | return SB; | |
162 | } | |
163 | ||
1a4d82fc | 164 | ErrorOr<std::unique_ptr<MemoryBuffer>> |
85aaf69f SL |
165 | MemoryBuffer::getFileOrSTDIN(const Twine &Filename, int64_t FileSize) { |
166 | SmallString<256> NameBuf; | |
167 | StringRef NameRef = Filename.toStringRef(NameBuf); | |
168 | ||
169 | if (NameRef == "-") | |
1a4d82fc JJ |
170 | return getSTDIN(); |
171 | return getFile(Filename, FileSize); | |
223e47cc LB |
172 | } |
173 | ||
85aaf69f SL |
174 | ErrorOr<std::unique_ptr<MemoryBuffer>> |
175 | MemoryBuffer::getFileSlice(const Twine &FilePath, uint64_t MapSize, | |
176 | uint64_t Offset) { | |
177 | return getFileAux(FilePath, -1, MapSize, Offset, false, false); | |
178 | } | |
179 | ||
223e47cc LB |
180 | |
181 | //===----------------------------------------------------------------------===// | |
182 | // MemoryBuffer::getFile implementation. | |
183 | //===----------------------------------------------------------------------===// | |
184 | ||
185 | namespace { | |
1a4d82fc | 186 | /// \brief Memory maps a file descriptor using sys::fs::mapped_file_region. |
970d7e83 LB |
187 | /// |
188 | /// This handles converting the offset into a legal offset on the platform. | |
189 | class MemoryBufferMMapFile : public MemoryBuffer { | |
190 | sys::fs::mapped_file_region MFR; | |
191 | ||
192 | static uint64_t getLegalMapOffset(uint64_t Offset) { | |
193 | return Offset & ~(sys::fs::mapped_file_region::alignment() - 1); | |
194 | } | |
223e47cc | 195 | |
970d7e83 LB |
196 | static uint64_t getLegalMapSize(uint64_t Len, uint64_t Offset) { |
197 | return Len + (Offset - getLegalMapOffset(Offset)); | |
198 | } | |
223e47cc | 199 | |
970d7e83 LB |
200 | const char *getStart(uint64_t Len, uint64_t Offset) { |
201 | return MFR.const_data() + (Offset - getLegalMapOffset(Offset)); | |
202 | } | |
223e47cc | 203 | |
970d7e83 LB |
204 | public: |
205 | MemoryBufferMMapFile(bool RequiresNullTerminator, int FD, uint64_t Len, | |
85aaf69f SL |
206 | uint64_t Offset, std::error_code &EC) |
207 | : MFR(FD, sys::fs::mapped_file_region::readonly, | |
970d7e83 LB |
208 | getLegalMapSize(Len, Offset), getLegalMapOffset(Offset), EC) { |
209 | if (!EC) { | |
210 | const char *Start = getStart(Len, Offset); | |
211 | init(Start, Start + Len, RequiresNullTerminator); | |
212 | } | |
213 | } | |
214 | ||
1a4d82fc | 215 | const char *getBufferIdentifier() const override { |
970d7e83 LB |
216 | // The name is stored after the class itself. |
217 | return reinterpret_cast<const char *>(this + 1); | |
223e47cc LB |
218 | } |
219 | ||
1a4d82fc | 220 | BufferKind getBufferKind() const override { |
223e47cc LB |
221 | return MemoryBuffer_MMap; |
222 | } | |
223 | }; | |
224 | } | |
225 | ||
1a4d82fc | 226 | static ErrorOr<std::unique_ptr<MemoryBuffer>> |
85aaf69f | 227 | getMemoryBufferForStream(int FD, const Twine &BufferName) { |
970d7e83 LB |
228 | const ssize_t ChunkSize = 4096*4; |
229 | SmallString<ChunkSize> Buffer; | |
230 | ssize_t ReadBytes; | |
231 | // Read into Buffer until we hit EOF. | |
232 | do { | |
233 | Buffer.reserve(Buffer.size() + ChunkSize); | |
234 | ReadBytes = read(FD, Buffer.end(), ChunkSize); | |
235 | if (ReadBytes == -1) { | |
236 | if (errno == EINTR) continue; | |
1a4d82fc | 237 | return std::error_code(errno, std::generic_category()); |
970d7e83 LB |
238 | } |
239 | Buffer.set_size(Buffer.size() + ReadBytes); | |
240 | } while (ReadBytes != 0); | |
241 | ||
1a4d82fc | 242 | return MemoryBuffer::getMemBufferCopy(Buffer, BufferName); |
970d7e83 LB |
243 | } |
244 | ||
1a4d82fc JJ |
245 | |
246 | ErrorOr<std::unique_ptr<MemoryBuffer>> | |
85aaf69f | 247 | MemoryBuffer::getFile(const Twine &Filename, int64_t FileSize, |
1a4d82fc | 248 | bool RequiresNullTerminator, bool IsVolatileSize) { |
85aaf69f SL |
249 | return getFileAux(Filename, FileSize, FileSize, 0, |
250 | RequiresNullTerminator, IsVolatileSize); | |
223e47cc LB |
251 | } |
252 | ||
1a4d82fc | 253 | static ErrorOr<std::unique_ptr<MemoryBuffer>> |
85aaf69f | 254 | getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize, |
1a4d82fc JJ |
255 | uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator, |
256 | bool IsVolatileSize); | |
257 | ||
258 | static ErrorOr<std::unique_ptr<MemoryBuffer>> | |
85aaf69f SL |
259 | getFileAux(const Twine &Filename, int64_t FileSize, uint64_t MapSize, |
260 | uint64_t Offset, bool RequiresNullTerminator, bool IsVolatileSize) { | |
1a4d82fc JJ |
261 | int FD; |
262 | std::error_code EC = sys::fs::openFileForRead(Filename, FD); | |
263 | if (EC) | |
264 | return EC; | |
265 | ||
266 | ErrorOr<std::unique_ptr<MemoryBuffer>> Ret = | |
85aaf69f | 267 | getOpenFileImpl(FD, Filename, FileSize, MapSize, Offset, |
1a4d82fc | 268 | RequiresNullTerminator, IsVolatileSize); |
223e47cc | 269 | close(FD); |
1a4d82fc | 270 | return Ret; |
223e47cc LB |
271 | } |
272 | ||
273 | static bool shouldUseMmap(int FD, | |
274 | size_t FileSize, | |
275 | size_t MapSize, | |
276 | off_t Offset, | |
277 | bool RequiresNullTerminator, | |
1a4d82fc JJ |
278 | int PageSize, |
279 | bool IsVolatileSize) { | |
280 | // mmap may leave the buffer without null terminator if the file size changed | |
281 | // by the time the last page is mapped in, so avoid it if the file size is | |
282 | // likely to change. | |
283 | if (IsVolatileSize) | |
284 | return false; | |
285 | ||
223e47cc LB |
286 | // We don't use mmap for small files because this can severely fragment our |
287 | // address space. | |
1a4d82fc | 288 | if (MapSize < 4 * 4096 || MapSize < (unsigned)PageSize) |
223e47cc LB |
289 | return false; |
290 | ||
291 | if (!RequiresNullTerminator) | |
292 | return true; | |
293 | ||
294 | ||
295 | // If we don't know the file size, use fstat to find out. fstat on an open | |
296 | // file descriptor is cheaper than stat on a random path. | |
297 | // FIXME: this chunk of code is duplicated, but it avoids a fstat when | |
298 | // RequiresNullTerminator = false and MapSize != -1. | |
299 | if (FileSize == size_t(-1)) { | |
1a4d82fc JJ |
300 | sys::fs::file_status Status; |
301 | if (sys::fs::status(FD, Status)) | |
302 | return false; | |
303 | FileSize = Status.getSize(); | |
223e47cc LB |
304 | } |
305 | ||
306 | // If we need a null terminator and the end of the map is inside the file, | |
307 | // we cannot use mmap. | |
308 | size_t End = Offset + MapSize; | |
309 | assert(End <= FileSize); | |
310 | if (End != FileSize) | |
311 | return false; | |
312 | ||
313 | // Don't try to map files that are exactly a multiple of the system page size | |
314 | // if we need a null terminator. | |
315 | if ((FileSize & (PageSize -1)) == 0) | |
316 | return false; | |
317 | ||
1a4d82fc JJ |
318 | #if defined(__CYGWIN__) |
319 | // Don't try to map files that are exactly a multiple of the physical page size | |
320 | // if we need a null terminator. | |
321 | // FIXME: We should reorganize again getPageSize() on Win32. | |
322 | if ((FileSize & (4096 - 1)) == 0) | |
323 | return false; | |
324 | #endif | |
325 | ||
223e47cc LB |
326 | return true; |
327 | } | |
328 | ||
1a4d82fc | 329 | static ErrorOr<std::unique_ptr<MemoryBuffer>> |
85aaf69f | 330 | getOpenFileImpl(int FD, const Twine &Filename, uint64_t FileSize, |
1a4d82fc JJ |
331 | uint64_t MapSize, int64_t Offset, bool RequiresNullTerminator, |
332 | bool IsVolatileSize) { | |
85aaf69f | 333 | static int PageSize = sys::Process::getPageSize(); |
223e47cc LB |
334 | |
335 | // Default is to map the full file. | |
336 | if (MapSize == uint64_t(-1)) { | |
337 | // If we don't know the file size, use fstat to find out. fstat on an open | |
338 | // file descriptor is cheaper than stat on a random path. | |
339 | if (FileSize == uint64_t(-1)) { | |
1a4d82fc JJ |
340 | sys::fs::file_status Status; |
341 | std::error_code EC = sys::fs::status(FD, Status); | |
342 | if (EC) | |
343 | return EC; | |
970d7e83 LB |
344 | |
345 | // If this not a file or a block device (e.g. it's a named pipe | |
346 | // or character device), we can't trust the size. Create the memory | |
347 | // buffer by copying off the stream. | |
1a4d82fc JJ |
348 | sys::fs::file_type Type = Status.type(); |
349 | if (Type != sys::fs::file_type::regular_file && | |
350 | Type != sys::fs::file_type::block_file) | |
351 | return getMemoryBufferForStream(FD, Filename); | |
970d7e83 | 352 | |
1a4d82fc | 353 | FileSize = Status.getSize(); |
223e47cc LB |
354 | } |
355 | MapSize = FileSize; | |
356 | } | |
357 | ||
358 | if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator, | |
1a4d82fc JJ |
359 | PageSize, IsVolatileSize)) { |
360 | std::error_code EC; | |
361 | std::unique_ptr<MemoryBuffer> Result( | |
362 | new (NamedBufferAlloc(Filename)) | |
363 | MemoryBufferMMapFile(RequiresNullTerminator, FD, MapSize, Offset, EC)); | |
970d7e83 | 364 | if (!EC) |
1a4d82fc | 365 | return std::move(Result); |
223e47cc LB |
366 | } |
367 | ||
1a4d82fc JJ |
368 | std::unique_ptr<MemoryBuffer> Buf = |
369 | MemoryBuffer::getNewUninitMemBuffer(MapSize, Filename); | |
223e47cc LB |
370 | if (!Buf) { |
371 | // Failed to create a buffer. The only way it can fail is if | |
372 | // new(std::nothrow) returns 0. | |
373 | return make_error_code(errc::not_enough_memory); | |
374 | } | |
375 | ||
1a4d82fc | 376 | char *BufPtr = const_cast<char *>(Buf->getBufferStart()); |
223e47cc LB |
377 | |
378 | size_t BytesLeft = MapSize; | |
379 | #ifndef HAVE_PREAD | |
380 | if (lseek(FD, Offset, SEEK_SET) == -1) | |
1a4d82fc | 381 | return std::error_code(errno, std::generic_category()); |
223e47cc LB |
382 | #endif |
383 | ||
384 | while (BytesLeft) { | |
385 | #ifdef HAVE_PREAD | |
386 | ssize_t NumRead = ::pread(FD, BufPtr, BytesLeft, MapSize-BytesLeft+Offset); | |
387 | #else | |
388 | ssize_t NumRead = ::read(FD, BufPtr, BytesLeft); | |
389 | #endif | |
390 | if (NumRead == -1) { | |
391 | if (errno == EINTR) | |
392 | continue; | |
393 | // Error while reading. | |
1a4d82fc | 394 | return std::error_code(errno, std::generic_category()); |
223e47cc LB |
395 | } |
396 | if (NumRead == 0) { | |
1a4d82fc | 397 | memset(BufPtr, 0, BytesLeft); // zero-initialize rest of the buffer. |
223e47cc LB |
398 | break; |
399 | } | |
400 | BytesLeft -= NumRead; | |
401 | BufPtr += NumRead; | |
402 | } | |
403 | ||
1a4d82fc | 404 | return std::move(Buf); |
223e47cc LB |
405 | } |
406 | ||
1a4d82fc | 407 | ErrorOr<std::unique_ptr<MemoryBuffer>> |
85aaf69f | 408 | MemoryBuffer::getOpenFile(int FD, const Twine &Filename, uint64_t FileSize, |
1a4d82fc JJ |
409 | bool RequiresNullTerminator, bool IsVolatileSize) { |
410 | return getOpenFileImpl(FD, Filename, FileSize, FileSize, 0, | |
411 | RequiresNullTerminator, IsVolatileSize); | |
412 | } | |
413 | ||
414 | ErrorOr<std::unique_ptr<MemoryBuffer>> | |
85aaf69f SL |
415 | MemoryBuffer::getOpenFileSlice(int FD, const Twine &Filename, uint64_t MapSize, |
416 | int64_t Offset) { | |
417 | assert(MapSize != uint64_t(-1)); | |
1a4d82fc | 418 | return getOpenFileImpl(FD, Filename, -1, MapSize, Offset, false, |
85aaf69f | 419 | /*IsVolatileSize*/ false); |
1a4d82fc | 420 | } |
223e47cc | 421 | |
1a4d82fc | 422 | ErrorOr<std::unique_ptr<MemoryBuffer>> MemoryBuffer::getSTDIN() { |
223e47cc LB |
423 | // Read in all of the data from stdin, we cannot mmap stdin. |
424 | // | |
425 | // FIXME: That isn't necessarily true, we should try to mmap stdin and | |
426 | // fallback if it fails. | |
1a4d82fc JJ |
427 | sys::ChangeStdinToBinary(); |
428 | ||
429 | return getMemoryBufferForStream(0, "<stdin>"); | |
430 | } | |
223e47cc | 431 | |
1a4d82fc JJ |
432 | MemoryBufferRef MemoryBuffer::getMemBufferRef() const { |
433 | StringRef Data = getBuffer(); | |
434 | StringRef Identifier = getBufferIdentifier(); | |
435 | return MemoryBufferRef(Data, Identifier); | |
223e47cc | 436 | } |