Description
I've had some issue with Aeron on Windows and as result have been looking at this code (in MemoryMappedFile.cpp):
MemoryMappedFile::ptr_t MemoryMappedFile::createNew(const char *filename, size_t offset, size_t size)
{
FileHandle fd;
fd.handle = CreateFile(filename, GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (fd.handle == INVALID_HANDLE_VALUE)
{
throw IOException(std::string("Failed to create file: ") + filename + " " + toString(GetLastError()), SOURCEINFO);
}
OnScopeExit tidy(
[&]()
{
CloseHandle(fd.handle);
});
if (!fill(fd, size, 0))
{
throw IOException(std::string("Failed to write to file: ") + filename + " " + toString(GetLastError()), SOURCEINFO);
}
return MemoryMappedFile::ptr_t(new MemoryMappedFile(fd, offset, size, false));
}
While similar thing on the Linux is OK (mmap man says file handle does not need to remain open after mapping is etablished), Microsoft Docs for Windows say right the opposite (https://docs.microsoft.com/en-us/windows/win32/memory/creating-a-file-mapping-object):
The first step in mapping a file is to open the file by calling the CreateFile function.
To ensure that other processes cannot write to the portion of the file that is mapped,
you should open the file with exclusive access.
In addition, the file handle should remain open until the process no longer needs
the file mapping object.
But what we can see here, file handle is unconditionally closed with this one:
OnScopeExit tidy(
[&]()
{
CloseHandle(fd.handle);
});
Instead, on success it should have been saved inside MemoryMappedFile object and closed only after mapping is closed. But here is also error in the MemoryMappedFile::cleanUp()
- file handle is closed first:
void MemoryMappedFile::cleanUp()
{
if (m_file)
{
CloseHandle(m_file);
}
if (m_memory)
{
UnmapViewOfFile(m_memory);
}
if (m_mapping)
{
CloseHandle(m_mapping);
}
}
while it must be closed last, after mapping is closed, i.e. move first if to the end of this function.