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/Support/MathExtras.h" 18 #include "llvm/Support/Errno.h" 19 #include "llvm/Support/Path.h" 20 #include "llvm/Support/Process.h" 21 #include "llvm/Support/Program.h" 22 #include "llvm/Support/system_error.h" 23 #include <cassert> 24 #include <cstdio> 25 #include <cstring> 26 #include <cerrno> 27 #include <new> 28 #include <sys/types.h> 29 #include <sys/stat.h> 30 #if !defined(_MSC_VER) && !defined(__MINGW32__) 31 #include <unistd.h> 32 #else 33 #include <io.h> 34 #endif 35 #include <fcntl.h> 36 using namespace llvm; 37 38 namespace { const llvm::error_code success; } 39 40 //===----------------------------------------------------------------------===// 41 // MemoryBuffer implementation itself. 42 //===----------------------------------------------------------------------===// 43 44 MemoryBuffer::~MemoryBuffer() { } 45 46 /// init - Initialize this MemoryBuffer as a reference to externally allocated 47 /// memory, memory that we know is already null terminated. 48 void 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. 62 static 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. 68 template <typename T> 69 static 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 76 namespace { 77 /// MemoryBufferMem - Named MemoryBuffer pointing to a block of memory. 78 class MemoryBufferMem : public MemoryBuffer { 79 public: 80 MemoryBufferMem(StringRef InputData, bool RequiresNullTerminator) { 81 init(InputData.begin(), InputData.end(), RequiresNullTerminator); 82 } 83 84 virtual const char *getBufferIdentifier() const { 85 // The name is stored after the class itself. 86 return reinterpret_cast<const char*>(this + 1); 87 } 88 89 virtual BufferKind getBufferKind() const { 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! 97 MemoryBuffer *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]. 107 MemoryBuffer *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. 120 MemoryBuffer *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. 145 MemoryBuffer *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. 157 error_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 165 error_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 177 namespace { 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. 181 class MemoryBufferMMapFile : public MemoryBufferMem { 182 public: 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 { 199 return MemoryBuffer_MMap; 200 } 201 }; 202 } 203 204 error_code MemoryBuffer::getFile(StringRef Filename, 205 OwningPtr<MemoryBuffer> &result, 206 int64_t FileSize, 207 bool RequiresNullTerminator) { 208 // Ensure the path is null terminated. 209 SmallString<256> PathBuf(Filename.begin(), Filename.end()); 210 return MemoryBuffer::getFile(PathBuf.c_str(), result, FileSize, 211 RequiresNullTerminator); 212 } 213 214 error_code MemoryBuffer::getFile(const char *Filename, 215 OwningPtr<MemoryBuffer> &result, 216 int64_t FileSize, 217 bool RequiresNullTerminator) { 218 int OpenFlags = O_RDONLY; 219 #ifdef O_BINARY 220 OpenFlags |= O_BINARY; // Open input file in binary mode on win32. 221 #endif 222 int FD = ::open(Filename, OpenFlags); 223 if (FD == -1) 224 return error_code(errno, posix_category()); 225 226 error_code ret = getOpenFile(FD, Filename, result, FileSize, FileSize, 227 0, RequiresNullTerminator); 228 close(FD); 229 return ret; 230 } 231 232 static bool shouldUseMmap(int FD, 233 size_t FileSize, 234 size_t MapSize, 235 off_t Offset, 236 bool RequiresNullTerminator, 237 int PageSize) { 238 // We don't use mmap for small files because this can severely fragment our 239 // address space. 240 if (MapSize < 4096*4) 241 return false; 242 243 if (!RequiresNullTerminator) 244 return true; 245 246 247 // If we don't know the file size, use fstat to find out. fstat on an open 248 // file descriptor is cheaper than stat on a random path. 249 // FIXME: this chunk of code is duplicated, but it avoids a fstat when 250 // RequiresNullTerminator = false and MapSize != -1. 251 if (FileSize == size_t(-1)) { 252 struct stat FileInfo; 253 // TODO: This should use fstat64 when available. 254 if (fstat(FD, &FileInfo) == -1) { 255 return error_code(errno, posix_category()); 256 } 257 FileSize = FileInfo.st_size; 258 } 259 260 // If we need a null terminator and the end of the map is inside the file, 261 // we cannot use mmap. 262 size_t End = Offset + MapSize; 263 assert(End <= FileSize); 264 if (End != FileSize) 265 return false; 266 267 // Don't try to map files that are exactly a multiple of the system page size 268 // if we need a null terminator. 269 if ((FileSize & (PageSize -1)) == 0) 270 return false; 271 272 return true; 273 } 274 275 error_code MemoryBuffer::getOpenFile(int FD, const char *Filename, 276 OwningPtr<MemoryBuffer> &result, 277 uint64_t FileSize, uint64_t MapSize, 278 int64_t Offset, 279 bool RequiresNullTerminator) { 280 static int PageSize = sys::Process::GetPageSize(); 281 282 // Default is to map the full file. 283 if (MapSize == uint64_t(-1)) { 284 // If we don't know the file size, use fstat to find out. fstat on an open 285 // file descriptor is cheaper than stat on a random path. 286 if (FileSize == uint64_t(-1)) { 287 struct stat FileInfo; 288 // TODO: This should use fstat64 when available. 289 if (fstat(FD, &FileInfo) == -1) { 290 return error_code(errno, posix_category()); 291 } 292 FileSize = FileInfo.st_size; 293 } 294 MapSize = FileSize; 295 } 296 297 if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator, 298 PageSize)) { 299 off_t RealMapOffset = Offset & ~(PageSize - 1); 300 off_t Delta = Offset - RealMapOffset; 301 size_t RealMapSize = MapSize + Delta; 302 303 if (const char *Pages = sys::Path::MapInFilePages(FD, 304 RealMapSize, 305 RealMapOffset)) { 306 result.reset(GetNamedBuffer<MemoryBufferMMapFile>( 307 StringRef(Pages + Delta, MapSize), Filename, RequiresNullTerminator)); 308 return success; 309 } 310 } 311 312 MemoryBuffer *Buf = MemoryBuffer::getNewUninitMemBuffer(MapSize, Filename); 313 if (!Buf) { 314 // Failed to create a buffer. The only way it can fail is if 315 // new(std::nothrow) returns 0. 316 return make_error_code(errc::not_enough_memory); 317 } 318 319 OwningPtr<MemoryBuffer> SB(Buf); 320 char *BufPtr = const_cast<char*>(SB->getBufferStart()); 321 322 size_t BytesLeft = MapSize; 323 if (lseek(FD, Offset, SEEK_SET) == -1) 324 return error_code(errno, posix_category()); 325 326 while (BytesLeft) { 327 ssize_t NumRead = ::read(FD, BufPtr, BytesLeft); 328 if (NumRead == -1) { 329 if (errno == EINTR) 330 continue; 331 // Error while reading. 332 return error_code(errno, posix_category()); 333 } else if (NumRead == 0) { 334 // We hit EOF early, truncate and terminate buffer. 335 Buf->BufferEnd = BufPtr; 336 *BufPtr = 0; 337 result.swap(SB); 338 return success; 339 } 340 BytesLeft -= NumRead; 341 BufPtr += NumRead; 342 } 343 344 result.swap(SB); 345 return success; 346 } 347 348 //===----------------------------------------------------------------------===// 349 // MemoryBuffer::getSTDIN implementation. 350 //===----------------------------------------------------------------------===// 351 352 error_code MemoryBuffer::getSTDIN(OwningPtr<MemoryBuffer> &result) { 353 // Read in all of the data from stdin, we cannot mmap stdin. 354 // 355 // FIXME: That isn't necessarily true, we should try to mmap stdin and 356 // fallback if it fails. 357 sys::Program::ChangeStdinToBinary(); 358 359 const ssize_t ChunkSize = 4096*4; 360 SmallString<ChunkSize> Buffer; 361 ssize_t ReadBytes; 362 // Read into Buffer until we hit EOF. 363 do { 364 Buffer.reserve(Buffer.size() + ChunkSize); 365 ReadBytes = read(0, Buffer.end(), ChunkSize); 366 if (ReadBytes == -1) { 367 if (errno == EINTR) continue; 368 return error_code(errno, posix_category()); 369 } 370 Buffer.set_size(Buffer.size() + ReadBytes); 371 } while (ReadBytes != 0); 372 373 result.reset(getMemBufferCopy(Buffer, "<stdin>")); 374 return success; 375 } 376