-
Notifications
You must be signed in to change notification settings - Fork 13.6k
[libc++] Make std::filesystem::canonical throw when given empty path #77223
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
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.
Thank you for submitting a Pull Request (PR) to the LLVM Project! This PR will be automatically labeled and the relevant teams will be If you wish to, you can add reviewers by using the "Reviewers" section on this page. If this is not working for you, it is probably because you do not have write If you have received no comments on your PR for a week, you can request a review If you have further questions, they may be answered by the LLVM GitHub User Guide. You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums. |
@llvm/pr-subscribers-libcxx Author: Leo (Yuki-cpp) ChangesFixes #77170 As noted in the issue, Note: Running clang-format on the canonical.pass.cpp file produced formatting different than the rest of the file. As such, to conform with the Coding Standard I haven't formatted that file automatically but rather kept the style of the file intact. Let me know if I missed something there and I'll gladly fix it. Note 2: Might as well mention now that I do not have commit access Full diff: https://github.com/llvm/llvm-project/pull/77223.diff 2 Files Affected:
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;
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
You should format the code snippet you added. Please check the code formatter checker. It is normal that old code is using old formatting and the new one the new style in the same file. |
Will remember that for next time. Thanks |
Thanks for your contribution!
Can you remove the notes below from the commit message, to avoid accidentally merging them in the commit?
we recently have formatted our code except for the tests. That will done in the future. For now keeping the existing code is fine.
No problem. Can you make sure your e-mail address is not hidden. |
libcxx/src/filesystem/operations.cpp
Outdated
if (orig_p.empty()) | ||
return err.report(capture_errno()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I dislike this solution, does not fix the real issue, this part should be fixed in __do_absolute
. See https://godbolt.org/z/GrvW1KonT
Can you fix absolute
and weakly_canonical
too?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a heads up.
By moving that test (a slightly modified version) to __do_absolute
as you suggest, I can get absolute
, canonical
and weakly_canonical
to work as expected. However it appears that both proximate
and relative
are dependent on weakly_canonical
and are both in their tests depending on the ""
becomes current_dir
behavior.
Modifying your example, I can highlight some more discrepancies : https://godbolt.org/z/14h8Pv7vc
I believe I can iron those out, but it will take me a bit more time and extend the scope of this PR. Is that acceptable?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since they are all related to the same root cause I don't mind to have these changes in one PR.
Take the time you need.
libcxx/test/std/input.output/filesystems/fs.op.funcs/fs.op.canonical/canonical.pass.cpp
Outdated
Show resolved
Hide resolved
Thank you for the review. I'll get to it. One question though:
Are you referring to this part?
Or to are referring to the note I added to the PR description? (Those 2 shouldn't be in the commit message, but I can also remove them from the PR if you think it's best) |
I'm referring to the two notes below this comment. The one for |
…hen given empty path
For the buildkite CI issues you can ignore Apple for now, but please have a look at Windows. |
Yeah. I am on it. In the current implementation I have simply "fixed" the test (I'll handle the windows one ASAP) but the constant reliance on those folders make me feel like I missed something somewhere. Is there actually something somewhere that I missed or was previously forgotten that defines those files and folders structure? |
…throw when given empty path
@mordante Windows build should be good now. |
Thanks! I'll try to have a look tomorrow. |
Thanks I think this looks good, I want to test the patch locally to compare a bit more with GCC. I need to do some unrelated changes so we can properly mark the status for the Apple builds. |
Thanks. I'll be on stand-by if you require any changes here then. |
I'm quite busy and this patch depends on a work-in-progess patch to fix the apple-build. So it will take a bit longer to get to this patch. |
I finally landed the patch that makes it easier to disable the Apple tests. Can you rebase this patch and add the following to the patches that fail on the Apple CI?
|
Sure. |
Great. No hurry. I just wanted to inform you I landed the patch that unblocks this patch. (That took longer than I expected.) |
@mordante Just a bit of an update. Sorry for the annoyance. |
Thanks for the update! Not problem at all. |
@Yuki-cpp Do you plan to continue working on this? |
Fixes #77170
As noted in the issue,
std::filesystem::canonical
returns the current path when given""
while an error is expected. Further investigations shown that the issue lies withinstd::filesystem::absolute
which is then re-used by canonical.To fix that, this PR adds a check for empty paths in
std::filesystem::absolute
and raise an error accordingly. This in turn fixesstd::filesystem::canonical
Since
std::filesystem::weakly_canonical
and usesstd::filesystem::canonical
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.Finally tests for
std::filesystem::weakly_canonical
andstd::filesystem::proximate
were updated as they were built on the faulty behavior.