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/OwningPtr.h" 16#include "llvm/ADT/SmallString.h" 17#include "llvm/Config/config.h" 18#include "llvm/Support/MathExtras.h" 19#include "llvm/Support/Errno.h" 20#include "llvm/Support/FileSystem.h" 21#include "llvm/Support/Path.h" 22#include "llvm/Support/Process.h" 23#include "llvm/Support/Program.h" 24#include "llvm/Support/system_error.h" 25#include <cassert> 26#include <cstdio> 27#include <cstring> 28#include <cerrno> 29#include <new> 30#include <sys/types.h> 31#include <sys/stat.h> 32#if !defined(_MSC_VER) && !defined(__MINGW32__) 33#include <unistd.h> 34#else 35#include <io.h> 36#endif 37#include <fcntl.h> 38using namespace llvm; 39 40//===----------------------------------------------------------------------===// 41// MemoryBuffer implementation itself. 42//===----------------------------------------------------------------------===// 43 44MemoryBuffer::~MemoryBuffer() { } 45 46/// init - Initialize this MemoryBuffer as a reference to externally allocated 47/// memory, memory that we know is already null terminated. 48void MemoryBuffer::init(const char *BufStart, const char *BufEnd, 49 bool RequiresNullTerminator) { 50 assert((!RequiresNullTerminator || BufEnd[0] == 0) && 51 "Buffer is not null terminated!"); 52 BufferStart = BufStart; 53 BufferEnd = BufEnd; 54} 55 56//===----------------------------------------------------------------------===// 57// MemoryBufferMem implementation. 58//===----------------------------------------------------------------------===// 59 60/// CopyStringRef - Copies contents of a StringRef into a block of memory and 61/// null-terminates it. 62static void CopyStringRef(char *Memory, StringRef Data) { 63 memcpy(Memory, Data.data(), Data.size()); 64 Memory[Data.size()] = 0; // Null terminate string. 65} 66 67/// GetNamedBuffer - Allocates a new MemoryBuffer with Name copied after it. 68template <typename T> 69static T *GetNamedBuffer(StringRef Buffer, StringRef Name, 70 bool RequiresNullTerminator) { 71 char *Mem = static_cast<char*>(operator new(sizeof(T) + Name.size() + 1)); 72 CopyStringRef(Mem + sizeof(T), Name); 73 return new (Mem) T(Buffer, RequiresNullTerminator); 74} 75 76namespace { 77/// MemoryBufferMem - Named MemoryBuffer pointing to a block of memory. 78class MemoryBufferMem : public MemoryBuffer { 79public: 80 MemoryBufferMem(StringRef InputData, bool RequiresNullTerminator) { 81 init(InputData.begin(), InputData.end(), RequiresNullTerminator); 82 } 83 84 virtual const char *getBufferIdentifier() const LLVM_OVERRIDE { 85 // The name is stored after the class itself. 86 return reinterpret_cast<const char*>(this + 1); 87 } 88 89 virtual BufferKind getBufferKind() const LLVM_OVERRIDE { 90 return MemoryBuffer_Malloc; 91 } 92}; 93} 94 95/// getMemBuffer - Open the specified memory range as a MemoryBuffer. Note 96/// that InputData must be a null terminated if RequiresNullTerminator is true! 97MemoryBuffer *MemoryBuffer::getMemBuffer(StringRef InputData, 98 StringRef BufferName, 99 bool RequiresNullTerminator) { 100 return GetNamedBuffer<MemoryBufferMem>(InputData, BufferName, 101 RequiresNullTerminator); 102} 103 104/// getMemBufferCopy - Open the specified memory range as a MemoryBuffer, 105/// copying the contents and taking ownership of it. This has no requirements 106/// on EndPtr[0]. 107MemoryBuffer *MemoryBuffer::getMemBufferCopy(StringRef InputData, 108 StringRef BufferName) { 109 MemoryBuffer *Buf = getNewUninitMemBuffer(InputData.size(), BufferName); 110 if (!Buf) return 0; 111 memcpy(const_cast<char*>(Buf->getBufferStart()), InputData.data(), 112 InputData.size()); 113 return Buf; 114} 115 116/// getNewUninitMemBuffer - Allocate a new MemoryBuffer of the specified size 117/// that is not initialized. Note that the caller should initialize the 118/// memory allocated by this method. The memory is owned by the MemoryBuffer 119/// object. 120MemoryBuffer *MemoryBuffer::getNewUninitMemBuffer(size_t Size, 121 StringRef BufferName) { 122 // Allocate space for the MemoryBuffer, the data and the name. It is important 123 // that MemoryBuffer and data are aligned so PointerIntPair works with them. 124 size_t AlignedStringLen = 125 RoundUpToAlignment(sizeof(MemoryBufferMem) + BufferName.size() + 1, 126 sizeof(void*)); // TODO: Is sizeof(void*) enough? 127 size_t RealLen = AlignedStringLen + Size + 1; 128 char *Mem = static_cast<char*>(operator new(RealLen, std::nothrow)); 129 if (!Mem) return 0; 130 131 // The name is stored after the class itself. 132 CopyStringRef(Mem + sizeof(MemoryBufferMem), BufferName); 133 134 // The buffer begins after the name and must be aligned. 135 char *Buf = Mem + AlignedStringLen; 136 Buf[Size] = 0; // Null terminate buffer. 137 138 return new (Mem) MemoryBufferMem(StringRef(Buf, Size), true); 139} 140 141/// getNewMemBuffer - Allocate a new MemoryBuffer of the specified size that 142/// is completely initialized to zeros. Note that the caller should 143/// initialize the memory allocated by this method. The memory is owned by 144/// the MemoryBuffer object. 145MemoryBuffer *MemoryBuffer::getNewMemBuffer(size_t Size, StringRef BufferName) { 146 MemoryBuffer *SB = getNewUninitMemBuffer(Size, BufferName); 147 if (!SB) return 0; 148 memset(const_cast<char*>(SB->getBufferStart()), 0, Size); 149 return SB; 150} 151 152 153/// getFileOrSTDIN - Open the specified file as a MemoryBuffer, or open stdin 154/// if the Filename is "-". If an error occurs, this returns null and fills 155/// in *ErrStr with a reason. If stdin is empty, this API (unlike getSTDIN) 156/// returns an empty buffer. 157error_code MemoryBuffer::getFileOrSTDIN(StringRef Filename, 158 OwningPtr<MemoryBuffer> &result, 159 int64_t FileSize) { 160 if (Filename == "-") 161 return getSTDIN(result); 162 return getFile(Filename, result, FileSize); 163} 164 165error_code MemoryBuffer::getFileOrSTDIN(const char *Filename, 166 OwningPtr<MemoryBuffer> &result, 167 int64_t FileSize) { 168 if (strcmp(Filename, "-") == 0) 169 return getSTDIN(result); 170 return getFile(Filename, result, FileSize); 171} 172 173//===----------------------------------------------------------------------===// 174// MemoryBuffer::getFile implementation. 175//===----------------------------------------------------------------------===// 176 177namespace { 178/// MemoryBufferMMapFile - This represents a file that was mapped in with the 179/// sys::Path::MapInFilePages method. When destroyed, it calls the 180/// sys::Path::UnMapFilePages method. 181class MemoryBufferMMapFile : public MemoryBufferMem { 182public: 183 MemoryBufferMMapFile(StringRef Buffer, bool RequiresNullTerminator) 184 : MemoryBufferMem(Buffer, RequiresNullTerminator) { } 185 186 ~MemoryBufferMMapFile() { 187 static int PageSize = sys::Process::GetPageSize(); 188 189 uintptr_t Start = reinterpret_cast<uintptr_t>(getBufferStart()); 190 size_t Size = getBufferSize(); 191 uintptr_t RealStart = Start & ~(PageSize - 1); 192 size_t RealSize = Size + (Start - RealStart); 193 194 sys::Path::UnMapFilePages(reinterpret_cast<const char*>(RealStart), 195 RealSize); 196 } 197 198 virtual BufferKind getBufferKind() const LLVM_OVERRIDE { 199 return MemoryBuffer_MMap; 200 } 201}; 202} 203 204static error_code getMemoryBufferForStream(int FD, 205 StringRef BufferName, 206 OwningPtr<MemoryBuffer> &result) { 207 const ssize_t ChunkSize = 4096*4; 208 SmallString<ChunkSize> Buffer; 209 ssize_t ReadBytes; 210 // Read into Buffer until we hit EOF. 211 do { 212 Buffer.reserve(Buffer.size() + ChunkSize); 213 ReadBytes = read(FD, Buffer.end(), ChunkSize); 214 if (ReadBytes == -1) { 215 if (errno == EINTR) continue; 216 return error_code(errno, posix_category()); 217 } 218 Buffer.set_size(Buffer.size() + ReadBytes); 219 } while (ReadBytes != 0); 220 221 result.reset(MemoryBuffer::getMemBufferCopy(Buffer, BufferName)); 222 return error_code::success(); 223} 224 225error_code MemoryBuffer::getFile(StringRef Filename, 226 OwningPtr<MemoryBuffer> &result, 227 int64_t FileSize, 228 bool RequiresNullTerminator) { 229 // Ensure the path is null terminated. 230 SmallString<256> PathBuf(Filename.begin(), Filename.end()); 231 return MemoryBuffer::getFile(PathBuf.c_str(), result, FileSize, 232 RequiresNullTerminator); 233} 234 235error_code MemoryBuffer::getFile(const char *Filename, 236 OwningPtr<MemoryBuffer> &result, 237 int64_t FileSize, 238 bool RequiresNullTerminator) { 239 // First check that the "file" is not a directory 240 bool is_dir = false; 241 error_code err = sys::fs::is_directory(Filename, is_dir); 242 if (err) 243 return err; 244 if (is_dir) 245 return make_error_code(errc::is_a_directory); 246 247 int OpenFlags = O_RDONLY; 248#ifdef O_BINARY 249 OpenFlags |= O_BINARY; // Open input file in binary mode on win32. 250#endif 251 int FD = ::open(Filename, OpenFlags); 252 if (FD == -1) 253 return error_code(errno, posix_category()); 254 255 error_code ret = getOpenFile(FD, Filename, result, FileSize, FileSize, 256 0, RequiresNullTerminator); 257 close(FD); 258 return ret; 259} 260 261static bool shouldUseMmap(int FD, 262 size_t FileSize, 263 size_t MapSize, 264 off_t Offset, 265 bool RequiresNullTerminator, 266 int PageSize) { 267 // We don't use mmap for small files because this can severely fragment our 268 // address space. 269 if (MapSize < 4096*4) 270 return false; 271 272 if (!RequiresNullTerminator) 273 return true; 274 275 276 // If we don't know the file size, use fstat to find out. fstat on an open 277 // file descriptor is cheaper than stat on a random path. 278 // FIXME: this chunk of code is duplicated, but it avoids a fstat when 279 // RequiresNullTerminator = false and MapSize != -1. 280 if (FileSize == size_t(-1)) { 281 struct stat FileInfo; 282 // TODO: This should use fstat64 when available. 283 if (fstat(FD, &FileInfo) == -1) { 284 return error_code(errno, posix_category()); 285 } 286 FileSize = FileInfo.st_size; 287 } 288 289 // If we need a null terminator and the end of the map is inside the file, 290 // we cannot use mmap. 291 size_t End = Offset + MapSize; 292 assert(End <= FileSize); 293 if (End != FileSize) 294 return false; 295 296 // Don't try to map files that are exactly a multiple of the system page size 297 // if we need a null terminator. 298 if ((FileSize & (PageSize -1)) == 0) 299 return false; 300 301 return true; 302} 303 304error_code MemoryBuffer::getOpenFile(int FD, const char *Filename, 305 OwningPtr<MemoryBuffer> &result, 306 uint64_t FileSize, uint64_t MapSize, 307 int64_t Offset, 308 bool RequiresNullTerminator) { 309 static int PageSize = sys::Process::GetPageSize(); 310 311 // Default is to map the full file. 312 if (MapSize == uint64_t(-1)) { 313 // If we don't know the file size, use fstat to find out. fstat on an open 314 // file descriptor is cheaper than stat on a random path. 315 if (FileSize == uint64_t(-1)) { 316 struct stat FileInfo; 317 // TODO: This should use fstat64 when available. 318 if (fstat(FD, &FileInfo) == -1) { 319 return error_code(errno, posix_category()); 320 } 321 322 // If this is a named pipe, we can't trust the size. Create the memory 323 // buffer by copying off the stream. 324 if (FileInfo.st_mode & S_IFIFO) { 325 return getMemoryBufferForStream(FD, Filename, result); 326 } 327 328 FileSize = FileInfo.st_size; 329 } 330 MapSize = FileSize; 331 } 332 333 if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator, 334 PageSize)) { 335 off_t RealMapOffset = Offset & ~(PageSize - 1); 336 off_t Delta = Offset - RealMapOffset; 337 size_t RealMapSize = MapSize + Delta; 338 339 if (const char *Pages = sys::Path::MapInFilePages(FD, 340 RealMapSize, 341 RealMapOffset)) { 342 result.reset(GetNamedBuffer<MemoryBufferMMapFile>( 343 StringRef(Pages + Delta, MapSize), Filename, RequiresNullTerminator)); 344 return error_code::success(); 345 } 346 } 347 348 MemoryBuffer *Buf = MemoryBuffer::getNewUninitMemBuffer(MapSize, Filename); 349 if (!Buf) { 350 // Failed to create a buffer. The only way it can fail is if 351 // new(std::nothrow) returns 0. 352 return make_error_code(errc::not_enough_memory); 353 } 354 355 OwningPtr<MemoryBuffer> SB(Buf); 356 char *BufPtr = const_cast<char*>(SB->getBufferStart()); 357 358 size_t BytesLeft = MapSize; 359#ifndef HAVE_PREAD 360 if (lseek(FD, Offset, SEEK_SET) == -1) 361 return error_code(errno, posix_category()); 362#endif 363 364 while (BytesLeft) { 365#ifdef HAVE_PREAD 366 ssize_t NumRead = ::pread(FD, BufPtr, BytesLeft, MapSize-BytesLeft+Offset); 367#else 368 ssize_t NumRead = ::read(FD, BufPtr, BytesLeft); 369#endif 370 if (NumRead == -1) { 371 if (errno == EINTR) 372 continue; 373 // Error while reading. 374 return error_code(errno, posix_category()); 375 } 376 if (NumRead == 0) { 377 assert(0 && "We got inaccurate FileSize value or fstat reported an " 378 "invalid file size."); 379 *BufPtr = '\0'; // null-terminate at the actual size. 380 break; 381 } 382 BytesLeft -= NumRead; 383 BufPtr += NumRead; 384 } 385 386 result.swap(SB); 387 return error_code::success(); 388} 389 390//===----------------------------------------------------------------------===// 391// MemoryBuffer::getSTDIN implementation. 392//===----------------------------------------------------------------------===// 393 394error_code MemoryBuffer::getSTDIN(OwningPtr<MemoryBuffer> &result) { 395 // Read in all of the data from stdin, we cannot mmap stdin. 396 // 397 // FIXME: That isn't necessarily true, we should try to mmap stdin and 398 // fallback if it fails. 399 sys::Program::ChangeStdinToBinary(); 400 401 return getMemoryBufferForStream(0, "<stdin>", result); 402} 403