[libcxx-commits] [libcxx] 1139902 - [libcxx] Correct and clean-up filesystem operations error_code paths (#88341)

via libcxx-commits libcxx-commits at lists.llvm.org
Wed Jun 12 09:12:01 PDT 2024


Author: Rodrigo Salazar
Date: 2024-06-12T12:11:57-04:00
New Revision: 11399028ba2d74de770f46e7044ee0f008b01778

URL: https://github.com/llvm/llvm-project/commit/11399028ba2d74de770f46e7044ee0f008b01778
DIFF: https://github.com/llvm/llvm-project/commit/11399028ba2d74de770f46e7044ee0f008b01778.diff

LOG: [libcxx] Correct and clean-up filesystem operations error_code paths (#88341)

3 error_code related cleanups/corrections in the std::filesystem
operations functions.

1. In `__copy`, the `ec->clear()` is unnecessary as `ErrorHandler` at
the start of each function clears the error_code as part of its
initialization.

2. In `__copy`, in the recursive codepath we are not checking the
error_code result of `it.increment(m_ec2)` immediately after use in the
for loop condition (and we aren't checking it after the final increment
when we don't enter the loop).

3. In `__weakly_canonical`, it makes calls to `__canonical` (which
internally uses OS APIs implementing POSIX `realpath`) and we are not
checking the error code result from the `__canonical` call. Both
`weakly_canonical` and `canonical` are supposed to set the error_code
when underlying OS APIs result in an error
(https://eel.is/c++draft/fs.err.report#3.1). With this change we
propagate up the error_code from `__canonical` caused by any underlying
OS API failure up to the `__weakly_canonical`. Essentially, if
`__canonical` thinks an error code should be set, then
`__weakly_canonical` must as well. Before this change it would be
throwing an exception in the non-error_code form of the function when
`__canonical` fails, while not setting the error code in the error_code
form of the function (an inconsistency).

Added a little coverage in weakly_canonical.pass.cpp for the error_code
forms of the API that was missing. Though I am lacking utilities in
libcxx testing to add granular testing of the failure scenarios (like
forcing realpath to fail for a given path, as it could if you had
something like a flaky remote filesystem).

Added: 
    

Modified: 
    libcxx/src/filesystem/operations.cpp
    libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.weakly_canonical/weakly_canonical.pass.cpp

Removed: 
    


################################################################################
diff  --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
index 87b38fbdecf4e..abd8695978ea7 100644
--- a/libcxx/src/filesystem/operations.cpp
+++ b/libcxx/src/filesystem/operations.cpp
@@ -126,9 +126,6 @@ void __copy(const path& from, const path& to, copy_options options, error_code*
     return err.report(errc::function_not_supported);
   }
 
-  if (ec)
-    ec->clear();
-
   if (is_symlink(f)) {
     if (bool(copy_options::skip_symlinks & options)) {
       // do nothing
@@ -166,15 +163,15 @@ void __copy(const path& from, const path& to, copy_options options, error_code*
       return;
     }
     error_code m_ec2;
-    for (; it != directory_iterator(); it.increment(m_ec2)) {
-      if (m_ec2) {
-        return err.report(m_ec2);
-      }
+    for (; !m_ec2 && it != directory_iterator(); it.increment(m_ec2)) {
       __copy(it->path(), to / it->path().filename(), options | copy_options::__in_recursive_copy, ec);
       if (ec && *ec) {
         return;
       }
     }
+    if (m_ec2) {
+      return err.report(m_ec2);
+    }
   }
 }
 
@@ -936,23 +933,28 @@ path __weakly_canonical(const path& p, error_code* ec) {
   --PP;
   vector<string_view_t> DNEParts;
 
+  error_code m_ec;
   while (PP.State != PathParser::PS_BeforeBegin) {
     tmp.assign(createView(p.native().data(), &PP.RawEntry.back()));
-    error_code m_ec;
     file_status st = __status(tmp, &m_ec);
     if (!status_known(st)) {
       return err.report(m_ec);
     } else if (exists(st)) {
-      result = __canonical(tmp, ec);
+      result = __canonical(tmp, &m_ec);
+      if (m_ec) {
+        return err.report(m_ec);
+      }
       break;
     }
     DNEParts.push_back(*PP);
     --PP;
   }
-  if (PP.State == PathParser::PS_BeforeBegin)
-    result = __canonical("", ec);
-  if (ec)
-    ec->clear();
+  if (PP.State == PathParser::PS_BeforeBegin) {
+    result = __canonical("", &m_ec);
+    if (m_ec) {
+      return err.report(m_ec);
+    }
+  }
   if (DNEParts.empty())
     return result;
   for (auto It = DNEParts.rbegin(); It != DNEParts.rend(); ++It)

diff  --git a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.weakly_canonical/weakly_canonical.pass.cpp b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.weakly_canonical/weakly_canonical.pass.cpp
index 053bddcad9b43..59bb3c78667b4 100644
--- a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.weakly_canonical/weakly_canonical.pass.cpp
+++ b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.weakly_canonical/weakly_canonical.pass.cpp
@@ -74,11 +74,23 @@ int main(int, char**) {
     fs::path p      = TC.input;
     fs::path expect = TC.expect;
     expect.make_preferred();
-    const fs::path output = fs::weakly_canonical(p);
 
-    TEST_REQUIRE(PathEq(output, expect),
-                 TEST_WRITE_CONCATENATED(
-                     "Input: ", TC.input.string(), "\nExpected: ", expect.string(), "\nOutput: ", output.string()));
+    {
+      const fs::path output = fs::weakly_canonical(p);
+      TEST_REQUIRE(PathEq(output, expect),
+                   TEST_WRITE_CONCATENATED(
+                       "Input: ", TC.input.string(), "\nExpected: ", expect.string(), "\nOutput: ", output.string()));
+    }
+
+    // Test the error_code variant
+    {
+      std::error_code ec;
+      const fs::path output_c = fs::weakly_canonical(p, ec);
+
+      TEST_REQUIRE(PathEq(output_c, expect),
+                   TEST_WRITE_CONCATENATED(
+                       "Input: ", TC.input.string(), "\nExpected: ", expect.string(), "\nOutput: ", output_c.string()));
+    }
   }
   return 0;
 }


        


More information about the libcxx-commits mailing list