-
Notifications
You must be signed in to change notification settings - Fork 88
Description
In recent years, Rust has adopted a notion of I/O safety that conflicts with some traditional APIs dealing with raw file descriptors (or Win32 handles). In particular, std::io documentation says:
To uphold I/O safety, it is crucial that no code acts on file descriptors it does not own or borrow, and no code closes file descriptors it does not own. In other words, a safe function that takes a regular integer, treats it as a file descriptor, and acts on it, is unsound.
Some safe APIs in signal-hook predate this decree and conflict with it:
signal_hook::low_level::pipe::registersignal_hook::low_level::pipe::register_rawsignal_hook::iterator::backend::SignalDelivery::with_pipe
All of these take an FD as RawFd (alias for c_int) directly or via conversion traits , so they can be called with any plain old integer and are thus considered unsound today. For example, pipe::register_raw(signal, 1) compiles, puts stdout into non-blocking mode, and writes an X to stdout whenever the signal occurs. Unfortunately there's no way to fix this without a semver-breaking change (i.e., bumping signal-hook 0.3 -> 0.4):
- Mark these functions
unsafeand pass the I/O safety requirements to callers. This is a breaking change, and requires all callers to write some extraunsafethemselves. This I/O safety concept also isn't the most intuitive in practice (e.g., it's non-obvious thatimpl IntoRawFdis the wrong trait bound for a safe function taking ownership of an FD), so I wouldn't be surprised if it just pushes the unsoundness into callers. - Change the parameter types / trait bounds to make the functions safe. For example, I believe
pipe::register_rawcould acceptOwnedFd(since it ultimately closes the FD if the action is later unregistered). This is also a breaking change, harder to get right on the library side, and requires bumping MSRV to 1.66 to get access to the new vocabulary types. On the bright side, it's more friendly to users of the library in the long run, since it allows doing a lot of things without anyunsafe(since many types in std and the ecosystem implementAsFdandInto<OwnedFd>).