Skip to content

Bug: Null Byte Executables Created on VirtualBox Shared Folders with LLVM's LLD linker #2

@ronpinkas

Description

@ronpinkas

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:

  1. Set up a shared folder in VirtualBox.
  2. 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;
}

  1. 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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions