diff --git a/src/coreclr/ilasm/asmparse.h b/src/coreclr/ilasm/asmparse.h index a20157e83132d8..12fb0c587ebea5 100644 --- a/src/coreclr/ilasm/asmparse.h +++ b/src/coreclr/ilasm/asmparse.h @@ -7,6 +7,8 @@ #define asmparse_h #include // for FILE +#include +#include #include "assembler.h" // for ErrorReporter Labels //class Assembler; @@ -95,9 +97,8 @@ class MappedFileStream : public ReadStream { public: MappedFileStream(_In_ __nullterminated WCHAR* wFileName) : m_fileNameUtf8(NULL) - , m_hFile(INVALID_HANDLE_VALUE) + , m_File(nullptr) , m_FileSize(0) - , m_hMapFile(NULL) { m_pStart = open(wFileName); m_pCurr = m_pStart; @@ -112,20 +113,8 @@ class MappedFileStream : public ReadStream { } ~MappedFileStream() { - if (m_hFile != INVALID_HANDLE_VALUE) - { - if (m_pStart) - UnmapViewOfFile((void*)m_pStart); - if (m_hMapFile) - CloseHandle(m_hMapFile); - CloseHandle(m_hFile); - - m_pStart = NULL; - m_hMapFile = NULL; - m_hFile = INVALID_HANDLE_VALUE; - m_FileSize = 0; - } - + if (m_File) + delete m_File; if (m_fileNameUtf8 != NULL) delete [] m_fileNameUtf8; } @@ -171,37 +160,27 @@ class MappedFileStream : public ReadStream { } private: - char* map_file() - { - DWORD dwFileSizeLow; - - dwFileSizeLow = GetFileSize( m_hFile, NULL); - if (dwFileSizeLow == INVALID_FILE_SIZE) - return NULL; - m_FileSize = dwFileSizeLow; - - // No difference between A and W in this case: last param (LPCTSTR) is NULL - m_hMapFile = CreateFileMapping(m_hFile, NULL, PAGE_READONLY, 0, 0, NULL); - if (m_hMapFile == NULL) - return NULL; - - return (char*)(HMODULE) MapViewOfFile(m_hMapFile, FILE_MAP_READ, 0, 0, 0); - } char* open(const WCHAR* moduleName) { _ASSERTE(moduleName); if (!moduleName) return NULL; - m_hFile = WszCreateFile(moduleName, GENERIC_READ, FILE_SHARE_READ, - 0, OPEN_EXISTING, 0, 0); - return (m_hFile == INVALID_HANDLE_VALUE) ? NULL : map_file(); + m_File = CreateMappedFile(moduleName); + if (m_File == nullptr) + { + m_File = nullptr; + m_FileSize = 0; + return nullptr; + } + + m_FileSize = (DWORD)m_File->Size(); + return (char*)m_File->Address(); } char* m_fileNameUtf8; // FileName (for error reporting) - HANDLE m_hFile; // File we are reading from + MemoryMappedFile* m_File; // File we are reading from DWORD m_FileSize; - HANDLE m_hMapFile; char* m_pStart; char* m_pEnd; char* m_pCurr; diff --git a/src/coreclr/ildasm/ceeload.cpp b/src/coreclr/ildasm/ceeload.cpp index df7666d6522bea..ffaf67586e1e40 100644 --- a/src/coreclr/ildasm/ceeload.cpp +++ b/src/coreclr/ildasm/ceeload.cpp @@ -17,9 +17,8 @@ /*************************************************************************************/ PELoader::PELoader() { - m_hFile = NULL; + m_File = nullptr; m_hMod = NULL; - m_hMapFile = NULL; m_pNT64 = NULL; m_bIsPE32 = FALSE; m_FileSize = m_FileSizeAligned = 0; @@ -30,91 +29,31 @@ PELoader::~PELoader() m_hMod = NULL; m_pNT64 = NULL; - // If we have an hFile then we opened this file ourselves! - // If we do not then this file was loaded by the OS and the OS will - // close it for us. - if (m_hFile) - this->close(); } /*************************************************************************************/ /*************************************************************************************/ void PELoader::close() { - - // _ASSERTE(m_hFile != NULL); - if (m_hFile) - { - if (m_hMod) - UnmapViewOfFile((void*)m_hMod); - if (m_hMapFile) - CloseHandle(m_hMapFile); - CloseHandle(m_hFile); - - m_hMod = NULL; - m_hMapFile = NULL; - m_hFile = NULL; - m_FileSize = m_FileSizeAligned = 0; - } -} - - -BOOL PELoader::open(LPCSTR moduleName) -{ - HMODULE newhMod = NULL; - DWORD dwFileSizeLow; - - _ASSERTE(moduleName); - if (!moduleName) - return FALSE; - - - m_hFile = CreateFileA(moduleName, GENERIC_READ, FILE_SHARE_READ, - 0, OPEN_EXISTING, 0, 0); - if (m_hFile == INVALID_HANDLE_VALUE) - return FALSE; - - dwFileSizeLow = GetFileSize( m_hFile, NULL); - if (dwFileSizeLow == INVALID_FILE_SIZE) - return FALSE; - m_FileSize = dwFileSizeLow; - - m_hMapFile = CreateFileMapping(m_hFile, NULL, PAGE_READONLY, 0, 0, NULL); - if (m_hMapFile == NULL) - return FALSE; - - newhMod = (HMODULE) MapViewOfFile(m_hMapFile, FILE_MAP_READ, 0, 0, 0); - if (newhMod == NULL) - return FALSE; - return open(newhMod); + delete m_File; + m_File = nullptr; } BOOL PELoader::open(const WCHAR* moduleName) { HMODULE newhMod = NULL; - DWORD dwFileSizeLow; _ASSERTE(moduleName); if (!moduleName) return FALSE; - m_hFile = WszCreateFile(moduleName, GENERIC_READ, FILE_SHARE_READ, - 0, OPEN_EXISTING, 0, 0); - if (m_hFile == INVALID_HANDLE_VALUE) + m_File = CreateMappedFile(moduleName); + if (m_File == nullptr) return FALSE; - dwFileSizeLow = GetFileSize( m_hFile, NULL); - if (dwFileSizeLow == INVALID_FILE_SIZE) - return FALSE; - m_FileSize = dwFileSizeLow; + m_FileSize = m_File->Size(); - m_hMapFile = CreateFileMapping(m_hFile, NULL, PAGE_READONLY, 0, 0, NULL); - if (m_hMapFile == NULL) - return FALSE; - - newhMod = (HMODULE) MapViewOfFile(m_hMapFile, FILE_MAP_READ, 0, 0, 0); - if (newhMod == NULL) - return FALSE; + newhMod = (HMODULE)m_File->Address(); return open(newhMod); } diff --git a/src/coreclr/ildasm/ceeload.h b/src/coreclr/ildasm/ceeload.h index f1c8ec7248b9bb..c1eb630c1c4852 100644 --- a/src/coreclr/ildasm/ceeload.h +++ b/src/coreclr/ildasm/ceeload.h @@ -35,8 +35,7 @@ class PELoader { protected: HMODULE m_hMod; - HANDLE m_hFile; - HANDLE m_hMapFile; + MemoryMappedFile* m_File; BOOL m_bIsPE32; size_t m_FileSize; size_t m_FileSizeAligned; @@ -54,7 +53,6 @@ class PELoader { PELoader(); ~PELoader(); - BOOL open(const char* moduleNameIn); BOOL open(const WCHAR* moduleNameIn); BOOL open(HMODULE hMod); BOOL getCOMHeader(IMAGE_COR20_HEADER **ppCorHeader); @@ -69,7 +67,7 @@ class PELoader { inline DWORD Signature() { return m_pNT32->Signature; }; inline BYTE* base() { return (BYTE*) m_hMod; }; inline HMODULE getHModule() { return m_hMod; }; - inline HANDLE getHFile() { return m_hFile; } ; + inline uint32_t getFileSize() { return (uint32_t)m_FileSize; }; }; #endif // CEELoad_H diff --git a/src/coreclr/ildasm/dasm.cpp b/src/coreclr/ildasm/dasm.cpp index 45f0070ffc390d..5648db5b5fd612 100644 --- a/src/coreclr/ildasm/dasm.cpp +++ b/src/coreclr/ildasm/dasm.cpp @@ -5837,7 +5837,7 @@ void DumpStatistics(IMAGE_COR20_HEADER *CORHeader, void* GUICookie) TableSeenReset(); metaSize = 0; - sprintf_s(szString,SZSTRING_SIZE,"// File size : %d", fileSize = SafeGetFileSize(g_pPELoader->getHFile(), NULL)); + sprintf_s(szString,SZSTRING_SIZE,"// File size : %u", fileSize = g_pPELoader->getFileSize()); printLine(GUICookie,szStr); if (g_pPELoader->IsPE32()) diff --git a/src/coreclr/ildasm/ildasmpch.h b/src/coreclr/ildasm/ildasmpch.h index af7295f12a21aa..8736661443e77d 100644 --- a/src/coreclr/ildasm/ildasmpch.h +++ b/src/coreclr/ildasm/ildasmpch.h @@ -13,7 +13,8 @@ #include #include #include -#include "dn-stdio.h" +#include +#include using std::min; using std::max; diff --git a/src/coreclr/inc/longfilepathwrappers.h b/src/coreclr/inc/longfilepathwrappers.h index ca028bf6d625a1..585c2c3b53dcba 100644 --- a/src/coreclr/inc/longfilepathwrappers.h +++ b/src/coreclr/inc/longfilepathwrappers.h @@ -5,6 +5,8 @@ #define _WIN_PATH_APIS_WRAPPER_ class SString; +#include + #ifdef HOST_WINDOWS HMODULE @@ -27,6 +29,8 @@ CreateFileWrapper( int u16_fopen_wrapper(FILE** stream, const WCHAR* filename, const WCHAR* mode); +MemoryMappedFile* CreateMappedFileWrapper(const WCHAR* filename); + BOOL CopyFileExWrapper( _In_ LPCWSTR lpExistingFileName, diff --git a/src/coreclr/inc/winwrap.h b/src/coreclr/inc/winwrap.h index 2e8946aa50205f..b6ee5743cc0662 100644 --- a/src/coreclr/inc/winwrap.h +++ b/src/coreclr/inc/winwrap.h @@ -43,10 +43,12 @@ #define WszLoadLibrary LoadLibraryExWrapper #define WszCreateFile CreateFileWrapper #define fopen_lp u16_fopen_wrapper +#define CreateMappedFile CreateMappedFileWrapper #else // HOST_WINDOWS #define WszLoadLibrary LoadLibraryExW #define WszCreateFile CreateFileW #define fopen_lp u16_fopen_s +#define CreateMappedFile MemoryMappedFile::Open #endif // HOST_WINDOWS //APIS which have a buffer as an out parameter diff --git a/src/coreclr/md/enc/stgio.cpp b/src/coreclr/md/enc/stgio.cpp index aeba5e59f47359..708294fe8b011d 100644 --- a/src/coreclr/md/enc/stgio.cpp +++ b/src/coreclr/md/enc/stgio.cpp @@ -39,6 +39,13 @@ #include "posterror.h" #include "pedecoder.h" #include "pedecoder.inl" +#ifdef HOST_UNIX +#include +#include +#include +#include +#include +#endif // HOST_UNIX //********** Types. *********************************************************** #define SMALL_ALLOC_MAP_SIZE (64 * 1024) // 64 kb is the minimum size of virtual @@ -90,9 +97,14 @@ void StgIO::CtorInit() m_bRewrite = false; m_bFreeMem = false; m_pIStream = 0; +#ifdef HOST_WINDOWS m_hFile = INVALID_HANDLE_VALUE; m_hModule = NULL; m_hMapping = 0; +#else + m_fd = -1; + m_isMmap = false; +#endif // HOST_WINDOWS m_pBaseData = 0; m_pData = 0; m_cbData = 0; @@ -198,12 +210,22 @@ HRESULT StgIO::Open( // Return code. // but would be much slower. // Create the new file, overwriting only if caller allows it. +#ifdef HOST_WINDOWS if ((m_hFile = WszCreateFile(szName, GENERIC_READ | GENERIC_WRITE, 0, 0, (fFlags & DBPROP_TMODEF_FAILIFTHERE) ? CREATE_NEW : CREATE_ALWAYS, 0, 0)) == INVALID_HANDLE_VALUE) { return (MapFileError(GetLastError())); } +#else // HOST_WINDOWS + MAKE_UTF8PTR_FROMWIDE_NOTHROW(u8Name, szName); + if ((m_fd = open(u8Name, + O_RDWR | O_CREAT | ((fFlags & DBPROP_TMODEF_FAILIFTHERE) ? O_EXCL : O_TRUNC), + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)) == -1) + { + return HRESULTFromErr(errno); + } +#endif // HOST_WINDOWS // Data will come from the file. m_iType = STGIO_HFILE; @@ -212,9 +234,13 @@ HRESULT StgIO::Open( // Return code. // memory view, it has to be opened already, so no file open. else if ((fFlags & DBPROP_TMODEF_WRITE) == 0) { +#ifdef HOST_WINDOWS // We have not opened the file nor loaded it as module _ASSERTE(m_hFile == INVALID_HANDLE_VALUE); _ASSERTE(m_hModule == NULL); +#else // HOST_WINDOWS + _ASSERTE(m_fd == -1); +#endif // HOST_WINDOWS // Open the file for read. Sharing is determined by caller, it can // allow other readers or be exclusive. @@ -266,6 +292,7 @@ HRESULT StgIO::Open( // Return code. #endif //!DACCESS_COMPILE && !TARGET_UNIX } +#ifdef HOST_WINDOWS if (m_hModule == NULL) { // We didn't get the loaded module (we either didn't want to or it failed) HandleHolder hFile(WszCreateFile(szName, @@ -291,6 +318,27 @@ HRESULT StgIO::Open( // Return code. m_iType = STGIO_HFILE; } +#else // HOST_WINDOWS + MAKE_UTF8PTR_FROMWIDE_NOTHROW(u8Name, szName); + int fd = open(u8Name, O_RDONLY); + if (fd == -1) + return HRESULTFromErr(errno); + + // Get size of file. + struct stat st; + if (fstat(fd, &st) != 0 || st.st_size == 0 || st.st_size >= UINT32_MAX) + { + // Can't read anything from an empty file. + close(fd); + return (PostError(CLDB_E_NO_DATA)); + } + + m_cbData = (ULONG)st.st_size; + + // Data will come from the file. + m_fd = fd; + m_iType = STGIO_HFILE; +#endif // HOST_WINDOWS } ErrExit: @@ -356,6 +404,7 @@ void StgIO::Close() // Intentional fall through to file case, if we kept handle open. FALLTHROUGH; +#ifdef HOST_WINDOWS case STGIO_HFILE: { // Free the file handle. @@ -373,6 +422,15 @@ void StgIO::Close() m_hModule = NULL; break; } +#else // HOST_WINDOWS + case STGIO_HFILE: + { + // Free the file handle. + if (m_fd != -1) + close(m_fd); + } + break; +#endif // HOST_WINDOWS // Free the stream pointer. case STGIO_STREAM: @@ -471,7 +529,11 @@ HRESULT StgIO::Read( // Return code. case STGIO_HFILE: case STGIO_HMODULE: { +#ifdef HOST_WINDOWS _ASSERTE((m_hFile != INVALID_HANDLE_VALUE) || (m_hModule != NULL)); +#else // HOST_WINDOWS + _ASSERTE(m_fd != -1); +#endif // HOST_WINDOWS // Backing store does its own paging. if (IsBackingStore() || IsMemoryMapped()) @@ -488,8 +550,12 @@ HRESULT StgIO::Read( // Return code. // If there is no backing store, this is just a read operation. else { +#ifdef HOST_WINDOWS _ASSERTE((m_iType == STGIO_HFILE) && (m_hFile != INVALID_HANDLE_VALUE)); _ASSERTE(m_hModule == NULL); +#else // HOST_WINDOWS + _ASSERTE((m_iType == STGIO_HFILE) && (m_fd != -1)); +#endif // HOST_WINDOWS ULONG cbTemp = 0; if (!pcbRead) @@ -622,6 +688,7 @@ HRESULT StgIO::Seek( // New offset. { case STGIO_HFILE: { +#ifdef HOST_WINDOWS // Use the file system's move. _ASSERTE(m_hFile != INVALID_HANDLE_VALUE); cbRtn = ::SetFilePointer(m_hFile, lVal, 0, fMoveType); @@ -636,6 +703,17 @@ HRESULT StgIO::Seek( // New offset. } m_cbOffset = cbRtn; } +#else // HOST_WINDOWS + _ASSERTE(m_fd != -1); + int64_t offRtn = (int64_t)lseek(m_fd, lVal, + fMoveType == FILE_BEGIN ? SEEK_SET : + (fMoveType == FILE_CURRENT ? SEEK_CUR : SEEK_END)); + if (offRtn < 0 || offRtn > UINT32_MAX) + { + IfFailGo(STG_E_INVALIDFUNCTION); + } + m_cbOffset = (ULONG)offRtn; +#endif // HOST_WINDOWS } break; @@ -784,6 +862,7 @@ HRESULT StgIO::MapFileToMem( // Return code. // If it is for exclusive, then we need to keep the handle open so the // file is locked, preventing other readers. Also leave it open if // in read/write mode so we can truncate and rewrite. +#ifdef HOST_WINDOWS if (m_hFile == INVALID_HANDLE_VALUE || ((m_fFlags & DBPROP_TMODEF_EXCLUSIVE) == 0 && (m_fFlags & DBPROP_TMODEF_WRITE) == 0)) { @@ -793,6 +872,17 @@ HRESULT StgIO::MapFileToMem( // Return code. VERIFY(CloseHandle(m_hFile)); m_hFile = INVALID_HANDLE_VALUE; } +#else // HOST_WINDOWS + if (m_fd == -1 || + ((m_fFlags & DBPROP_TMODEF_EXCLUSIVE) == 0 && (m_fFlags & DBPROP_TMODEF_WRITE) == 0)) + { + // If there was a handle open, then free it. + if (m_fd != -1) + { + VERIFY(close(m_fd) == 0); + m_fd = -1; + } +#endif // HOST_WINDOWS // Free the stream pointer. else if (m_pIStream != 0) @@ -814,13 +904,16 @@ HRESULT StgIO::MapFileToMem( // Return code. else { // Now we will map, so better have it right. +#ifdef HOST_WINDOWS _ASSERTE(m_hFile != INVALID_HANDLE_VALUE || m_iType == STGIO_STREAM); _ASSERTE(m_rgPageMap == 0); +#endif // HOST_WINDOWS // For read mode, use a memory mapped file since the size will never // change for the life of the handle. if ((m_fFlags & DBPROP_TMODEF_WRITE) == 0 && m_iType != STGIO_STREAM) { +#ifdef HOST_WINDOWS // Create a mapping object for the file. _ASSERTE(m_hMapping == 0); @@ -858,6 +951,16 @@ HRESULT StgIO::MapFileToMem( // Return code. m_pBaseData = m_pData = NULL; goto ErrExit; } +#else // HOST_WINDOWS + _ASSERTE(!m_isMmap); + if ((m_pBaseData = m_pData = mmap(nullptr, m_cbData, PROT_READ, MAP_SHARED, m_fd, 0)) == MAP_FAILED) + { + hr = HRESULTFromErr(errno); + m_pBaseData = m_pData = NULL; + goto ErrExit; + } + m_isMmap = true; +#endif // HOST_WINDOWS } // In write mode, we need the hybrid combination of being able to back up // the data in memory via cache, but then later rewrite the contents and @@ -898,9 +1001,11 @@ HRESULT StgIO::MapFileToMem( // Return code. // Check for errors and clean up. if (FAILED(hr)) { +#ifdef HOST_WINDOWS if (m_hMapping) CloseHandle(m_hMapping); m_hMapping = 0; +#endif // HOST_WINDOWS m_pBaseData = m_pData = 0; m_cbData = 0; } @@ -924,6 +1029,7 @@ HRESULT StgIO::ReleaseMappingObject() // Return code. return S_OK; } +#ifdef HOST_WINDOWS // Must have an allocated handle. _ASSERTE(m_hMapping != 0); @@ -941,6 +1047,17 @@ HRESULT StgIO::ReleaseMappingObject() // Return code. VERIFY(CloseHandle(m_hMapping)); m_hMapping = 0; } +#else // HOST_WINDOWS + _ASSERTE(m_isMmap); + + if (m_pData) + { + VERIFY(munmap(m_pData, m_cbData) == 0); + m_pData = nullptr; + } + + m_isMmap = false; +#endif // HOST_WINDOWS return S_OK; } @@ -1118,6 +1235,7 @@ HRESULT StgIO::FlushFileBuffers() { _ASSERTE(!IsReadOnly()); +#ifdef HOST_WINDOWS if (m_hFile != INVALID_HANDLE_VALUE) { if (::FlushFileBuffers(m_hFile)) @@ -1125,6 +1243,15 @@ HRESULT StgIO::FlushFileBuffers() else return (MapFileError(GetLastError())); } +#else // HOST_WINDOWS + if (m_fd != -1) + { + if (fsync(m_fd) == 0) + return (S_OK); + else + return HRESULTFromErr(errno); + } +#endif // HOST_WINDOWS return (S_OK); } @@ -1179,12 +1306,18 @@ HRESULT StgIO::WriteToDisk( // Return code. case STGIO_HFILE: case STGIO_HFILEMEM: { +#ifdef HOST_WINDOWS // Use the file system's move. _ASSERTE(m_hFile != INVALID_HANDLE_VALUE); // Do the write to disk. if (!::WriteFile(m_hFile, pbBuff, cbWrite, pcbWritten, 0)) hr = MapFileError(GetLastError()); +#else // HOST_WINDOWS + _ASSERTE(m_fd != -1); + if ((cbWritten = write(m_fd, pbBuff, cbWrite)) != cbWrite) + hr = HRESULTFromErr(errno); +#endif // HOST_WINDOWS } break; @@ -1233,9 +1366,15 @@ HRESULT StgIO::ReadFromDisk( // Return code. // Read only from file to avoid recursive logic. if (m_iType == STGIO_HFILE || m_iType == STGIO_HFILEMEM) { +#ifdef HOST_WINDOWS if (::ReadFile(m_hFile, pbBuff, cbBuff, pcbRead, 0)) return (S_OK); return (MapFileError(GetLastError())); +#else // HOST_WINDOWS + if ((cbRead = read(m_fd, pbBuff, cbBuff)) >= 0) + return (S_OK); + return HRESULTFromErr(errno); +#endif // HOST_WINDOWS } // Read directly from stream. else @@ -1254,11 +1393,20 @@ void StgIO::FreePageMap() if (m_bFreeMem && m_pBaseData) FreeMemory(m_pBaseData); // For mmf, close handles and free resources. +#ifdef HOST_WINDOWS else if (m_hMapping && m_pBaseData) { VERIFY(UnmapViewOfFile(m_pBaseData)); VERIFY(CloseHandle(m_hMapping)); + m_hMapping = 0; + } +#else // HOST_WINDOWS + else if (m_isMmap && m_pBaseData) + { + VERIFY(munmap(m_pBaseData, m_cbData) == 0); + m_isMmap = false; } +#endif // HOST_WINDOWS // For our own system, free memory. else if (m_rgPageMap && m_pBaseData) { @@ -1271,7 +1419,6 @@ void StgIO::FreePageMap() } m_pBaseData = 0; - m_hMapping = 0; m_cbData = 0; } diff --git a/src/coreclr/md/inc/stgio.h b/src/coreclr/md/inc/stgio.h index d46c9119a7db49..44312ee8981e04 100644 --- a/src/coreclr/md/inc/stgio.h +++ b/src/coreclr/md/inc/stgio.h @@ -240,7 +240,11 @@ class StgIO int IsBackingStore() { return (m_rgPageMap != 0); } int IsMemoryMapped() +#ifdef HOST_WINDOWS { return ((m_hMapping != NULL) || (m_hModule != NULL)); } +#else // + { return m_isMmap; } +#endif // HOST_WINDOWS void CtorInit(); HRESULT WriteToDisk(const void *pbBuff, ULONG cbWrite, ULONG *pcbWritten); @@ -258,9 +262,14 @@ class StgIO // Handles. IStream * m_pIStream; // For save to stream instead of file. +#ifdef HOST_WINDOWS HANDLE m_hFile; // The actual file with contents. HANDLE m_hMapping; // Mapping handle. HMODULE m_hModule; // If we load with LoadLibrary, this is the module (otherwise NULL). +#else // HOST_WINDOWS + int m_fd; + bool m_isMmap; +#endif // HOST_WINDOWS void * m_pBaseData; // Base address for memory mapped file. void * m_pData; // For memory mapped file read. ULONG m_cbData; // Size of in memory data. diff --git a/src/coreclr/minipal/Unix/CMakeLists.txt b/src/coreclr/minipal/Unix/CMakeLists.txt index 969c502323ea79..fe81f89151f4f3 100644 --- a/src/coreclr/minipal/Unix/CMakeLists.txt +++ b/src/coreclr/minipal/Unix/CMakeLists.txt @@ -3,6 +3,7 @@ set(SOURCES dn-u16.cpp dn-stdio.cpp memory.cpp + memmap.cpp ) add_library(coreclrminipal_objects diff --git a/src/coreclr/minipal/Unix/memmap.cpp b/src/coreclr/minipal/Unix/memmap.cpp new file mode 100644 index 00000000000000..9562c207588d8d --- /dev/null +++ b/src/coreclr/minipal/Unix/memmap.cpp @@ -0,0 +1,65 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +typedef char16_t WCHAR; + +#include +#include +#include +#include +#include +#include +#include +#include + +MemoryMappedFile* MemoryMappedFile::OpenImpl(const WCHAR* path, bool readWrite, uint32_t desiredSize, void* desiredAddress) +{ + assert(path); + size_t pathLen = u16_strlen(path); + size_t pathU8Len = minipal_get_length_utf16_to_utf8((CHAR16_T*)path, pathLen, 0); + char* pathU8 = new char[pathU8Len + 1]; + size_t ret = minipal_convert_utf16_to_utf8((CHAR16_T*)path, pathLen, pathU8, pathU8Len, 0); + pathU8[ret] = '\0'; + + void* address = nullptr; + + int fd = open(pathU8, readWrite ? (O_RDWR | O_CREAT) : O_RDONLY, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); + delete[] pathU8; + + if (fd == -1) + goto Fail; + + struct stat st; + if (fstat(fd, &st) != 0) + goto Fail; + + // All the use cases are not accepting files >4GB + if (st.st_size > UINT32_MAX) + goto Fail; + + if (st.st_size < desiredSize) + { + if (ftruncate(fd, desiredSize) != 0) + goto Fail; + if (fstat(fd, &st) != 0 || st.st_size != desiredSize) + goto Fail; + } + + address = mmap(desiredAddress, (size_t)st.st_size, readWrite ? (PROT_WRITE | PROT_READ) : PROT_READ , MAP_SHARED, fd, 0); + if (address == MAP_FAILED) + goto Fail; + + close(fd); + return new MemoryMappedFile(address, (uint32_t)st.st_size); + +Fail: + if (fd != -1) + close(fd); + return nullptr; +} + +MemoryMappedFile::~MemoryMappedFile() +{ + if (m_address != nullptr) + munmap(m_address, m_size); +} diff --git a/src/coreclr/minipal/Windows/CMakeLists.txt b/src/coreclr/minipal/Windows/CMakeLists.txt index fa6ed5bd8a4b82..217f484f485eee 100644 --- a/src/coreclr/minipal/Windows/CMakeLists.txt +++ b/src/coreclr/minipal/Windows/CMakeLists.txt @@ -3,6 +3,7 @@ set(SOURCES dn-u16.cpp dn-stdio.cpp memory.cpp + memmap.cpp ) add_library(coreclrminipal STATIC diff --git a/src/coreclr/minipal/Windows/memmap.cpp b/src/coreclr/minipal/Windows/memmap.cpp new file mode 100644 index 00000000000000..57464fd5938b45 --- /dev/null +++ b/src/coreclr/minipal/Windows/memmap.cpp @@ -0,0 +1,65 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#include +#include +#include + +MemoryMappedFile* MemoryMappedFile::OpenImpl(const WCHAR* path, bool readWrite, uint32_t desiredSize, void* desiredAddress) +{ + HANDLE hFile = INVALID_HANDLE_VALUE; + HANDLE hFileMapping = NULL; + + hFile = CreateFileW(path, + readWrite ? (GENERIC_READ | GENERIC_WRITE) : GENERIC_READ, + FILE_SHARE_READ, + NULL, + readWrite ? CREATE_ALWAYS : OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, + NULL); + if (hFile == INVALID_HANDLE_VALUE) + goto Fail; + + LARGE_INTEGER li; + // All the use cases are not accepting files >4GB + if (!GetFileSizeEx(hFile, &li) || li.HighPart != 0) + goto Fail; + + uint32_t size = li.LowPart; + + hFileMapping = CreateFileMappingW(hFile, + NULL, + readWrite ? PAGE_READWRITE : PAGE_READONLY, + 0, + desiredSize, + NULL); + if (hFileMapping == NULL) + goto Fail; + + void* address = MapViewOfFileEx(hFileMapping, + readWrite ? FILE_MAP_ALL_ACCESS : FILE_MAP_READ, + 0, + 0, + 0, + desiredAddress); + if (address == nullptr) + goto Fail; + + CloseHandle(hFile); + CloseHandle(hFileMapping); + + return new MemoryMappedFile(address, size); + +Fail: + if (hFile != INVALID_HANDLE_VALUE) + CloseHandle(hFile); + if (hFileMapping != NULL) + CloseHandle(hFileMapping); + return nullptr; +} + +MemoryMappedFile::~MemoryMappedFile() +{ + if (m_address != nullptr) + UnmapViewOfFile(m_address); +} diff --git a/src/coreclr/minipal/dn-memmap.h b/src/coreclr/minipal/dn-memmap.h new file mode 100644 index 00000000000000..11258e9220a07e --- /dev/null +++ b/src/coreclr/minipal/dn-memmap.h @@ -0,0 +1,36 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// + +#ifndef DN_MEMMAP_H +#define DN_MEMMAP_H + +#include + +class MemoryMappedFile final +{ + void* m_address; + uint32_t m_size; + + MemoryMappedFile(void* address, uint32_t size) + : m_address(address) + , m_size(size) + {} + static MemoryMappedFile* OpenImpl(const WCHAR* path, bool readWrite, uint32_t desiredSize, void* desiredAddress); + +public: + static MemoryMappedFile* Open(const WCHAR* path) { return OpenImpl(path, false, 0, nullptr); } + static MemoryMappedFile* OpenRW(const WCHAR* path, uint32_t desiredSize, void* desiredAddress) + { + return OpenImpl(path, true, desiredSize, desiredAddress); + } + ~MemoryMappedFile(); + + MemoryMappedFile(const MemoryMappedFile&) = delete; + MemoryMappedFile& operator=(const MemoryMappedFile&) = delete; + + void* Address() { return m_address; } + uint32_t Size() { return m_size; } +}; + +#endif // DN_MEMMAP_H diff --git a/src/coreclr/tools/metainfo/mdobj.cpp b/src/coreclr/tools/metainfo/mdobj.cpp index 8d9d604280213b..5c8020b8bd38cc 100644 --- a/src/coreclr/tools/metainfo/mdobj.cpp +++ b/src/coreclr/tools/metainfo/mdobj.cpp @@ -5,6 +5,7 @@ #include #include #include "mdinfo.h" +#include #ifndef STRING_BUFFER_LEN #define STRING_BUFFER_LEN 4096 @@ -55,44 +56,6 @@ static HRESULT FindObjMetaData(PVOID pImage, PVOID *ppMetaData, long *pcbMetaDat return (S_OK); } - -// This function returns the address to the MapView of file and file size. -void GetMapViewOfFile(_In_ WCHAR *szFile, PBYTE *ppbMap, DWORD *pdwFileSize) -{ - HANDLE hMapFile; - DWORD dwHighSize; - - HANDLE hFile = WszCreateFile(szFile, - GENERIC_READ, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, - NULL); - if (hFile == INVALID_HANDLE_VALUE) - MDInfo::Error("CreateFileA failed!"); - - *pdwFileSize = GetFileSize(hFile, &dwHighSize); - - if ((*pdwFileSize == 0xFFFFFFFF) && (GetLastError() != NO_ERROR)) - { - CloseHandle(hFile); - MDInfo::Error("GetFileSize failed!"); - } - _ASSERTE(dwHighSize == 0); - - hMapFile = CreateFileMappingW(hFile, NULL, PAGE_READONLY, 0, 0, NULL); - CloseHandle(hFile); - if (!hMapFile) - MDInfo::Error("CreateFileMappingW failed!"); - - *ppbMap = (PBYTE) MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0); - CloseHandle(hMapFile); - - if (!*ppbMap) - MDInfo::Error("MapViewOfFile failed!"); -} // void GetMapViewOfFile() - // This function skips a member given the pointer to the member header // and returns a pointer to the next header. PBYTE SkipMember(PBYTE pbMapAddress) @@ -177,7 +140,15 @@ void DisplayArchive(_In_z_ WCHAR* szFile, ULONG DumpFilter, _In_opt_z_ WCHAR* sz HRESULT hr; char szString[1024]; - GetMapViewOfFile(szFile, &pbMapAddress, &dwFileSize); + MemoryMappedFile* f = CreateMappedFile(szFile); + if (f == nullptr) + { + MDInfo::Error("CreateMappedFile failed!"); + return; + } + + pbMapAddress = (PBYTE)f->Address(); + dwFileSize = (DWORD)f->Size(); pbStartAddress = pbMapAddress; // Verify and skip archive signature. @@ -241,7 +212,7 @@ void DisplayArchive(_In_z_ WCHAR* szFile, ULONG DumpFilter, _In_opt_z_ WCHAR* sz pbMapAddress = SkipMember(pbMapAddress); } - UnmapViewOfFile(pbStartAddress); + delete f; } // void DisplayArchive() // DisplayFile() function diff --git a/src/coreclr/utilcode/longfilepathwrappers.cpp b/src/coreclr/utilcode/longfilepathwrappers.cpp index a0586a0b3ec97b..c4934f1f73b354 100644 --- a/src/coreclr/utilcode/longfilepathwrappers.cpp +++ b/src/coreclr/utilcode/longfilepathwrappers.cpp @@ -343,6 +343,32 @@ CreateFileWrapper( return ret; } +MemoryMappedFile* CreateMappedFileWrapper(const WCHAR* filename) +{ + CONTRACTL + { + NOTHROW; + } + CONTRACTL_END; + + EX_TRY + { + LongPathString path(LongPathString::Literal, filename); + + if (SUCCEEDED(LongFile::NormalizePath(path))) + { + return MemoryMappedFile::Open(path.GetUnicode()); + } + } + EX_CATCH + { + // Swallow all exceptions + } + EX_END_CATCH + + return nullptr; +} + int u16_fopen_wrapper(FILE** stream, const WCHAR* filename, const WCHAR* mode) { CONTRACTL @@ -362,7 +388,7 @@ int u16_fopen_wrapper(FILE** stream, const WCHAR* filename, const WCHAR* mode) } EX_CATCH { - return -1; + // Swallow all exceptions } EX_END_CATCH diff --git a/src/coreclr/utilcode/stresslog.cpp b/src/coreclr/utilcode/stresslog.cpp index b1b415c0dde833..a3c27c4ea5773f 100644 --- a/src/coreclr/utilcode/stresslog.cpp +++ b/src/coreclr/utilcode/stresslog.cpp @@ -16,6 +16,7 @@ #define DONOT_DEFINE_ETW_CALLBACK #include "eventtracebase.h" #include "minipal/time.h" +#include #if !defined(STRESS_LOG_READONLY) #ifdef HOST_WINDOWS @@ -181,9 +182,9 @@ void ReplacePid(LPCWSTR original, LPWSTR replaced, size_t replacedLength) } #ifdef MEMORY_MAPPED_STRESSLOG -static LPVOID CreateMemoryMappedFile(LPWSTR logFilename, size_t maxBytesTotal) +static LPVOID CreateMemoryMappedFile(LPWSTR logFilename, uint32_t maxBytesTotal) { - if (maxBytesTotal < sizeof(StressLog::StressLogHeader)) + if ((size_t)maxBytesTotal < sizeof(StressLog::StressLogHeader)) { return nullptr; } @@ -191,27 +192,9 @@ static LPVOID CreateMemoryMappedFile(LPWSTR logFilename, size_t maxBytesTotal) WCHAR logFilenameReplaced[MAX_PATH]; ReplacePid(logFilename, logFilenameReplaced, MAX_PATH); - HandleHolder hFile = WszCreateFile(logFilenameReplaced, - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ, - NULL, // default security descriptor - CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL); - - if (hFile == INVALID_HANDLE_VALUE) - { - return nullptr; - } - - size_t fileSize = maxBytesTotal; - HandleHolder hMap = CreateFileMapping(hFile, NULL, PAGE_READWRITE, (DWORD)(fileSize >> 32), (DWORD)fileSize, NULL); - if (hMap == NULL) - { - return nullptr; - } - - return MapViewOfFileEx(hMap, FILE_MAP_ALL_ACCESS, 0, 0, fileSize, MEMORY_MAPPED_STRESSLOG_BASE_ADDRESS); + // The memory map will be released at process exit + MemoryMappedFile* mmap = MemoryMappedFile::OpenRW(logFilename, maxBytesTotal, MEMORY_MAPPED_STRESSLOG_BASE_ADDRESS); + return mmap ? mmap->Address() : nullptr; } #endif //MEMORY_MAPPED_STRESSLOG @@ -267,7 +250,7 @@ void StressLog::Initialize(unsigned facilities, unsigned level, unsigned maxByte StressLogChunk::s_memoryMapped = false; if (logFilename != nullptr) { - theLog.hMapView = CreateMemoryMappedFile(logFilename, maxBytesTotal); + theLog.hMapView = CreateMemoryMappedFile(logFilename, (uint32_t)maxBytesTotal); if (theLog.hMapView != nullptr) { StressLogChunk::s_memoryMapped = true;