[libcxx-commits] [libcxx] [libc++] Fix filesystem::remove_all bug with read-only nested directory (PR #197104)

Jake Egan via libcxx-commits libcxx-commits at lists.llvm.org
Mon May 25 13:17:23 PDT 2026


https://github.com/jakeegan updated https://github.com/llvm/llvm-project/pull/197104

>From a429230b2471fa6ff4b84d83fc60dcc40b109dc7 Mon Sep 17 00:00:00 2001
From: Jake Egan <jake.egan at ibm.com>
Date: Tue, 12 May 2026 00:14:03 -0400
Subject: [PATCH 1/6] [libc++] Fix filesystem::remove_all bug with read-only
 nested directory

---
 libcxx/src/filesystem/operations.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
index 745db87ce3736..6afcec07b374d 100644
--- a/libcxx/src/filesystem/operations.cpp
+++ b/libcxx/src/filesystem/operations.cpp
@@ -904,6 +904,9 @@ uintmax_t remove_all_impl(int parent_directory, const path& p, error_code& ec) {
         break; // we're done iterating through the directory
       } else {
         count += remove_all_impl(fd, str, ec);
+        // If there's an error removing the child, return immediately to preserve the error code.
+        if (ec)
+          return count;
       }
     }
 

>From 9c04e74b3a2d7cd5116798e3035be53de332e920 Mon Sep 17 00:00:00 2001
From: Jake Egan <jake.egan at ibm.com>
Date: Fri, 15 May 2026 10:58:36 -0400
Subject: [PATCH 2/6] Add test

---
 .../bad_perms_parent.pass.cpp                 | 38 +++++++++++++++++++
 1 file changed, 38 insertions(+)
 create mode 100644 libcxx/test/libcxx/input.output/filesystems/fs.op.funcs/fs.op.remove_all/bad_perms_parent.pass.cpp

diff --git a/libcxx/test/libcxx/input.output/filesystems/fs.op.funcs/fs.op.remove_all/bad_perms_parent.pass.cpp b/libcxx/test/libcxx/input.output/filesystems/fs.op.funcs/fs.op.remove_all/bad_perms_parent.pass.cpp
new file mode 100644
index 0000000000000..1c129e9c08c39
--- /dev/null
+++ b/libcxx/test/libcxx/input.output/filesystems/fs.op.funcs/fs.op.remove_all/bad_perms_parent.pass.cpp
@@ -0,0 +1,38 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14
+// UNSUPPORTED: no-filesystem
+
+// Verify that remove_all reports the correct error (permission_denied)
+// when the parent directory has insufficient permissions.
+
+// <filesystem>
+
+#include <filesystem>
+
+#include "test_macros.h"
+#include "filesystem_test_helper.h"
+namespace fs = std::filesystem;
+using namespace fs;
+
+int main(int, char**) {
+    scoped_test_env env;
+
+    const path parent_dir = env.create_dir("parent");
+    const path child_dir = env.create_dir(parent_dir / "child");
+    permissions(parent_dir, perms::owner_read | perms::owner_write);
+
+    const auto BadRet = static_cast<std::uintmax_t>(-1);
+    std::error_code ec;
+    assert(fs::remove_all(parent_dir, ec) == BadRet);
+    assert(ec == std::errc::permission_denied);
+
+    permissions(parent_dir, perms::owner_all);
+    return 0;
+}

>From a4182b96d5378b144773ac26f826dad0a501cc07 Mon Sep 17 00:00:00 2001
From: Jake Egan <jake.egan at ibm.com>
Date: Fri, 15 May 2026 11:03:25 -0400
Subject: [PATCH 3/6] Fix formatting

---
 .../bad_perms_parent.pass.cpp                 | 20 +++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/libcxx/test/libcxx/input.output/filesystems/fs.op.funcs/fs.op.remove_all/bad_perms_parent.pass.cpp b/libcxx/test/libcxx/input.output/filesystems/fs.op.funcs/fs.op.remove_all/bad_perms_parent.pass.cpp
