Skip to content
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

Fix #9584 - Using dirEntries and chdir() can have unwanted results. #6125

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open

Fix #9584 - Using dirEntries and chdir() can have unwanted results. #6125

wants to merge 6 commits into from

Conversation

GallaFrancesco
Copy link

@GallaFrancesco GallaFrancesco commented Feb 4, 2018

After following issue 6138 on the bug tracker [edit: #9584 on GitHub], I am proposing this fix for the std.file module.

All it does is calling absolutePath from std.path before passing the argument to dirEntries.
The overload of dirEntries which also accepts string patterns doesn't seem to be affected by this, therefore no changes were proposed.

@dlang-bot
Copy link
Contributor

dlang-bot commented Feb 4, 2018

Thanks for your pull request and interest in making D better, @GallaFrancesco! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please verify that your PR follows this checklist:

  • My PR is fully covered with tests (you can see the coverage diff by visiting the details link of the codecov check)
  • My PR is as minimal as possible (smaller, focused PRs are easier to review than big ones)
  • I have provided a detailed rationale explaining my changes
  • New or modified functions have Ddoc comments (with Params: and Returns:)

Please see CONTRIBUTING.md for more information.


If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment.

Bugzilla references

Your PR doesn't reference any Bugzilla issue.

If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.

⚠️⚠️⚠️ Warnings ⚠️⚠️⚠️

  • In preparation for migrating from Bugzilla to GitHub Issues, the issue reference syntax has changed. Please add the word "Bugzilla" to issue references. For example, Fix Bugzilla Issue 12345 or Fix Bugzilla 12345.(Reminder: the edit needs to be done in the Git commit message, not the GitHub pull request.)

Testing this PR locally

If you don't have a local development environment setup, you can use Digger to test this PR:

dub run digger -- build "master + phobos#6125"

Copy link
Member

@wilzbach wilzbach left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for submitting your first PR to Phobos!
Short initial feedback:

  1. no tabs
  2. mind @CyberShadow's comment about potential breakage
  3. Please add a test case

std/file.d Outdated
@@ -4038,7 +4038,8 @@ foreach (d; dFiles)
+/
auto dirEntries(string path, SpanMode mode, bool followSymlink = true)
{
return DirIterator(path, mode, followSymlink);
import std.path: absolutePath;
return DirIterator(absolutePath(path), mode, followSymlink);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No tabs please (see https://dlang.org/dstyle.html)

std/file.d Outdated
@@ -4057,7 +4058,7 @@ auto dirEntries(string path, SpanMode mode, bool followSymlink = true)
.array;
}

void main(string[] args)
void main(string[] args)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tab.

@GallaFrancesco
Copy link
Author

I've updated the source code removing tabs.

Copy link
Member

@CyberShadow CyberShadow left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, but as I wrote in Bugzilla, I believe that this is the wrong approach.

If you don't want to implement the more correct solution (fdopendir + openat), then I suggest that you work around this in your code.

@@ -4109,7 +4110,7 @@ auto dirEntries(string path, SpanMode mode, bool followSymlink = true)
foreach (string name; dirEntries(testdir, SpanMode.breadth))
{
//writeln(name);
assert(name.startsWith(testdir));
assert(name.startsWith(absolutePath(testdir)));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not break existing tests!

Changing existing unit tests to conform to changes in the implementation is almost always a mistake.

@CyberShadow
Copy link
Member

@GallaFrancesco Have a look at the project tester (Jenkins) - this change actually breaks existing D code out there.

@GallaFrancesco
Copy link
Author

@CyberShadow thank you for your reply.

I will look into the approach you suggested (fdopendir + openat). I wonder how this could apply to non-POSIX environments though, given that I am mainly familiar with POSIX ones. Any suggestions? Could this be solved on POSIX systems only?

@CyberShadow
Copy link
Member

Windows is the only non-POSIX system we care about.

It doesn't look like Windows has native equivalents for fdopendir or openat. Here is the approach that Gnulib uses:

  • When beginning iteration (i.e. when dirEntries is called), save the current working directory.
  • Restore the working directory before every FindFileFirst call, but only for the duration of the FindFileFirst call.

However, I can't recommend the above because on Windows, the current directory is a process-wide value, so it could interfere with other threads (which are presumably aware that the user changed the current directory after calling dirEntries).

Another approach would be similar to your current implementation here, but would additionally remove the absolute path prefix in returned DirEntries, so as to not break existing code.

I think we should do the fdopendir thing on POSIX anyway, since it's more pragmatic and likely to improve performance, I'm not sure if doing the above is worthwhile on Windows... because, returning any sort of relative paths when the current directory changes is just not useful. If the path is relative to the initial working directory, then it will point to a non-existing file (or an existing file but not the one you want). If the path is relative to the current working directory, then recording it anywhere is likely to be meaningless.

Your example on Bugzilla also doesn't make sense - you're calling absolutePath twice in a row with a chdir in between, but that is not going to work right (because absolutePath uses the current directory as the base) unless the path in question was already absolute, in which case the absolutePath call is also meaningless.

So... maybe improve the POSIX implementation, because that won't hurt and could bring other benefits, but as for fixing the Bugzilla issue as it was stated... that strikes me more of a kind of "shooting yourself in the foot" situation. If you expect to change directories during directory iteration, just pass an absolute path to dirEntries.

I should add that as far as I can see, most D programs have no business at all in setting the current directory. For process creation, std.process functions can take a workDir parameter that sets directories' initial working directories. For most other things, just use std.path.buildPath & co. If your program has a "home directory" where it keeps all its work/resource files, you might be tempted to change into it when it starts, but you will later find out that this is not such a great idea when you attempt to process relative paths passed by users on your program's command line.

@GallaFrancesco
Copy link
Author

I agree with you, the situations in which one needs to chdir inside a program are very few and errors such as this one or the one recently reported in the bug tracker can be solved by passing absolutePath to dirEntries.

Nevertheless, it seems to me that this behavior is poorly documented, which is the main reason I opened this PR in the first place.

The POSIX solution looks feasible though, the only issue I encountered is the absence of the fdopendir and openat declarations from DRuntime, where fdopendir is supposed to be in module dirent and openat in module fcntl.

Would this require a PR to DRuntime? I'm not sure it is worth the minimal benefits brought by these changes.

@CyberShadow
Copy link
Member

Would this require a PR to DRuntime?

Improving our coverage of OS APIs is a worthwhile goal in itself.

@LightBender
Copy link
Contributor

@thewilsonator wants to take a look at this one.

@LightBender LightBender added the Review:Salvage This PR needs work, but we want to keep it and it can be salvaged. label Oct 27, 2024
@0xEAB 0xEAB changed the title Fix Issue 6138 - Using dirEntries and chdir() can have unwanted results. Fix #9584 - Using dirEntries and chdir() can have unwanted results. Dec 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Merge:stalled Review:Needs Work Review:Salvage This PR needs work, but we want to keep it and it can be salvaged. Severity:Bug Fix
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants