Limitations of Unsafe Rust

Please tell me what is possible in C/C++ but not in Unsafe Rust. Additionally, if there are any relevant references, I would appreciate it if you could share them.

Here is something I found, you might find it useful.

1 Like

They're different languages with different definitions of UB, so there are things you can do in C which are UB to do in unsafe Rust, and there are things you can do in Rust that are UB in C.

Unsafe Rust has to restore any safety invariants before concluding or invoking safe Rust, while C is effectively all unsafe.

The Nomicon is the go-to reference for unsafe Rust.

7 Likes

Neither is a subset. C++ has typed memory which Rust doesn't, so in some places there's more UB in C++ than in Rust.

1 Like

Can you be more specific please? What kind of answers are you looking for?

2 Likes

I'm concerned about any potential drawbacks of Unsafe Rust, especially regarding low-level pointer operations.

C and Rust have roughly similar pointer UB. See Pointers Are Complicated II, or: We need better language specs

4 Likes

The potential drawback of unsafe Rust is that it is VERY hard to write correct (sound) unsafe Rust. 99% of the time you should just not even try it. A majority of Rust users use it "Pretty much never" ( to "go faster"). You may need to use it to interface to C or C++ code etc. or for low-level programming of IO devices.

2 Likes

It's an interesting dichotomy, on one-hand Rust is low-level and encourages direct memory manipulation and aims for C equivalent performance, while on the other-hand it has an extensive standard library and evolving language like C++. Of those two it's hard to say which is the clearer comparison. I would tend towards C personally, but that isn't to ignore the significance of the standard abstractions.

1 Like

By which I mean that the ways I might arrive at UB in either of Rust, C, or C++ can be very different.

One difference other commenters haven't mentioned is that Rust is based on LLVM and there's one compiler (though gccrs might eventually be an alternative). But for C and C++ there are many choices (gcc, icc, clang, MSVC, etc.). Implementations may choose to not take advantage of optimizations based on undefined behavior, or may choose to define operations that C forbids (e.g. left shifting a negative number). You have the option of writing "incorrect" C that works with your vendor's compiler, with the risk that it might eventually break.

2 Likes

Yes, it’s interesting that the compilers differ in terms of the amount of issues, or warnings they each might create over certain code conditions.

For me, often, the use of unsafe, and by direct extension, the generating of UB in Rust is comparable to addressing low-level memory operations which are typical of C. In many cases with C++ the UB can result from the inappropriate use of high-level function calls. Rust has this too, of course, which is where tools like the geiger-counter are helpful. I think it’s just my perspective of when I see an unsafe block I’m usually expecting there’s going to be code contained which is working with low-level ops.

Really? How?

I understand that without "unsafe" Rust code is guaranteed to be free of UB. There may be "unsafe" in the lower levels but there I trust the authors of said "unsafe" have done the safety checks manually and there is no UB.

That's the goal, but as it turns out, bugs[1] still happen.


  1. or maliciousness etc ↩︎

Ah yes, modulo bugs in the compiler. No doubt they will be fixed.

The wording was mostly me trying to avoid blanket generalizations. Though I agree it’s pretty/very hard to think of cases where the Rust compiler wouldn’t prevent really bad memory safety violations even with function indirection involved. Like it’s generally not that a non-unsafe wielding Rust user of a function would very often necessarily be responsible for mishandling memory as might be the case in C++ which has well-known examples of this, mostly because of the surface area of the language and general absence of compile time checks.

1 Like

And is a difference which I also think disproves comparisons and concerns about the size of the standard library, and the growth of the language generally.

On the other hand, while there are still compiler checks on unsafe code the area of the language with the least restrictions is inline-asm.