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

Implement I/O Safety #1750

Open
28 of 29 tasks
asomers opened this issue Jun 23, 2022 · 19 comments
Open
28 of 29 tasks

Implement I/O Safety #1750

asomers opened this issue Jun 23, 2022 · 19 comments
Milestone

Comments

@asomers
Copy link
Member

asomers commented Jun 23, 2022

Most Nix functions that involve files use RawFd arguments, but those are difficult to use correctly. For example, it's easy to use-after-close. Rust nightly just added I/O Safety traits that fix most of the problems with RawFd. It's a very good fit for Nix. We should begin using them as soon as possible. They're on track to be released as part of Rust 1.63.0, which will probably be released on 11-August.
https://github.com/rust-lang/rfcs/blob/master/text/3128-io-safety.md

@polarathene
Copy link

  • A tracking issue over at io-lifetimes (crate referenced by the linked RFC) may be of interest.
  • rustix, a crate similar to nix also implements the new I/O safety traits (via using io-lifetimes) if that's helpful to reference.

I lack the knowledge of how you'd approach this, but the main takeaway from the io-lifetimes tracking issue seems to describe two approaches (with or without the io-lifetimes dependency):

They may require a Minimum Supported Rust Version bump too, though another option is to use io-lifetimes once the change to have it re-export std's types and traits by default lands.

Once bumping MSRV becomes acceptable for the project, you can drop io-lifetimes?

@notgull
Copy link
Contributor

notgull commented Aug 11, 2022

Given that Rust 1.63.0 just dropped and I/O safety is now in the standard library, it might be worth it to bump the MSRV.

If the bump is desired, I can implement the change, moving the input file descriptors to BorrowedFd and the output file descriptors to OwnedFd.

@coolreader18
Copy link
Contributor

I've got a wip branch changing around half so far of the uses of RawFd to the io-safe versions.

@SUPERCILEX
Copy link
Contributor

@coolreader18 Mind trying to merge what you've got? I don't see the need to convert everything at once... any progress in this direction is a net improvement IMO.

@SUPERCILEX
Copy link
Contributor

@asomers I'd be willing to take a crack at this over the weekend assuming there's review bandwidth.

@SUPERCILEX
Copy link
Contributor

I've been thinking about this some more... what's our backwards compat story? Do we add an io_safety feature that has the new wrappers and deprecate all the old ones? Or do we just pull the plug and make everyone use the new types?

cc @rtzoeller

@asomers
Copy link
Member Author

asomers commented Nov 19, 2022

Since we're pre-1.0, we don't technically have to maintain backwards-compat. And in the past, we sometimes haven't. If you were only going to modify one or two functions, I'd say add new methods and deprecate the old ones. But this change is way too big. Better to pull the plug all at once, I'd say.

@notgull
Copy link
Contributor

notgull commented Nov 19, 2022

As it's partially a safety concern, I think a break would be justified, as significant as it would be.

@SUPERCILEX
Copy link
Contributor

Sounds good! Based on discussion over at rustix, I'll need to update my PR to not take fds in by reference. #1862 needs to go through first anyway, so I'll update stuff after that.

Another possibility that's crossed my mind: we could have an extension trait on fds so that you can say fd.read(...). I don't think this is a good idea because it'll be confusing with functions that take in multiple fds, but I wanted to throw it out there.

@asomers
Copy link
Member Author

asomers commented Nov 19, 2022

The extension trait sounds confusing to me, just because it's such a big break from Nix's existing API.

@asomers
Copy link
Member Author

asomers commented Nov 20, 2022

#1874 adds I/O safety to signalfd

@asomers asomers added this to the 0.27.0 milestone Nov 20, 2022
@SUPERCILEX
Copy link
Contributor

@asomers #1863 covers most of unistd, fcntl, and sys/stat but not all since I didn't have the energy to convert weirder syscalls. The easiest way to see what's left will be to search for "RawFd".

bors bot added a commit that referenced this issue Dec 4, 2022
1862: Bump MSRV to 1.63 for I/O safety r=asomers a=SUPERCILEX

Prep for #1750

Co-authored-by: Alex Saveau <saveau.alexandre@gmail.com>
@SteveLauC
Copy link
Member

SteveLauC commented Dec 7, 2022

It might be worth annotating what are covered in #1863 to avoid duplicate work:

  • dir

  • fcntl (Partial)

    The following items are not covered in this module

    1. pub fn fcntl(fd: RawFd, arg: FcntlArg)
    2. enum FcntlArg<'a>
    3. enum FcntlArg
    4. fn flock(fd: RawFd, arg: FlockArg)
  • sys/stat

  • sys/timerfd

  • unistd (Partial)

    The following items are done

    1. pub fn tcgetpgrp(fd: c_int) -> Result<Pid>
    2. pub fn tcsetpgrp(fd: c_int, pgrp: Pid) -> Result<()>
    3. pub fn fpathconf(fd: RawFd, var: PathconfVar) -> Result<Option<c_long>>
    4. pub fn ttyname(fd: RawFd) -> Result<PathBuf>
    5. pub fn getpeereid(fd: RawFd) -> Result<(Uid, Gid)>

    in unistd: make getpeereid take AsFd rather than a raw FD #2137


BTW, they are modules dir and fcntl rather than sys/dir and sys/fcntl

@SUPERCILEX
Copy link
Contributor

@asomers @SteveLauC for APIs like pty, I think we should replace AsRawFd impls with AsFd, precisely to make the close style bugs harder. You'd still be able to get a raw fd with .as_fd().as_raw_fd(), but most APIs will work with AsFd so you shouldn't ever have to call a method to be able to use the type's fd.

@SUPERCILEX
Copy link
Contributor

Also worth noting that the convention I'm going with is to take fds by value (foo<Fd: AsFd>(fd: Fd)) as per this discussion: bytecodealliance/rustix#446

@SteveLauC
Copy link
Member

For the first reason why we should take AsFd by value given by the author of rustix:

This makes it work more like AsRef, which is typically passed by value rather than by reference.

In Nix, we are doing something like:

fn path_related_fn<P: NixPath>(path: &P)

@asomers
Copy link
Member Author

asomers commented Dec 8, 2022

I vote for pass-by-value, unless somebody can come up with a single case where it wouldn't work. After all, the standard library already provides impl<T: AsFd> AsFd for &T

@SteveLauC
Copy link
Member

I just updated this tracking issue, looking at those unfinished modules, most of them are in PR #1863, friendly ping @SUPERCILEX, would you like to split the parts that won't involve the design issue (non-xxat functions) to other PRs

@SUPERCILEX
Copy link
Contributor

@SteveLauC I won't have time to work on this, so I would recommend taking my first commit from that PR (30b32c4) and resolving the conflicts.

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

No branches or pull requests

6 participants