index 1c129e9c08c39..f1bd148a94e75 100644
--- a/libcxx/test/libcxx/input.output/filesystems/fs.op.funcs/fs.op.remove_all/bad_perms_parent.pass.cpp
+++ b/libcxx/test/libcxx/input.output/filesystems/fs.op.funcs/fs.op.remove_all/bad_perms_parent.pass.cpp
@@ -22,17 +22,17 @@ namespace fs = std::filesystem;
 using namespace fs;
 
 int main(int, char**) {
-    scoped_test_env env;
+  scoped_test_env env;
 
-    const path parent_dir = env.create_dir("parent");
-    const path child_dir = env.create_dir(parent_dir / "child");
-    permissions(parent_dir, perms::owner_read | perms::owner_write);
+  const path parent_dir = env.create_dir("parent");
+  const path child_dir  = env.create_dir(parent_dir / "child");
+  permissions(parent_dir, perms::owner_read | perms::owner_write);
 
-    const auto BadRet = static_cast<std::uintmax_t>(-1);
-    std::error_code ec;
-    assert(fs::remove_all(parent_dir, ec) == BadRet);
-    assert(ec == std::errc::permission_denied);
+  const auto BadRet = static_cast<std::uintmax_t>(-1);
+  std::error_code ec;
+  assert(fs::remove_all(parent_dir, ec) == BadRet);
+  assert(ec == std::errc::permission_denied);
 
-    permissions(parent_dir, perms::owner_all);
-    return 0;
+  permissions(parent_dir, perms::owner_all);
+  return 0;
 }

>From 2bb7b5a905c12cffbab7738915426ebd00042d35 Mon Sep 17 00:00:00 2001
From: Jake Egan <jake.egan at ibm.com>
Date: Fri, 15 May 2026 13:54:12 -0400
Subject: [PATCH 4/6] Unsupport windows

---
 .../fs.op.funcs/fs.op.remove_all/bad_perms_parent.pass.cpp      | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/libcxx/test/libcxx/input.output/filesystems/fs.op.funcs/fs.op.remove_all/bad_perms_parent.pass.cpp b/libcxx/test/libcxx/input.output/filesystems/fs.op.funcs/fs.op.remove_all/bad_perms_parent.pass.cpp
index f1bd148a94e75..a8f86af127e7b 100644
--- a/libcxx/test/libcxx/input.output/filesystems/fs.op.funcs/fs.op.remove_all/bad_perms_parent.pass.cpp
+++ b/libcxx/test/libcxx/input.output/filesystems/fs.op.funcs/fs.op.remove_all/bad_perms_parent.pass.cpp
@@ -9,6 +9,8 @@
 // UNSUPPORTED: c++03, c++11, c++14
 // UNSUPPORTED: no-filesystem
 
+// UNSUPPORTED: windows
+
 // Verify that remove_all reports the correct error (permission_denied)
 // when the parent directory has insufficient permissions.
 

>From 98aa585a8d4b2dbdec9229c72f813879c77de228 Mon Sep 17 00:00:00 2001
From: Jake Egan <jake.egan at ibm.com>
Date: Mon, 25 May 2026 10:44:57 -0400
Subject: [PATCH 5/6] XFAIL for apple configs using older library versions

---
 .../fs.op.funcs/fs.op.remove_all/bad_perms_parent.pass.cpp       | 1 +
 1 file changed, 1 insertion(+)

diff --git a/libcxx/test/libcxx/input.output/filesystems/fs.op.funcs/fs.op.remove_all/bad_perms_parent.pass.cpp b/libcxx/test/libcxx/input.output/filesystems/fs.op.funcs/fs.op.remove_all/bad_perms_parent.pass.cpp
index a8f86af127e7b..fbdfa15da38a6 100644
--- a/libcxx/test/libcxx/input.output/filesystems/fs.op.funcs/fs.op.remove_all/bad_perms_parent.pass.cpp
+++ b/libcxx/test/libcxx/input.output/filesystems/fs.op.funcs/fs.op.remove_all/bad_perms_parent.pass.cpp
@@ -10,6 +10,7 @@
 // UNSUPPORTED: no-filesystem
 
 // UNSUPPORTED: windows
+// XFAIL: using-built-library-before-llvm-23
 
 // Verify that remove_all reports the correct error (permission_denied)
 // when the parent directory has insufficient permissions.

>From 519c311e74adbea9b756ce7d3bde6c7b3a90e16b Mon Sep 17 00:00:00 2001
From: Jake Egan <jake.egan at ibm.com>
Date: Mon, 25 May 2026 16:16:43 -0400
Subject: [PATCH 6/6] Add 23 feature

---
 libcxx/utils/libcxx/test/features/availability.py | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/libcxx/utils/libcxx/test/features/availability.py b/libcxx/utils/libcxx/test/features/availability.py
index 39c6cf45a1708..c345ed244fe64 100644
--- a/libcxx/utils/libcxx/test/features/availability.py
+++ b/libcxx/utils/libcxx/test/features/availability.py
@@ -128,7 +128,7 @@
 # a libc++ flavor that enables availability markup. Similarly, a test could fail when
 # run against the system library of an older version of FreeBSD, even though FreeBSD
 # doesn't provide availability markup at the time of writing this.
-for version in ("12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22"):
+for version in ("12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23"):
     features.append(
         Feature(
             name="using-built-library-before-llvm-{}".format(version),



More information about the libcxx-commits mailing list