[libcxx-commits] [libcxx] [libc++] Make std::filesystem::canonical throw when given empty path (PR #77223)
via libcxx-commits
libcxx-commits at lists.llvm.org
Wed Jan 10 04:21:02 PST 2024
https://github.com/Yuki-cpp updated https://github.com/llvm/llvm-project/pull/77223
>From 19f5fb22944f79c672e192c75b90b3d94ad542c8 Mon Sep 17 00:00:00 2001
From: Leo <leo.ghafari at gmail.com>
Date: Sun, 7 Jan 2024 10:46:46 +0900
Subject: [PATCH 1/3] [libc++] Make std::filesystem::canonical throw when given
empty path
Adds a check for empty paths in std::filesystem::canonical and raise an
error accordingly. Since std::filesystem::weakly_canonical uses this function
and should not raise an error when given an empty path, it was updated
to return an empty path instead of the results of canonical.
---
libcxx/src/filesystem/operations.cpp | 6 +++--
.../fs.op.canonical/canonical.pass.cpp | 26 +++++++++++++++++++
2 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
index 6bee340e0d15c8..8f5b70a071373d 100644
--- a/libcxx/src/filesystem/operations.cpp
+++ b/libcxx/src/filesystem/operations.cpp
@@ -82,6 +82,8 @@ path __canonical(path const& orig_p, error_code* ec) {
path cwd;
ErrorHandler<path> err("canonical", ec, &orig_p, &cwd);
+ if (orig_p.empty())
+ return err.report(capture_errno());
path p = __do_absolute(orig_p, &cwd, ec);
#if (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || defined(_LIBCPP_WIN32API)
std::unique_ptr<path::value_type, decltype(&::free)> hold(detail::realpath(p.c_str(), nullptr), &::free);
@@ -912,7 +914,7 @@ path __weakly_canonical(const path& p, error_code* ec) {
ErrorHandler<path> err("weakly_canonical", ec, &p);
if (p.empty())
- return __canonical("", ec);
+ return __current_path(ec);
path result;
path tmp;
@@ -935,7 +937,7 @@ path __weakly_canonical(const path& p, error_code* ec) {
--PP;
}
if (PP.State == PathParser::PS_BeforeBegin)
- result = __canonical("", ec);
+ result = __current_path(ec);
if (ec)
ec->clear();
if (DNEParts.empty())
diff --git a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.canonical/canonical.pass.cpp b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.canonical/canonical.pass.cpp
index 0098fe8ee698ef..000fb47096ba19 100644
--- a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.canonical/canonical.pass.cpp
+++ b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.canonical/canonical.pass.cpp
@@ -92,6 +92,31 @@ static void test_dne_path()
}
}
+static void test_empty_path()
+{
+ std::error_code ec = GetTestEC();
+ {
+ const path ret = canonical(path{}, ec);
+ assert(ec != GetTestEC());
+ assert(ec);
+ assert(ret == path{});
+ }
+ {
+ TEST_THROWS_TYPE(filesystem_error, canonical(path{}));
+ }
+
+ ec = GetTestEC();
+ {
+ const path ret = canonical("", ec);
+ assert(ec != GetTestEC());
+ assert(ec);
+ assert(ret == path{});
+ }
+ {
+ TEST_THROWS_TYPE(filesystem_error, canonical(""));
+ }
+}
+
static void test_exception_contains_paths()
{
#ifndef TEST_HAS_NO_EXCEPTIONS
@@ -121,6 +146,7 @@ int main(int, char**) {
signature_test();
test_canonical();
test_dne_path();
+ test_empty_path();
test_exception_contains_paths();
return 0;
>From 614ec4b47f0c986092a95fc64e9f9f1b59de3f84 Mon Sep 17 00:00:00 2001
From: Leo <leo.ghafari at gmail.com>
Date: Sun, 7 Jan 2024 17:25:26 +0900
Subject: [PATCH 2/3] fixup! [libc++] Make std::filesystem::canonical throw
when given empty path
---
.../fs.op.canonical/canonical.pass.cpp | 39 ++++++++-----------
1 file changed, 17 insertions(+), 22 deletions(-)
diff --git a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.canonical/canonical.pass.cpp b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.canonical/canonical.pass.cpp
index 000fb47096ba19..c5935f20510844 100644
--- a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.canonical/canonical.pass.cpp
+++ b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.canonical/canonical.pass.cpp
@@ -92,29 +92,24 @@ static void test_dne_path()
}
}
-static void test_empty_path()
-{
- std::error_code ec = GetTestEC();
- {
- const path ret = canonical(path{}, ec);
- assert(ec != GetTestEC());
- assert(ec);
- assert(ret == path{});
- }
- {
- TEST_THROWS_TYPE(filesystem_error, canonical(path{}));
- }
+static void test_empty_path() {
+ std::error_code ec = GetTestEC();
+ {
+ const path ret = canonical(path{}, ec);
+ assert(ec != GetTestEC());
+ assert(ec);
+ assert(ret == path{});
+ }
+ { TEST_THROWS_TYPE(filesystem_error, canonical(path{})); }
- ec = GetTestEC();
- {
- const path ret = canonical("", ec);
- assert(ec != GetTestEC());
- assert(ec);
- assert(ret == path{});
- }
- {
- TEST_THROWS_TYPE(filesystem_error, canonical(""));
- }
+ ec = GetTestEC();
+ {
+ const path ret = canonical("", ec);
+ assert(ec != GetTestEC());
+ assert(ec);
+ assert(ret == path{});
+ }
+ { TEST_THROWS_TYPE(filesystem_error, canonical("")); }
}
static void test_exception_contains_paths()
>From fbc66968ccdafb828aa1f3bd6522c9fb75e2aff5 Mon Sep 17 00:00:00 2001
From: Leo <leo.ghafari at gmail.com>
Date: Wed, 10 Jan 2024 21:17:52 +0900
Subject: [PATCH 3/3] fixup! fixup! [libc++] Make std::filesystem::canonical
throw when given empty path
---
libcxx/src/filesystem/operations.cpp | 10 +++++----
.../fs.op.absolute/absolute.pass.cpp | 20 ++++++++++++-----
.../fs.op.canonical/canonical.pass.cpp | 9 --------
.../fs.op.proximate/proximate.pass.cpp | 22 +++++++++----------
.../fs.op.relative/relative.pass.cpp | 2 +-
.../weakly_canonical.pass.cpp | 8 +++----
6 files changed, 36 insertions(+), 35 deletions(-)
diff --git a/libcxx/src/filesystem/operations.cpp b/libcxx/src/filesystem/operations.cpp
index 8f5b70a071373d..51b8f14619fb2a 100644
--- a/libcxx/src/filesystem/operations.cpp
+++ b/libcxx/src/filesystem/operations.cpp
@@ -63,6 +63,10 @@ using parser::PathParser;
using parser::string_view_t;
static path __do_absolute(const path& p, path* cwd, error_code* ec) {
+ ErrorHandler<path> err("absolute", ec, &p);
+
+ if (p.empty())
+ return err.report(errc::invalid_argument);
if (ec)
ec->clear();
if (p.is_absolute())
@@ -82,8 +86,6 @@ path __canonical(path const& orig_p, error_code* ec) {
path cwd;
ErrorHandler<path> err("canonical", ec, &orig_p, &cwd);
- if (orig_p.empty())
- return err.report(capture_errno());
path p = __do_absolute(orig_p, &cwd, ec);
#if (defined(_POSIX_VERSION) && _POSIX_VERSION >= 200112) || defined(_LIBCPP_WIN32API)
std::unique_ptr<path::value_type, decltype(&::free)> hold(detail::realpath(p.c_str(), nullptr), &::free);
@@ -914,7 +916,7 @@ path __weakly_canonical(const path& p, error_code* ec) {
ErrorHandler<path> err("weakly_canonical", ec, &p);
if (p.empty())
- return __current_path(ec);
+ return p;
path result;
path tmp;
@@ -937,7 +939,7 @@ path __weakly_canonical(const path& p, error_code* ec) {
--PP;
}
if (PP.State == PathParser::PS_BeforeBegin)
- result = __current_path(ec);
+ result = path{};
if (ec)
ec->clear();
if (DNEParts.empty())
diff --git a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.absolute/absolute.pass.cpp b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.absolute/absolute.pass.cpp
index 7a60d1ab29f4ad..9c88613abc6a94 100644
--- a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.absolute/absolute.pass.cpp
+++ b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.absolute/absolute.pass.cpp
@@ -39,12 +39,8 @@ static void basic_test()
const struct {
std::string input;
fs::path expect;
- } TestCases [] = {
- {"", cwd / ""},
- {"foo", cwd / "foo"},
- {"foo/", cwd / "foo/"},
- {"/already_absolute", cwd.root_name() / "/already_absolute"}
- };
+ } TestCases[] = {
+ {"foo", cwd / "foo"}, {"foo/", cwd / "foo/"}, {"/already_absolute", cwd.root_name() / "/already_absolute"}};
for (auto& TC : TestCases) {
std::error_code ec = GetTestEC();
const path ret = absolute(TC.input, ec);
@@ -55,8 +51,20 @@ static void basic_test()
}
}
+static void test_empty_path() {
+ std::error_code ec = GetTestEC();
+ {
+ const path ret = absolute(path{}, ec);
+ assert(ec != GetTestEC());
+ assert(ec);
+ assert(ret == path{});
+ }
+ { TEST_THROWS_TYPE(filesystem_error, absolute(path{})); }
+}
+
int main(int, char**) {
absolute_signature_test();
+ test_empty_path();
basic_test();
return 0;
diff --git a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.canonical/canonical.pass.cpp b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.canonical/canonical.pass.cpp
index c5935f20510844..e5c968b8a5ebc2 100644
--- a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.canonical/canonical.pass.cpp
+++ b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.canonical/canonical.pass.cpp
@@ -101,15 +101,6 @@ static void test_empty_path() {
assert(ret == path{});
}
{ TEST_THROWS_TYPE(filesystem_error, canonical(path{})); }
-
- ec = GetTestEC();
- {
- const path ret = canonical("", ec);
- assert(ec != GetTestEC());
- assert(ec);
- assert(ret == path{});
- }
- { TEST_THROWS_TYPE(filesystem_error, canonical("")); }
}
static void test_exception_contains_paths()
diff --git a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.proximate/proximate.pass.cpp b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.proximate/proximate.pass.cpp
index d2e9c1e6e8bf0d..cb97ee4a0ae8ac 100644
--- a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.proximate/proximate.pass.cpp
+++ b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.proximate/proximate.pass.cpp
@@ -66,16 +66,16 @@ static void basic_test() {
fs::path expect;
} TestCases[] = {
{"", "", "."},
- {cwd, "a", ".."},
- {parent_cwd, "a", "../.."},
+ {cwd, "a", cwd},
+ {parent_cwd, "a", parent_cwd},
{"a", cwd, "a"},
- {"a", parent_cwd, curdir / "a"},
- {"/", "a", dot_dot_to_root / ".."},
- {"/", "a/b", dot_dot_to_root / "../.."},
- {"/", "a/b/", dot_dot_to_root / "../.."},
- {"a", "/", relative_cwd / "a"},
- {"a/b", "/", relative_cwd / "a/b"},
- {"a", "/net", ".." / relative_cwd / "a"},
+ {"a", parent_cwd, "a"},
+ {"/", "a", "/"},
+ {"/", "a/b", "/"},
+ {"/", "a/b/", "/"},
+ {"a", "/", "a"},
+ {"a/b", "/", "a/b"},
+ {"a", "/net", "a"},
#ifdef _WIN32
{"//foo/", "//foo", "//foo/"},
{"//foo", "//foo/", "//foo"},
@@ -104,10 +104,10 @@ static void basic_test() {
{"X:a", "Y:/b", "X:a"},
{"X:a", "Y:b", "X:a"},
#else
- {"//foo", "a", dot_dot_to_root / "../foo"},
+ {"//foo", "a", "/foo"},
{"//foo/a", "//bar", "../foo/a"},
{"//foo/a", "//bar/", "../foo/a"},
- {"//foo/a", "b", dot_dot_to_root / "../foo/a"},
+ {"//foo/a", "b", "/foo/a"},
{"//foo/a", "/b", "../foo/a"},
{"//foo/a", "//bar/b", "../../foo/a"},
{"X:/a", "X:/b", "../a"},
diff --git a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.relative/relative.pass.cpp b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.relative/relative.pass.cpp
index 9bd4051f790218..92209425d64288 100644
--- a/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.relative/relative.pass.cpp
+++ b/libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.relative/relative.pass.cpp
@@ -30,7 +30,7 @@ namespace fs = std::filesystem;
static void test_signature_0() {
fs::path p("");
const fs::path output = fs::weakly_canonical(p);
- assert(output == fs::path::string_type(fs::current_path()));
+ assert(output == fs::path::string_type(""));
}
static void test_signature_1() {
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 035e875e4ec83d..b981b25af455a8 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
@@ -36,15 +36,15 @@ int main(int, char**) {
fs::path input;
fs::path expect;
} TestCases[] = {
- {"", fs::current_path()},
+ {"", ""},
{".", fs::current_path()},
{"/", root},
{"/foo", root / "foo"},
{"/.", root},
{"/./", root},
- {"a/b", fs::current_path() / "a/b"},
- {"a", fs::current_path() / "a"},
- {"a/b/", fs::current_path() / "a/b/"},
+ {"a/b", "a/b"},
+ {"a", "a"},
+ {"a/b/", "a/b/"},
{static_env.File, static_env.File},
{static_env.Dir, static_env.Dir},
{static_env.SymlinkToDir, static_env.Dir},
More information about the libcxx-commits
mailing list