-
Notifications
You must be signed in to change notification settings - Fork 11
Description
Summary:
When using the LLVM toolchain to compile and link executables targeted to reside on a VirtualBox shared folder, the resulting files have the correct size but consist only of null bytes - unless an explicit call to FlushFileBuffers() is added.
Environment:
Host OS: [MacOS 14.1.1]
VirtualBox Version: [Version 7.0.12 r159484 (Qt5.15.2)]
Guest OS: [Window 11 Pro 22H2 Build: 22621.3007]
LLVM-Mingw Version: [17.0.6 (and nightly 18.0)]
Replicated by LLVM-MingW Owner on Jan 17 2024
Steps to Reproduce:
- Set up a shared folder in VirtualBox.
- Use the following minimal example code to replicate the behavior of the LLD linker:
#include <windows.h>
#include <stdio.h>
#include <tchar.h> // Include for TCHAR and related functions
void PrintLastError(int line) {
DWORD errorMessageID = GetLastError();
if(errorMessageID == 0) {
_tprintf(_T("Operation successful.\n"));
return;
}
LPTSTR messageBuffer = NULL;
size_t size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&messageBuffer, 0, NULL);
_tprintf(_T("Line: %d Error code %lu: %s\n"), line, errorMessageID, messageBuffer);
LocalFree(messageBuffer);
}
int main() {
TCHAR tempFilePath[MAX_PATH] = _T("Z:\\test.exe.tmp");
wchar_t finalFilePath[MAX_PATH] = L"Z:\\test.exe";
// Create a file
HANDLE hFile = CreateFile(tempFilePath, GENERIC_READ | GENERIC_WRITE | DELETE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
PrintLastError(__LINE__);
return 1;
}
// Create a file mapping object
HANDLE hMapFile = CreateFileMapping(hFile, NULL, PAGE_READWRITE, 0, 1024, NULL);
if (hMapFile == NULL) {
PrintLastError(__LINE__);
CloseHandle(hFile);
return 1;
}
// Map a view of the file into the address space
LPVOID pMapView = MapViewOfFile(hMapFile, FILE_MAP_ALL_ACCESS, 0, 0, 1024);
if (pMapView == NULL) {
PrintLastError(__LINE__);
CloseHandle(hMapFile);
CloseHandle(hFile);
return 1;
}
// Close the mapping handle; the mapping is still kept open.
CloseHandle(hMapFile);
// Write to the memory area
const char data[] = "Sample Data";
memcpy(pMapView, data, sizeof(data));
// Unmap the file
UnmapViewOfFile(pMapView);
// FlushFileBuffers(hFile);
char buf[sizeof(FILE_RENAME_INFO) + sizeof(wchar_t)*100];
FILE_RENAME_INFO *rename = (FILE_RENAME_INFO*)buf;
rename->ReplaceIfExists = 1;
rename->RootDirectory = 0;
rename->FileNameLength = wcslen(finalFilePath) * sizeof(wchar_t);
memcpy(rename->FileName, finalFilePath, wcslen(finalFilePath) * sizeof(wchar_t));
// Rename with SetFileInformationByHandle(FileRenameInfo)
if (!SetFileInformationByHandle(hFile, FileRenameInfo, buf, sizeof(buf))) {
PrintLastError(__LINE__);
CloseHandle(hFile);
return 1;
}
CloseHandle(hFile);
_tprintf(_T("File operation completed successfully.") );
return 0;
}
- Compile and run this code, targeting the VirtualBox shared folder.
Expected Behavior:
The executable file should be created with the specified data written to it.
Actual Behavior:
The executable file is of the right size but consists entirely of null bytes.
Additional Information:
This issue was initially reported to the LLVM-Mingw project (Issue #393). It was confirmed and replicated with a reduced sample.
The issue has been reported to the LLVM project and is being addressed in a pull request (PR #78597).
It was suggested by the maintainer of LLVM-Mingw to report this issue to VirtualBox, as it was not replicable on other virtualization software.
Potential Impact:
This issue impacts users who compile and link using LLVM's LLD on VirtualBox shared folders, as well as anyone using memory mapped files in a similar way to the LLD executable linkage process. potentially affecting a range of development and testing scenarios.