VirtualBox

Opened 14 months ago

Last modified 14 months ago

#21967 new defect

Memory Mapped file not flushed to disk file located on Host Shared Folder - Windows Guest

Reported by: ron[ny] Owned by:
Component: shared folders Version: VirtualBox-7.0.14
Keywords: Cc: ron[ny]
Guest type: Windows Host type: Mac OS X

Description

Summary:

Discovered when using the LLVM toolchain to compile and link executables targeted to reside on a VirtualBox shared folder, the resulting executable had the correct size but consisted of only null bytes. Subsequent review with LLVM-MingW owner revealed that adding an explicit call to FlushFileBuffers() solves the bug.

Environment:

Host OS: [MacOS 14.1.1] VirtualBox Version: [7.0.14] Guest OS: [Window 11 Pro 22H2 Build: 22621.3007]

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;
}

Expected Behavior:

The sample target file should be created with the specified data written to it.

Actual Behavior:

The target file is of the right size but consists entirely of null bytes.

Additional Information:

This issue was initially reported to the LLVM-Mingw project (https://github.com/mstorsjo/llvm-mingw/issues/393). It was confirmed by the LLVM-MingW owner and replicated with a reduced sample.

The issue has been reported to the LLVM project and a workaround this bug is being addressed in a pull request (https://github.com/llvm/llvm-project/pull/78597).

It was suggested by the maintainer of LLVM-Mingw to report this issue to VirtualBox Bug Tracker, as it was not replicable on other virtualization software.

Potential Impact:

This issue impacts developers 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 (examplified by the attached reduced sample). potentially affecting a range of development and testing scenarios.

Attachments (1)

testkeep.cpp (2.8 KB ) - added by ron[ny] 14 months ago.

Download all attachments as: .zip

Change History (3)

by ron[ny], 14 months ago

Attachment: testkeep.cpp added

comment:1 by fth0, 14 months ago

I don't know if it plays any role in your issue, but after skimming over your LLVM-Mingw issue thread, I think that the following perhaps might interest you:

For many years now, there has been a VirtualBox issue that prevents a Windows guest from running executables located in VirtualBox Shared Folders, giving the apparently wrong error message "The specified path does not exist". This only happens when using drive letter mappings (e.g. Z:), but not when using UNC paths. Two years ago, a user (and later myself) discovered that the length of the share name and the fully qualified file name in the guest play a tricky role (see #20702 for the gory details).

As an idea, could you replace any occurrence of drive letter mappings by UNC paths for a test?

comment:2 by ron[ny], 14 months ago

Not at all - in my case I have no problem, compiling, linking, and running exeutables on that same network drive. The only issue is this very specific case, i.e. memory mapped file NOT COMMITTED to disk, as used in the LLD workflow and thus appearing if one uses LLVM toolchain targeting such VM shared folder on a Windows guest.

Note: See TracTickets for help on using tickets.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette