Live data from Hacker News

Pitfalls of Safe Rust

corrode.dev

121–130 of 145 posts

Re: Pitfalls of Safe Rust

#121
post #69
post #46

Earlier quoted context omitted.

The commonly given response to this question is two-fold, and both parts have a similar root cause: smart pointers and "safety" being bolted-on features developed decades after the fact. The first part is the standard library itself. You can put your data in a vec for instance, but if you want to iterate, the standard library gives you back a regular pointer that can be dereferenced unchecked, and is intended to be i…

The standard library doesn't give you a regular pointer, though (unless you specifically ask for that). It gives you an iterator, which is pointer-like, but exists precisely so that other behaviors can be layered. There's no reason why such an iterator can't do bounds checking etc, and, indeed, in most C++ implementations around, iterators do make such checks in debug builds. The problem, rather, is that there's no i…

VC++ checked iterators are fast enough for my use cases, not everyone is trying to win a F1 race when having to deal with C++ written code.

Re: Pitfalls of Safe Rust

#122

Earlier quoted context omitted.

If a C++ developer decides to use purely containers and smart pointers when starting a new project, how are they going to develop unsafe code? Containers like std::vector and smart pointers like std::unique_ptr seem to offer all of the same statically checked guarantees that Rust does. I just do not see how Rust is a superior language compared to modern C++

C++ devs need to understand the difference between: Vec1[0]; Vec1.at(0); Even the at method isn’t statically checked. If you want static checking, you probably need to use std::array.

Many also need to learn that there are configuration settings on their compilers that make those two cases the same, enabling bounds checking on operator[]().

Re: Pitfalls of Safe Rust

#123
post #2

Is "as" an uneccesary footgun?

That was my first impression as well. So much of Rust’s language and standard library enforces correctness, that gaps start to feel way more visible. “as” is a good example. Floats are pretty much the only reason PartialEq exists, so why can’t we have a guaranteed-not-NaN-nor-inf type in std and use that everywhere? Why not make wrapping integers a panic even in release mode? Why not have proper dependent types (e.g.…

Regarding the not-NAN float type, there was actually a proposal for it which was shot down: https://github.com/rust-lang/libs-team/issues/238.

I don't remember every argument in there but it seemed that there are good reasons not to add it unlike a NonZero integer type which seems to have no real downsides.

Re: Pitfalls of Safe Rust

#124

Earlier quoted context omitted.

I'm a big fan of liberal use of saturating_mul/add/sub whenever there is a conceivable risk of coming withing a couple orders of magnitude of overflow. Or checked_*() or whatever the best behavior in the given case is. For my code it happens to mostly be saturating. Overflow bugs are a real pain, and so easy to prevent in Rust with just a function call. It's pretty high on my list of favorite improvements over C/C++

If you saturate you almost never ever want to use the result. You need to check and if it saturates do something else.

You obviously have to decide it on a case-by-case basis. But anything that is only used in a comparison is usually fine with saturating. And many things that measures values or work with measurements are fine with saturating if it's documented. Saturating is how most analog equipment works too, and in non-interactive use cases "just pick the closest value we can represent" is often better than erroring out or recording nothing at all.

Of course don't use saturating_add to calculate account balance, there you should use checked_add.

Re: Pitfalls of Safe Rust

#125
post #38

> Surprising Behavior of Path::join With Absolute Paths > I was not the only one who was confused by this behavior. Here’s a thread on the topic, which also includes an answer by Johannes Dahlström: > > The behavior is useful because a caller […] can choose whether it wants to use a relative or absolute path, and the callee can then simply absolutize it by adding its own prefix and the absolute path is unaffected whi…

It's the same in at least Python, so it's not a Rust idiosyncratic behavior. The "absolutize" method you're asking for exists since 1.79. https://doc.rust-lang.org/stable/std/path/fn.absolute.html

Yeah, but I meant a method that would take a custom prefix, like join does now. (In the hypothetical situation where join had different semantics.)

Re: Pitfalls of Safe Rust

#126
post #87
post #49

Earlier quoted context omitted.

Yep. Safe rust also protects you from UB resulting from incorrect multi-threaded code. In C++ (and C#, Java, Go and many other “memory safe languages”), it’s very easy to mess up multithreaded code. Bugs from multithreading are often insanely difficult to reproduce and debug. Rust’s safety guardrails make many of these bugs impossible. This is also great for performance. C++ libraries have to decide whether it’s bett…

I've written some multithreaded rust and I've gotta say, this does not reflect my experience. It's just as easy to make a mess, as in any other language.

Safe rust prevents you from writing data races. All concurrent access is forced to be guarded by synchronization primitives. Eliminating an entire class of bugs.

You can still create a mess from logical race conditions, deadlocks and similar bugs, but you won’t get segfaults because you after the tenth iteration forgot to diligently manage the mutex.

Personally I feel that in rust I can mostly reason locally, compared to say Go when I need to understand a global context whenever I touch multithreaded code.

Re: Pitfalls of Safe Rust

#127
post #120
post #91

Earlier quoted context omitted.

Me too. I agree that its not a bed of roses - and all the memory safety guarantees in the world don't stop you from making a huge mess. But I haven't run into any of the impossible-to-debug crashes / heisenbugs in my multithreaded rust code that I have in C/C++. I think rust delivers on its safety promise.

Most likely because it all multi-threaded code access in-memory data structures, internal to the process memory, the only scenario in multi-threaded systems that Rust has some support for. Make those threads access external resources simultaneously, or memory mapped to external writers, and there is no support from Rust type system.

What mainstream language has type system features that make multi-threaded access to external resources safe?

Managing something like that is a design decision of the software being implemented not a responsibility of the language itself.

Re: Pitfalls of Safe Rust

#128
post #122

Earlier quoted context omitted.

C++ devs need to understand the difference between: Vec1[0]; Vec1.at(0); Even the at method isn’t statically checked. If you want static checking, you probably need to use std::array.

Many also need to learn that there are configuration settings on their compilers that make those two cases the same, enabling bounds checking on operator[]().

Sure, but at() is guaranteed to throw an exception and operator[] can throw an exception when you go out of bounds. C++26 is tweaking this, but it's still going to differ implementation to implementation.

At least that's my understanding of the situation. Happy to be corrected though.

Re: Pitfalls of Safe Rust

#129
post #32

Earlier quoted context omitted.

> The coolest one I've heard is that Fuchsia's network stack managed to eliminate deadlocks. Is there a write up on this? That's very cool

IIRC it is just having locks with exclusive constructors, which take previous locks’ guards (by ownership?). That way you can never lock lock B if you have not received a guard aka lock from lock A prior. Ensured on the type level. I suppose doing this at scale is a real challenge.

The general term for this is "Session types." The Par crate is probably the most mature attempt at this to date.

https://github.com/faiface/par

Re: Pitfalls of Safe Rust

#130
post #120

Earlier quoted context omitted.

Most likely because it all multi-threaded code access in-memory data structures, internal to the process memory, the only scenario in multi-threaded systems that Rust has some support for. Make those threads access external resources simultaneously, or memory mapped to external writers, and there is no support from Rust type system.

What mainstream language has type system features that make multi-threaded access to external resources safe? Managing something like that is a design decision of the software being implemented not a responsibility of the language itself.

None, however the fearless concurrency sales pitch usually leaves that scenario as footnote.
Post reply on HN