4 ms·
I'm aware you can work around it, there are workarounds for issues in Go as well. In general, C programs do not require workarounds for dealing with kernel API
by cyphar 3y ago
I'm aware you can work around it, there are workarounds for issues in Go as well.
In general, C programs do not require workarounds for dealing with kernel APIs for the simple reason that the vast majority of kernel APIs are developed with test programs written in C, so kernel developers will usually not design an API that is awful to use in C.
Another thing that surprised me when I first started programming in Rust is that:
let fd = File::open("foo")?.as_raw_fd();
and
let f = File::open("foo")?;
let fd = f.as_raw_fd();
have different behaviour, with the former being incorrect and a possible security bug if you use the file descriptor directly afterwards. But I guess this behaviour is obvious to seasoned Rust developer (at least, it seems obvious to me now).
- LegionMammal978 3y agoAs I understand it, that as_raw_fd() issue is a big reason that they added the BorrowedFd<'_> type [0] and corresponding AsFd trait in 1.63.0, to prevent the raw file descriptor from outliving its logical owner. Still, I agree that there is lots of potential for issues on the boundary between Rust's implicit lifetime management vs. C APIs' explicit lifetime management, since there won't always be a convenient preexisting mechanism to bridge the gap. [0] https://doc.rust-lang.org/std/os/fd/struct.BorrowedFd.html https://doc.rust-lang.org/std/os/fd/struct.BorrowedFd.html
- kouteiheika 3y agoIt's not a workaround - the `File` in Rust wasn't meant nor designed to support full `open` semantics. If you want to use `open` you should use `open` (or an idiomatic wrapper which is meant to model that) instead of forcing it through `File`. And `open` is not a kernel API either. It's a libc API. If you want to directly access the API provided by the kernel you're supposed to make a syscall, which essentially is exactly the same in Rust and in C. And to make the point of `open` in C *not* being a kernel API more clear, in glibc the `open` function *doesn't* actually call the `open` syscall, but `openat` with `AT_FDCWD`. Glibc doesn't guarantee that a given function will actually call a given syscall, and new versions of glibc often change which syscalls are called by a given function. This is important if you're also doing e.g. seccomp sandboxing, because suddenly your program might stop working if glibc is updated. For example, glibc 2.34 started using the `clone3` syscall under the hood, which broke Chromium Embedded Framework's sandbox. So, again, your argument that a language like Rust "makes it harder to understand what exactly your program is doing" compared to C in this particular case isn't really valid, because C has exactly the same problem if you use libc functions, and the only way to guarantee that the program is doing exactly what you want is to use syscalls, which is the same both in C and Rust. > Another thing that surprised me when I first started programming in Rust Yep. That's one of the Rust's few badly designed APIs.
- rirze 3y agoWhere can I learn more about this? This seems very uninutive to me, as I'm learning Rust myself.
- cyphar 3y agoI'm not sure if there is a document that mentions this in particular, but it is a consequence of how lifetimes work. The core issue is that .as_raw_fd() takes &File and returns an integer (which doesn't have lifetime information). As a result, the File is dropped at the end of the statement and thus the number you got from .as_raw_fd() is invalidated. This does happen elsewhere in Rust, but often when you have methods on &self that return something you use later, the method returns something with the same lifetime (fn foo(&'a self) -> Foo<&'a>) and thus the original object will be kept alive until the end of the scope. It just so happens that file descriptors are tied to the lifetime of the File in a way that Rust cannot express nor detect. I don't know if clippy has a warning for this particular case. It might be useful to add it.