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

Race condition in std::fs::create_dir_all. #33707

Closed
dpc opened this issue May 18, 2016 · 5 comments
Closed

Race condition in std::fs::create_dir_all. #33707

dpc opened this issue May 18, 2016 · 5 comments
Labels
T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.

Comments

@dpc
Copy link
Contributor

dpc commented May 18, 2016

I just got bitten by this, took me a long time to find it and I see the issue was raised before in #30152

It's very non-obvious that std::fs::create_dir_all - which whole purpose of is to make sure the dir exists, can fail due to the fact that the dir was created concurrently.

The PR to fix it #30152 was rejected due to "Concurrent operations can't always be detected and when they do happen on the filesystem it often indicates that something else is going awry and needs to be kicked up further."

But please note that std::fs::create_dir_all is a convenience function, and not one directly mapping to a posix fs operation. If stdlib provides a convenience function, I think it should provide the sanest, and most robust one - not one with a big gotcha inside. The fact that there's a race condition between multiple calls to std::fs::create_dir_all is entirely a implementation choice and just a wrong behavior.

IMO any sane implementation should consider not takign care of this race condition a bug:

I've checked some other standard libraries and all are doing the right thing:

    BOOST_FS_FUNC(bool) create_directories(const Path& ph)
    {
         if (ph.empty() || exists(ph))
         {
           if ( !ph.empty() && !is_directory(ph) )
               boost::throw_exception( basic_filesystem_error<Path>(
                 "boost::filesystem::create_directories", ph,
                 make_error_code( boost::system::posix::file_exists ) ) );
           return false;
         }

         // First create branch, by calling ourself recursively
         create_directories(ph.parent_path());
         // Now that parent's path exists, create the directory
         create_directory(ph);
         return true;
     }

Note that return value of create_directories(ph.parent_path()); is ignored, not returned upwards, like in Rust implementation. And exception is thrown only if ph exists but is not a directory.

Think how many other Rust projects might have undetected race condition as they assumed the create_dir_all will do the right thing. Short googling already pointed other project that got bitten: https://github.com/droundy/bigbro/blob/464bfae81de4ad695a158315e3c75d6d21e382a2/src/lib.rs#L43

@alexcrichton alexcrichton added I-nominated T-libs-api Relevant to the library API team, which will review and decide on the PR/issue. labels May 19, 2016
@alexcrichton
Copy link
Member

The libs team discussed this during triage yesterday and the conclusion was that this does indeed seem ok to implement. Given the new information about other implementations along with a shift in intention for the "nice APIs" we provide like this and remove_dir_all, it also seems appropriate.

@dpc do you wanna send a PR?

@alexcrichton
Copy link
Member

Ah it was also brought up that we probably want to alter the documentation as well to indicate what version of Rust includes the new behavior.

@dpc
Copy link
Contributor Author

dpc commented May 24, 2016

I don't really have a Rust development setup nor the experience with it, so I'll not be able to provide a PR. But isn't #30152 still applicable?

@alexcrichton
Copy link
Member

Yeah it should still work, we'd probably just want to add some more tests as well

@rocallahan
Copy link

Can't this be closed now that #39799 is merged?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
T-libs-api Relevant to the library API team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

5 participants