Index: include/llvm/Support/FileSystem.h =================================================================== --- include/llvm/Support/FileSystem.h +++ include/llvm/Support/FileSystem.h @@ -1064,6 +1064,7 @@ void *FileHandle; #endif mapmode Mode; + bool Executable; ///< The file is an executable std::error_code init(int FD, uint64_t Offset, mapmode Mode); @@ -1076,7 +1077,7 @@ /// ownership if closefd is true. It must have been opended in the correct /// mode. mapped_file_region(int fd, mapmode mode, size_t length, uint64_t offset, - std::error_code &ec); + bool Exe, std::error_code &ec); ~mapped_file_region(); Index: lib/Support/FileOutputBuffer.cpp =================================================================== --- lib/Support/FileOutputBuffer.cpp +++ lib/Support/FileOutputBuffer.cpp @@ -144,7 +144,8 @@ // Mmap it. std::error_code EC; auto MappedFile = llvm::make_unique( - File.FD, fs::mapped_file_region::readwrite, Size, 0, EC); + File.FD, fs::mapped_file_region::readwrite, Size, 0, + !!(Mode & fs::all_exe), EC); if (EC) { consumeError(File.discard()); return errorCodeToError(EC); Index: lib/Support/MemoryBuffer.cpp =================================================================== --- lib/Support/MemoryBuffer.cpp +++ lib/Support/MemoryBuffer.cpp @@ -184,9 +184,11 @@ public: MemoryBufferMMapFile(bool RequiresNullTerminator, int FD, uint64_t Len, - uint64_t Offset, std::error_code &EC) + uint64_t Offset, llvm::sys::fs::perms Perm, + std::error_code &EC) : MFR(FD, MB::Mapmode, getLegalMapSize(Len, Offset), - getLegalMapOffset(Offset), EC) { + getLegalMapOffset(Offset), !!(Perm & llvm::sys::fs::perms::all_exe), + EC) { if (!EC) { const char *Start = getStart(Len, Offset); MemoryBuffer::init(Start, Start + Len, RequiresNullTerminator); @@ -370,16 +372,14 @@ if (EC) return EC; + sys::fs::file_status Status; + EC = sys::fs::status(FD, Status); + if (EC) + return EC; + // Default is to map the full file. if (MapSize == uint64_t(-1)) { - // If we don't know the file size, use fstat to find out. fstat on an open - // file descriptor is cheaper than stat on a random path. if (FileSize == uint64_t(-1)) { - sys::fs::file_status Status; - std::error_code EC = sys::fs::status(FD, Status); - if (EC) - return EC; - // If this not a file or a block device (e.g. it's a named pipe // or character device), we can't mmap it, so error out. sys::fs::file_type Type = Status.type(); @@ -395,7 +395,7 @@ std::unique_ptr Result( new (NamedBufferAlloc(Filename)) MemoryBufferMMapFile(false, FD, MapSize, - Offset, EC)); + Offset, Status.permissions(), EC)); if (EC) return EC; return std::move(Result); @@ -420,16 +420,14 @@ bool IsVolatile) { static int PageSize = sys::Process::getPageSize(); + sys::fs::file_status Status; + std::error_code EC = sys::fs::status(FD, Status); + if (EC) + return EC; + // Default is to map the full file. if (MapSize == uint64_t(-1)) { - // If we don't know the file size, use fstat to find out. fstat on an open - // file descriptor is cheaper than stat on a random path. if (FileSize == uint64_t(-1)) { - sys::fs::file_status Status; - std::error_code EC = sys::fs::status(FD, Status); - if (EC) - return EC; - // If this not a file or a block device (e.g. it's a named pipe // or character device), we can't trust the size. Create the memory // buffer by copying off the stream. @@ -446,9 +444,9 @@ if (shouldUseMmap(FD, FileSize, MapSize, Offset, RequiresNullTerminator, PageSize, IsVolatile)) { std::error_code EC; - std::unique_ptr Result( - new (NamedBufferAlloc(Filename)) MemoryBufferMMapFile( - RequiresNullTerminator, FD, MapSize, Offset, EC)); + std::unique_ptr Result(new (NamedBufferAlloc( + Filename)) MemoryBufferMMapFile(RequiresNullTerminator, FD, MapSize, + Offset, Status.permissions(), EC)); if (!EC) return std::move(Result); } Index: lib/Support/Windows/Path.inc =================================================================== --- lib/Support/Windows/Path.inc +++ lib/Support/Windows/Path.inc @@ -847,8 +847,9 @@ } mapped_file_region::mapped_file_region(int fd, mapmode mode, size_t length, - uint64_t offset, std::error_code &ec) - : Size(length), Mapping() { + uint64_t offset, bool Exe, + std::error_code &ec) + : Size(length), Mapping(), Executable(Exe) { ec = init(fd, offset, mode); if (ec) Mapping = 0; @@ -858,12 +859,14 @@ if (Mapping) { ::UnmapViewOfFile(Mapping); - if (Mode == mapmode::readwrite) { + if (Mode == mapmode::readwrite && Executable) { // There is a Windows kernel bug, the exact trigger conditions of which // are not well understood. When triggered, dirty pages are not properly // flushed and subsequent process's attempts to read a file can return // invalid data. Calling FlushFileBuffers on the write handle is // sufficient to ensure that this bug is not triggered. + // The bug only occurs when writing an executable and executing it right + // after, under high I/O pressure. ::FlushFileBuffers(FileHandle); } Index: lib/XRay/InstrumentationMap.cpp =================================================================== --- lib/XRay/InstrumentationMap.cpp +++ lib/XRay/InstrumentationMap.cpp @@ -137,7 +137,8 @@ InstrumentationMap::FunctionAddressReverseMap &FunctionIds) { std::error_code EC; sys::fs::mapped_file_region MappedFile( - Fd, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, EC); + Fd, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, + false /*Exe*/, EC); if (EC) return make_error( Twine("Failed memory-mapping file '") + Filename + "'.", EC); Index: lib/XRay/Profile.cpp =================================================================== --- lib/XRay/Profile.cpp +++ lib/XRay/Profile.cpp @@ -273,7 +273,8 @@ std::error_code EC; sys::fs::mapped_file_region MappedFile( - Fd, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, EC); + Fd, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, + false /*Exe*/, EC); if (EC) return make_error( Twine("Cannot mmap profile '") + Filename + "'", EC); Index: lib/XRay/Trace.cpp =================================================================== --- lib/XRay/Trace.cpp +++ lib/XRay/Trace.cpp @@ -381,7 +381,8 @@ // Map the opened file into memory and use a StringRef to access it later. std::error_code EC; sys::fs::mapped_file_region MappedFile( - Fd, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, EC); + Fd, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, + false /*Exe*/, EC); if (EC) { return make_error( Twine("Cannot read log from '") + Filename + "'", EC); Index: tools/llvm-xray/xray-fdr-dump.cpp =================================================================== --- tools/llvm-xray/xray-fdr-dump.cpp +++ tools/llvm-xray/xray-fdr-dump.cpp @@ -48,7 +48,8 @@ std::error_code EC; sys::fs::mapped_file_region MappedFile( - Fd, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, EC); + Fd, sys::fs::mapped_file_region::mapmode::readonly, FileSize, 0, + false /*Exe*/, EC); DataExtractor DE(StringRef(MappedFile.data(), MappedFile.size()), true, 8); uint32_t OffsetPtr = 0; Index: unittests/Support/Path.cpp =================================================================== --- unittests/Support/Path.cpp +++ unittests/Support/Path.cpp @@ -1049,7 +1049,8 @@ StringRef Val("hello there"); { fs::mapped_file_region mfr(FileDescriptor, - fs::mapped_file_region::readwrite, Size, 0, EC); + fs::mapped_file_region::readwrite, Size, 0, + false /*Executable*/, EC); ASSERT_NO_ERROR(EC); std::copy(Val.begin(), Val.end(), mfr.data()); // Explicitly add a 0. @@ -1063,14 +1064,16 @@ int FD; EC = fs::openFileForRead(Twine(TempPath), FD); ASSERT_NO_ERROR(EC); - fs::mapped_file_region mfr(FD, fs::mapped_file_region::readonly, Size, 0, EC); + fs::mapped_file_region mfr(FD, fs::mapped_file_region::readonly, Size, 0, + false /*Executable*/, EC); ASSERT_NO_ERROR(EC); // Verify content EXPECT_EQ(StringRef(mfr.const_data()), Val); // Unmap temp file - fs::mapped_file_region m(FD, fs::mapped_file_region::readonly, Size, 0, EC); + fs::mapped_file_region m(FD, fs::mapped_file_region::readonly, Size, 0, + false /*Executable*/, EC); ASSERT_NO_ERROR(EC); ASSERT_EQ(close(FD), 0); } Index: unittests/Support/ReplaceFileTest.cpp =================================================================== --- unittests/Support/ReplaceFileTest.cpp +++ unittests/Support/ReplaceFileTest.cpp @@ -147,8 +147,9 @@ std::error_code EC; ASSERT_NO_ERROR(fs::openFileForRead(TargetFileName, TargetFD)); ScopedFD X(TargetFD); - sys::fs::mapped_file_region MFR( - TargetFD, sys::fs::mapped_file_region::readonly, 10, 0, EC); + sys::fs::mapped_file_region MFR(TargetFD, + sys::fs::mapped_file_region::readonly, 10, + 0, false /*Executable*/, EC); ASSERT_FALSE(EC); ASSERT_NO_ERROR(fs::rename(SourceFileName, TargetFileName));