6 ms·
You pointed at the I/O safety notice in Rust's documentation, but now you've pivoted to saying you were really talking about something different. But wait a se
by tialaramex 3y ago
You pointed at the I/O safety notice in Rust's documentation, but now you've pivoted to saying you were really talking about something different.
But wait a second lets go look at that notice again. Rust is yet again delivering a safety feature C++ just does not have. This actually wasn't in Rust 1.0 -- the safety notice didn't appear then because the I/O safety work landed much later. These safe I/O properties are really useful (even if they're not magic, hence the notice) and C++ doesn't have them.
What's particularly going on here is that on a Unix Rust has types named OwnedFd and BorrowedFd which represent file descriptors, these are quietly just a 32-bit integer with a niche, because -1 isn't a valid file descriptor, that's a niche, so Option<OwnedFd> is the same size in memory as a 32-bit integer.
The result is that Rust gets to do the same trick with file descriptors as it does with pointers - a Rust program working with fds uses the same size data structures as you'd write native C (or thin C++) to work with file descriptors, but where that C or C++ would need to remember to write checks for the -1 file descriptor in Rust that's seamless anyway because it is Option<OwnedFd> so that's None.
On Windows they don't have file descriptors, but they do have Handles, the Handles are much more muddled, and so we can't optimise them as well (actually it's a wonder Windows manages to keep all these balls up in their air they're juggled so frantically, there's a lot of references to Raymond Chen's blog) but again Rust provides I/O safety for these types.
This is the purview of a programming language and Rust does a much better job, I wouldn't have gone out of my way to call attention to it, but you did apparently because you mistook this feature (which C++ doesn't have) for a different feature which C++ is bad at.
- kllrnohj 3y agoEverything you just talked about is unrelated to the issue being discussed. This bug isn't a mismanagement of FD lifecycles, which yes Rust will do more safely out of the box than C++. This bug is a TOCTOU issue ( https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use https://en.wikipedia.org/wiki/Time-of-check_to_time-of-use ) and, more broadly, concurrent access of the file system by multiple processes. Rust cannot guarantee anything about that. Just because you have an FD and you know it's not -1 and you never forget to check that, that doesn't mean anything at all with respect to the concurrent access to the underlying ionode by multiple process for which that FD references. Also it's very easy to make the equivalent of an OwnedFd in C++, eg https://cs.android.com/android/platform/superproject/main/+/main:system/libbase/include/android-base/unique_fd.h https://cs.android.com/android/platform/superproject/main/+/...
- tialaramex 3y agoI understand that the original topic was the TOCTOU bug but again, Rust actually makes explicit promises about what happens here, which it deliver via the appropriate filesystem APIs, whereas what the ISO document tells you for C++ is just you get Undefined Behaviour - absolutely anything might happen - the popular implementations do more but that's not what the standard says. I mentioned what I/O safety really is because you've stumbled onto it while scrabbling to justify the belief that Rust also has UB for the TOCTOU bug. And while Android's ScopedFd is more or less what you'd do in C++ it has a number of significant differences, which I'd say are disadvantages: 1: Most importantly OwnedFd is part of Rust's standard library. 2: ScopedFd insists on behaving like an integer, which is very typical in C++ but not in Rust. If we want a File Descriptor, who cares that those are "actually" integers? Thus we can compare a ScopedFd to an integer - is this ScopedFd more than ten? 3: And so ScopedFd can represent an invalid file descriptor. We don't own that of course, and it's not really a file descriptor at all, but we can (and Android does) represent it anyway. OwnedFd only represents valid file descriptors, an Option<OwnedFile> represents the wider category of either a valid file descriptor or not if that's what you meant. 4: Android provides a borrowing mechanic here, but of course doesn't have a borrow checker, so again you don't actually get the safety benefit of BorrowedFd.