[llvm] [Support] Always call FlushFileBuffers() when unmapping memory on Windows (PR #78597)

Martin Storsjö via llvm-commits llvm-commits at lists.llvm.org
Thu Jan 18 07:19:14 PST 2024


https://github.com/mstorsjo updated https://github.com/llvm/llvm-project/pull/78597

>From 109715766b00d8e4d3fac9b0e6c084344cbb5f7f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Martin=20Storsj=C3=B6?= <martin at martin.st>
Date: Thu, 18 Jan 2024 16:54:38 +0200
Subject: [PATCH] [Support] Always call FlushFileBuffers() when unmapping
 memory on Windows

This reverts the functional parts of commit
3b9b4d2156673edda50584086fbfb0d66460b4d2.

The conditional call to FlushFileBuffers was added to work around
a rare kernel bug, see acd8791c2619f2afc0347c1bff073b32fbffb5d6
and 3b9b4d2156673edda50584086fbfb0d66460b4d2.

However, closing a memory mapping that has been written to, can
also need a call to FlushFileBuffers in other cases. When operating
on a VirtualBox Shared Folder file system, the output file ends
up unwritten/unflushed (with the right size but all zeros), if
written via a memory mapping, then the file is renamed before
the output handle is closed (this is what is done in lld-link).

The sequence to trigger the issue on the VirtualBox Shared Folders
is this, summarized:

    file = CreateFile()
    mapping = CreateFileMapping(file)
    mem = MapViewOfFile()
    CloseHandle(mapping)
    write(mem)
    UnmapViewOfFile(mem)
    SetFileInformationByHandle(file, FileRenameInfo)
    CloseHandle(file)

With this sequence, the output file always ends up with all zeros.
See https://github.com/mstorsjo/llvm-mingw/issues/393#issuecomment-1895640756
for a full reproduction example.

The issue can seem elusive, as we conditionally do the call to
FlushFileBuffers() to work around the rare kernel bug, whenever
running on versions of Windows older than 10.0.0.17763.

This fixes downstream bug
https://github.com/mstorsjo/llvm-mingw/issues/393.
---
 llvm/lib/Support/Windows/Path.inc | 27 +++++++--------------------
 1 file changed, 7 insertions(+), 20 deletions(-)

diff --git a/llvm/lib/Support/Windows/Path.inc b/llvm/lib/Support/Windows/Path.inc
index 2bf68b7972e746f..7559de26bcabb48 100644
--- a/llvm/lib/Support/Windows/Path.inc
+++ b/llvm/lib/Support/Windows/Path.inc
@@ -936,30 +936,11 @@ mapped_file_region::mapped_file_region(sys::fs::file_t fd, mapmode mode,
     copyFrom(mapped_file_region());
 }
 
-static bool hasFlushBufferKernelBug() {
-  static bool Ret{GetWindowsOSVersion() < llvm::VersionTuple(10, 0, 0, 17763)};
-  return Ret;
-}
-
-static bool isEXE(StringRef Magic) {
-  static const char PEMagic[] = {'P', 'E', '\0', '\0'};
-  if (Magic.starts_with(StringRef("MZ")) && Magic.size() >= 0x3c + 4) {
-    uint32_t off = read32le(Magic.data() + 0x3c);
-    // PE/COFF file, either EXE or DLL.
-    if (Magic.substr(off).starts_with(StringRef(PEMagic, sizeof(PEMagic))))
-      return true;
-  }
-  return false;
-}
-
 void mapped_file_region::unmapImpl() {
   if (Mapping) {
-
-    bool Exe = isEXE(StringRef((char *)Mapping, Size));
-
     ::UnmapViewOfFile(Mapping);
 
-    if (Mode == mapmode::readwrite && Exe && hasFlushBufferKernelBug()) {
+    if (Mode == mapmode::readwrite) {
       // There is a Windows kernel bug, the exact trigger conditions of which
       // are not well understood.  When triggered, dirty pages are not properly
       // flushed and subsequent process's attempts to read a file can return
@@ -967,6 +948,12 @@ void mapped_file_region::unmapImpl() {
       // sufficient to ensure that this bug is not triggered.
       // The bug only occurs when writing an executable and executing it right
       // after, under high I/O pressure.
+      //
+      // Separately, on VirtualBox Shared Folder mounts, writes via memory maps
+      // always end up unflushed (regardless of version of Windows, unless
+      // flushed with this explicit call, if they are renamed with
+      // SetFileInformationByHandle(FileRenameInfo) before closing the output
+      // handle.
       ::FlushFileBuffers(FileHandle);
     }
 



More information about the llvm-commits mailing list