4 ms·
How is that a compromise? The unsafe in `unsafe mod ffi { ... }` is literally the proof that all APIs exposed in the block are sound to call from safe Rust. I
by fluffything 6y ago
How is that a compromise?
The unsafe in `unsafe mod ffi { ... }` is literally the proof that all APIs exposed in the block are sound to call from safe Rust.
It would only need to go hand in hand with a comment explaining why each API in the block is sound to call safely, and it allows users to not list unsound APIs in there, but wrap them manually when needed. Along with code that checks the C++ lib version, etc. to make sure that the proof are kept in sync with each version of the lib.
That's completely different from not requiring any unsafe in the Rust side, and doing this en masse via bindgen.
- cornstalks 6y ago> How is that a compromise? How is it not a compromise? Party A wanted (and implemented) something that didn't require `unsafe`. Party B wanted `unsafe` to be used. After much discussion, Party A concedes with allowing people to put `unsafe` in some of the code, and Party B concedes that putting it there is sufficient instead of requiring it to be strewn all over the place. Sounds like a (reasonable) compromise to me.
- fluffything 6y agoRust requires all safe Rust code to not have undefined behavior. Party A wanting safe Rust to have undefined behavior was wrong. Party A now adds unsafe to their API, so that undefined behavior only happens in unsafe Rust. I don't see the compromise anywhere. Party B told party A that they were wrong, and party A acknowledge it and fixed their crate.
- cornstalks 6y agoYou either haven't looked at how cxx works, or you're intentionally misrepresenting it. cxx generates code that uses `unsafe` blocks/functions. It then generates safe wrappers around those, which are what it exposes to users. It's no different then someone doing this: pub fn safe_fn() { extern { fn unsafe_fn(); } unsafe { unsafe_fn(); } } cxx just uses macros to generate that. You're welcome to have a different opinion on whether or not the user must pass an `unsafe` token to the macro. But that has no bearing on the code generated by the macro. Statements like "Party A wanting safe Rust to have undefined behavior was wrong" are just straight up incorrect.
- Jweb_Guru 6y agoSomeone doing what you just described is wrong in the context of C++, at least without manual review.
- fluffything 6y agoI know how cxx works, and I am not misrepresenting anything. cxx is currently unsound, and the author (dtolnay) has chimed in above with a fix they are considering that fixes it (https://news.ycombinator.com/item?id=24244121 https://news.ycombinator.com/item?id=24244121) The API of the cxx crate is safe, and it can cause UB, therefore it is unsound. It doesn't matter that the cxx crate API is a macro. Yes, this macro expands to unsafe code like you mention, but the problem is that this unsafe code is often "broken" (unsound).
- Ar-Curunir 6y agoUnsafe != unsound
- fluffything 6y agoI know. The Rust spec defines "unsound" as "introducing undefined behavior in safe Rust". The API of the cxx crate allows a safe Rust program to have undefined behavior, and it is therefore unsound.
- tick_tock_tick 6y agoRust requires ALL CODE to not to have undefined behavior. Unsafe doesn't mean you can do whatever you want it just means that you are guaranteeing to the compiler that this block is safe.
- simias 6y agoCan you explain why having to put "unsafe" before FFI calls is considered a problem? That's the part I don't get, isn't the whole point of using Rust that you want sound, memory-safe code by default? If you don't want to have unsafe everywhere it seems to me that the reasonable path (taken by many Rust libraries) is simply to wrap the raw C/C++ interface around a Rust interface that enforces the safety invariants. That's why you can write safe GTK or OpenGL code in Rust, using Rust libraries that expose an actually sound interface. I mean, FFI code is tagged as unsafe because it is unsafe to call. I don't see how "but I don't like having to write unsafe everywhere in my FFI code :(" is in any way a reasonable technical argument here.
- drran 6y agoSome coders want their code to be safe. Some coders want their code to look safe. Feel the difference.
- cornstalks 6y ago> Can you explain why having to put "unsafe" before FFI calls is considered a problem? I intentionally avoided taking a side in this debate. My response was focused on the claim that there was no compromise between the parties, when I think it's pretty clear cut that there is a compromise. Personally, I'm sympathetic to both parties. In my own personal FFI-binding library I chose to let the programmer decide per-method whether it's safe or unsafe.
- simias 6y agoI'm all for compromise but first I need to understand the pros and cons of both sides. For me here so far it's pretty clear cut: there's a right way and a wrong way. The compromise is just a slightly less wrong way. So no I don't accept this compromise in this situation.
- eximius 6y ago> The unsafe in `unsafe mod ffi { ... }` is literally the proof that all APIs exposed in the block are sound to call from safe Rust. I think there might be a misunderstanding here. I interpreted the `unsafe mod ffi { ... }` to be like `unsafe fn foo()`, declaring the module as unsafe, not an unsafe block where we're telling the compiler we will maintain the invariants ourselves. It is somewhat unfortunate both the proof obligation and proof 'declaration' use the same token.
- fluffything 6y ago> It is somewhat unfortunate both the proof obligation and proof 'declaration' use the same token. There have been some RFCs open to improve this situation (e.g. unsafe blocks in unsafe functions comes to mind).