[llvm] Avoid calling `GetFileAttributesW` in Windows' `fs::access` when checking for existence (PR #83495)

Jeremy Day via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 29 14:35:16 PST 2024


https://github.com/z2oh created https://github.com/llvm/llvm-project/pull/83495

Fixes https://github.com/llvm/llvm-project/issues/83046

There is a race condition when calling `GetFileAttributesW` that can cause it to return `ERROR_ACCESS_DENIED` on a path which exists, which is unexpected for callers using this function to check for file existence by passing `AccessMode::Exist`. This was manifesting as a compiler crash on Windows downstream in the Swift compiler when using the `-index-store-path` flag (more information in https://github.com/apple/llvm-project/issues/8224).

I looked for alternate APIs to avoid bringing in `shlwapi.h`, but didn't see any good candidates. I'm not tied at all to this solution, any feedback and alternative approaches are more than welcome.

>From 645f01fbb5618ebc012a7b5d2177a5c168bdacde Mon Sep 17 00:00:00 2001
From: Jeremy Day <jeremy at thebrowser.company>
Date: Thu, 29 Feb 2024 11:41:42 -0800
Subject: [PATCH] Avoid calling GetFileAttributesW in Windows' fs::access when
 checking for existence

---
 llvm/lib/Support/CMakeLists.txt   | 2 +-
 llvm/lib/Support/Windows/Path.inc | 9 +++++++++
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt
index 1f2d82427552f7..83889535d88f1b 100644
--- a/llvm/lib/Support/CMakeLists.txt
+++ b/llvm/lib/Support/CMakeLists.txt
@@ -40,7 +40,7 @@ endif()
 if( MSVC OR MINGW )
   # libuuid required for FOLDERID_Profile usage in lib/Support/Windows/Path.inc.
   # advapi32 required for CryptAcquireContextW in lib/Support/Windows/Path.inc.
-  set(system_libs ${system_libs} psapi shell32 ole32 uuid advapi32 ws2_32)
+  set(system_libs ${system_libs} psapi shell32 shlwapi ole32 uuid advapi32 ws2_32)
 elseif( CMAKE_HOST_UNIX )
   if( HAVE_LIBRT )
     set(system_libs ${system_libs} rt)
diff --git a/llvm/lib/Support/Windows/Path.inc b/llvm/lib/Support/Windows/Path.inc
index 3e4c1f74161c6f..03befdd5412628 100644
--- a/llvm/lib/Support/Windows/Path.inc
+++ b/llvm/lib/Support/Windows/Path.inc
@@ -27,6 +27,7 @@
 #include "llvm/Support/Windows/WindowsSupport.h"
 #include <shellapi.h>
 #include <shlobj.h>
+#include <shlwapi.h>
 
 #undef max
 
@@ -620,6 +621,14 @@ std::error_code access(const Twine &Path, AccessMode Mode) {
   if (std::error_code EC = widenPath(Path, PathUtf16))
     return EC;
 
+  if (Mode == AccessMode::Exist) {
+    if (::PathFileExistsW(PathUtf16.begin())) {
+      return std::error_code();
+    } else {
+      return errc::no_such_file_or_directory;
+    }
+  }
+
   DWORD Attributes = ::GetFileAttributesW(PathUtf16.begin());
 
   if (Attributes == INVALID_FILE_ATTRIBUTES) {



More information about the llvm-commits mailing list