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

[TempFile] Revert to using mkstemp on unix #181

Merged
merged 1 commit into from
Jan 10, 2023

Conversation

roypat
Copy link
Collaborator

@roypat roypat commented Jan 9, 2023

Summary of the PR

The name generation in TempFile is done by appending a randomly generated string of 6 alphanumeric characters to a prefix-path. This PR changes that implementation back ot using mkstemp on unix systems, to prevent name collisions. This additionally brings it inline with the TempDir implementation in the unix::tempdir module.

It seems that on windows something similar is possible via GetTempFileName, but I am too unfamiliar with the win32 api (and also have no windows machine available for testing) to be confident in implementing that change.

Reason

We encountered spurious failures in tests due to multiple parallel running tests generating the same random file name.

Open Questions

  • Does this need a unit test?
  • The (now windows-only) implementation of TempDir::new_with_prefix uses .truncate(true), which silently overwrites existing temporary files in the case of a name collision. Should this be changed?

Requirements

Before submitting your PR, please make sure you addressed the following
requirements:

  • All commits in this PR are signed (with git commit -s), and the commit
    message has max 60 characters for the summary and max 75 characters for each
    description line.
  • All added/changed functionality has a corresponding unit/integration
    test.
  • All added/changed public-facing functionality has entries in the "Upcoming
    Release" section of CHANGELOG.md (if no such section exists, please create one).
  • Any newly added unsafe code is properly documented.

@roypat roypat force-pushed the collision-free-tempfile branch 3 times, most recently from 194191d to 65de6df Compare January 9, 2023 10:49
src/tempfile.rs Show resolved Hide resolved
src/tempfile.rs Outdated
let mut os_fname = prefix.as_ref().to_os_string();
os_fname.push("XXXXXX");

let raw_fname = CString::new(os_fname.into_vec()).unwrap().into_raw();
Copy link
Member

Choose a reason for hiding this comment

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

Why is this unwrap safe? We should add a comment here to say that OsStr on unix is guaranteed to not have any non-zero bytes, and thus converting this to CString is safe, thus we can use unwrap.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Okay I just checked the documentation and this seems to not be true (There is From<String> for OsString which does not allocate, and Strings are allowed to have nuls). Sooo I guess just using the old implementation does not work :(

Diving very deep into rust's stdlib, I came across how they handle this case, which seems to be std::io::ErrorKind::InvalidInput. After looking into more implementation details it seems that this would've previously been mapped to Err(Error(0)), so I'll mimic that behaviour

Copy link
Member

Choose a reason for hiding this comment

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

Hmmm, this is rather unexpected. Nice dive deep!

Did you also check the implementation of From? It allows null bytes? 😱

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yep, it eventually proxies through to this. I was quite surprised too, but I got suspicious after I couldn't find any docs telling me that "no nuls" was an invariant of OsString :(

@roypat
Copy link
Collaborator Author

roypat commented Jan 9, 2023

@andreeaflorescu Do you want to me address your comments by amending the commit that git revert generated, or do you want them in a follow up commit? 😅

@andreeaflorescu
Copy link
Member

@andreeaflorescu Do you want to me address your comments by amending the commit that git revert generated, or do you want them in a follow up commit? 😅

I missed the commits history actually. Why do you want to handle this as a revert? It looks like we want to keep some of the functionality from the initial commit (i.e. the part where it works on Windows), so a revert might not be the best path forward in this case. I am opened to being changed my mind 😆 but for me right now it does not make sense to have this as a revert.

@roypat
Copy link
Collaborator Author

roypat commented Jan 9, 2023

@andreeaflorescu Do you want to me address your comments by amending the commit that git revert generated, or do you want them in a follow up commit? 😅

I missed the commits history actually. Why do you want to handle this as a revert? It looks like we want to keep some of the functionality from the initial commit (i.e. the part where it works on Windows), so a revert might not be the best path forward in this case. I am opened to being changed my mind 😆 but for me right now it does not make sense to have this as a revert.

In my head I treated it as a "revert the unix behavior change introduced by commit xxxxxx", but am happy to just treat it as a normal commit that cfgs the current impl to windows and reintroduces the impl from pre- 4e950be on unix. Since it's not a clean revert anyway, that'd result in a cleaner commit history, too.

@roypat roypat force-pushed the collision-free-tempfile branch 3 times, most recently from 8230e74 to 04b06b7 Compare January 9, 2023 16:34
src/tempfile.rs Outdated Show resolved Hide resolved
@roypat roypat force-pushed the collision-free-tempfile branch 5 times, most recently from 1e62d0e to df11360 Compare January 10, 2023 14:22
This partially reverts commit 2e77de9,
as in that on unix we return to the behavior implemented before that
commit was made. By using mkstemp, we prevent potential filename
collisions from occuring (something firecracker occasionally observed
when running heavily parallelized testing workloads).

Code for the unix implementation is taken from the git history, with
minor adjustments to meet the now-higher linting bar.

On windows, we stick to the implementation of naming tempfiles after 6
random alphanumeric characters.

Signed-off-by: Patrick Roy <[email protected]>
@alxiord alxiord merged commit ad20b5c into rust-vmm:main Jan 10, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants