Coverage Report

Created: 2026-02-14 07:25

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