[llvm] Fix overlay vfs iteration over empty directories (PR #126093)

Thomas Gibson-Robinson via llvm-commits llvm-commits at lists.llvm.org
Thu Feb 6 09:23:32 PST 2025


https://github.com/tomgr created https://github.com/llvm/llvm-project/pull/126093

Before this fix, iterating over an empty directory with a OverlayFileSystem would incorrectly return an
errc::no_such_file_or_directory error.

>From cad6e54504dfe2d7ca76aa083bb2c2dcc2c7fce8 Mon Sep 17 00:00:00 2001
From: Thomas Gibson-Robinson <tom at cocotec.io>
Date: Thu, 6 Feb 2025 17:20:24 +0000
Subject: [PATCH] Fix overlay vfs iteration over empty directories

Before this fix, iterating over an empty directory with a
OverlayFileSystem would incorrectly return an
errc::no_such_file_or_directory error.
---
 llvm/lib/Support/VirtualFileSystem.cpp        | 14 ++++++-----
 .../Support/VirtualFileSystemTest.cpp         | 24 +++++++++++++++++++
 2 files changed, 32 insertions(+), 6 deletions(-)

diff --git a/llvm/lib/Support/VirtualFileSystem.cpp b/llvm/lib/Support/VirtualFileSystem.cpp
index e489282281d269e..2e09a0ea2a53dac 100644
--- a/llvm/lib/Support/VirtualFileSystem.cpp
+++ b/llvm/lib/Support/VirtualFileSystem.cpp
@@ -546,16 +546,13 @@ class CombiningDirIterImpl : public llvm::vfs::detail::DirIterImpl {
 
   /// Sets \c CurrentDirIter to the next iterator in the list, or leaves it as
   /// is (at its end position) if we've already gone through them all.
-  std::error_code incrementIter(bool IsFirstTime) {
+  std::error_code incrementIter() {
     while (!IterList.empty()) {
       CurrentDirIter = IterList.back();
       IterList.pop_back();
       if (CurrentDirIter != directory_iterator())
         break; // found
     }
-
-    if (IsFirstTime && CurrentDirIter == directory_iterator())
-      return errc::no_such_file_or_directory;
     return {};
   }
 
@@ -563,10 +560,15 @@ class CombiningDirIterImpl : public llvm::vfs::detail::DirIterImpl {
     assert((IsFirstTime || CurrentDirIter != directory_iterator()) &&
            "incrementing past end");
     std::error_code EC;
-    if (!IsFirstTime)
+    if (IsFirstTime) {
+      // If the list of iterators is empty then this mmust mean that none of the
+      // overlays have this directory.
+      if (IterList.empty())
+        EC = errc::no_such_file_or_directory;
+    } else
       CurrentDirIter.increment(EC);
     if (!EC && CurrentDirIter == directory_iterator())
-      EC = incrementIter(IsFirstTime);
+      EC = incrementIter();
     return EC;
   }
 
diff --git a/llvm/unittests/Support/VirtualFileSystemTest.cpp b/llvm/unittests/Support/VirtualFileSystemTest.cpp
index eb590e474c2ecc0..66396e6cc3301cf 100644
--- a/llvm/unittests/Support/VirtualFileSystemTest.cpp
+++ b/llvm/unittests/Support/VirtualFileSystemTest.cpp
@@ -3675,3 +3675,27 @@ TEST(TracingFileSystemTest, PrintOutput) {
             "  InMemoryFileSystem\n",
             Output);
 }
+
+TEST(VirtualFileSystemTest, RecursiveDirectoryIteratorEmpty) {
+  TempDir TestDirectory("virtual-file-system-test", /*Unique*/ true);
+  auto FS = llvm::makeIntrusiveRefCnt<llvm::vfs::OverlayFileSystem>(
+      vfs::getRealFileSystem());
+
+  // An empty directory should not fail
+  {
+    std::error_code EC;
+    vfs::recursive_directory_iterator I =
+        vfs::recursive_directory_iterator(*FS, TestDirectory.path(), EC);
+    ASSERT_FALSE(EC);
+    EXPECT_EQ(vfs::recursive_directory_iterator(), I);
+  }
+
+  // But a non-existent directory should fail
+  {
+    std::error_code EC;
+    vfs::recursive_directory_iterator I =
+        vfs::recursive_directory_iterator(*FS, "/non-existent", EC);
+    ASSERT_EQ(EC, std::errc::no_such_file_or_directory);
+    EXPECT_EQ(vfs::recursive_directory_iterator(), I);
+  }
+}



More information about the llvm-commits mailing list