Index: llvm/include/llvm/Support/FileSystem.h =================================================================== --- llvm/include/llvm/Support/FileSystem.h +++ llvm/include/llvm/Support/FileSystem.h @@ -1262,10 +1262,18 @@ std::error_code init(sys::fs::file_t FD, uint64_t Offset, mapmode Mode); + void moveFrom(mapped_file_region &MovedFrom); + public: mapped_file_region() = delete; - mapped_file_region(mapped_file_region&) = delete; - mapped_file_region &operator =(mapped_file_region&) = delete; + mapped_file_region(const mapped_file_region &) = delete; + mapped_file_region &operator=(const mapped_file_region &) = delete; + + mapped_file_region(mapped_file_region &&MovedFrom) { moveFrom(MovedFrom); } + mapped_file_region &operator=(mapped_file_region &&MovedFrom) { + moveFrom(MovedFrom); + return *this; + } /// \param fd An open file descriptor to map. Does not take ownership of fd. mapped_file_region(sys::fs::file_t fd, mapmode mode, size_t length, uint64_t offset, Index: llvm/lib/Support/FileOutputBuffer.cpp =================================================================== --- llvm/lib/Support/FileOutputBuffer.cpp +++ llvm/lib/Support/FileOutputBuffer.cpp @@ -33,8 +33,7 @@ // with the temporary file on commit(). class OnDiskBuffer : public FileOutputBuffer { public: - OnDiskBuffer(StringRef Path, fs::TempFile Temp, - std::unique_ptr Buf) + OnDiskBuffer(StringRef Path, fs::TempFile Temp, fs::mapped_file_region Buf) : FileOutputBuffer(Path), Buffer(std::move(Buf)), Temp(std::move(Temp)) {} uint8_t *getBufferStart() const override { return (uint8_t *)Buffer->data(); } @@ -47,7 +46,7 @@ Error commit() override { // Unmap buffer, letting OS flush dirty pages to file on disk. - Buffer.reset(); + Buffer = None; // Atomically replace the existing file with the new one. return Temp.keep(FinalPath); @@ -56,7 +55,7 @@ ~OnDiskBuffer() override { // Close the mapping before deleting the temp file, so that the removal // succeeds. - Buffer.reset(); + Buffer = None; consumeError(Temp.discard()); } @@ -67,7 +66,7 @@ } private: - std::unique_ptr Buffer; + Optional Buffer; fs::TempFile Temp; }; @@ -139,9 +138,9 @@ // Mmap it. std::error_code EC; - auto MappedFile = std::make_unique( - fs::convertFDToNativeFile(File.FD), fs::mapped_file_region::readwrite, - Size, 0, EC); + fs::mapped_file_region MappedFile = + fs::mapped_file_region(fs::convertFDToNativeFile(File.FD), + fs::mapped_file_region::readwrite, Size, 0, EC); // mmap(2) can fail if the underlying filesystem does not support it. // If that happens, we fall back to in-memory buffer as the last resort. Index: llvm/lib/Support/Path.cpp =================================================================== --- llvm/lib/Support/Path.cpp +++ llvm/lib/Support/Path.cpp @@ -1152,6 +1152,21 @@ return Status.permissions(); } +void mapped_file_region::moveFrom(mapped_file_region &MovedFrom) { + Size = MovedFrom.Size; + Mapping = MovedFrom.Mapping; + Mode = MovedFrom.Mode; + + MovedFrom.Size = 0; + MovedFrom.Mapping = 0; + MovedFrom.Mode = mapmode(); + +#ifdef _WIN32 + FileHandle = MovedFrom.FileHandle; + MovedFrom.FileHandle = nullptr; +#endif +} + } // end namespace fs } // end namespace sys } // end namespace llvm Index: llvm/unittests/Support/Path.cpp =================================================================== --- llvm/unittests/Support/Path.cpp +++ llvm/unittests/Support/Path.cpp @@ -1341,6 +1341,7 @@ // Map in temp file and add some content std::error_code EC; StringRef Val("hello there"); + Optional MaybeMFR; { fs::mapped_file_region mfr(fs::convertFDToNativeFile(FileDescriptor), fs::mapped_file_region::readwrite, Size, 0, EC); @@ -1348,8 +1349,22 @@ std::copy(Val.begin(), Val.end(), mfr.data()); // Explicitly add a 0. mfr.data()[Val.size()] = 0; - // Unmap temp file + + // Move it out of the scope and confirm mfr is reset. + MaybeMFR.emplace(std::move(mfr)); +#if !defined(NDEBUG) && GTEST_HAS_DEATH_TEST + EXPECT_DEATH(mfr.data(), "Mapping failed but used anyway!"); + EXPECT_DEATH(mfr.size(), "Mapping failed but used anyway!"); +#endif } + + // Check that the moved-to region is still valid. + EXPECT_EQ(Val, StringRef(MaybeMFR->data())); + EXPECT_EQ(Size, MaybeMFR->size()); + + // Unmap temp file. + MaybeMFR = None; + ASSERT_EQ(close(FileDescriptor), 0); // Map it back in read-only