Description
I/O safety is summarized as
a guarantee that if one part of a program holds a raw handle privately, other parts cannot access it
I would argue then that if a function is written foo(fd: OwnedFd)
, then it should be guaranteed that it is the only one with read/write access to the underlying resource managed by this FD. (Of course if it is a file, others might be able to open the file again, but not all FDs are for files that have a name in the file system.) And this guarantee almost holds, except for OwnedFd::try_clone
and BorrowedFd::try_clone_to_owned
. These will take a mere reference and return a fully owned OwnedFd
(via dup
), so our foo
function has been foo'led and it is not actually exclusively reading/writing the underlying resource.
I am somewhat surprised to discover this now; these functions were not mentioned in the original RFC. They fundamentally change what it means to hold an OwnedFd
, and I think not for the better. They are incompatible with the mental model I used when helping design and defend I/O safety.
So, what shall we do about this?
- Document the actually remaining guarantees for
OwnedFd
carefully. They are very weak (basically just "nobody will close this FD while you have it"). - Attempt to change the past and deprecate the safety of these methods.
Also, we should clarify what this means for I/O safety overall. Would it be sound to do dup(rand())
and return the result as an OwnedFd
? I think the answer should be "absolutely not"; if I create an FD and don't share it with anyone I should be guaranteed that no duplicates exist. This would at least make it possible for a user crate to define NonDupOwnedFd
/NonDupBorrowedFd
types that guarantee an absence of duplicates.
Cc @sunfishcode