Live data from Hacker News

Pitfalls of Safe Rust

corrode.dev

91–100 of 145 posts

Re: Pitfalls of Safe Rust

#91
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.

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.

Re: Pitfalls of Safe Rust

#92
post #84

Earlier quoted context omitted.

It is consistent with the way the Rust community uses "safe": as "passes static checks and thus protects from many runtime errors." This regularly drives C++ programmers mad: the statement "C++ is all unsafe" is taken as some kind of hyperbole, attack or dogma, while the intent may well be to factually point out the lack of statically checked guarantees. It is subtle but not inconsistent that strong static checks ("s…

> This regularly drives C++ programmers mad I thought the C++ language did that.

It certainly used to, but tbh C++ since 17 has been pretty decent and continually improving.

That said, I still prefer to use it only where necessary.

Re: Pitfalls of Safe Rust

#93
post #71

Earlier quoted context omitted.

Thank you for sharing. Seems I still have more to learn! It seems the bug you are flagging here is a null reference bug - I know Rust has Optional as a workaround for “null” Are there any pitfalls in Rust when Optional does not return anything? Or does Optional close this bug altogether? I saw Optional pop up in Java to quiet down complaints on null pointer bugs but remained skeptical whether or not it was better to…

It's not so much Optional that deals with the bug. It's the fact that you can't just use a value that could possibly be null in a way that would break at runtime if it is null - the type system won't allow you, forcing an explicit check. Different languages do this in different ways - e.g. in C# and TypeScript you still have null, but references are designated as nullable or non-nullable - and an explicit comparison…

I think sum types in general and Option in particular is nicer. But the reason C# has nullability isn't that they disagree with me, it's that fundamentally the CLR has the same model as Java, all these types can be null, even though in the modern C# language you can say "No, not null that's never OK" at runtime on the CLR too bad maybe it's null.

For example if I write a C# function which takes a Goose, specifically a Goose, not a Goose? or similar - well, too bad the CLR says my C# function can be called by this obsolete BASIC code which has no idea what a Goose is, but it's OK because it passed null. If my code can't cope with a null? Too bad, runtime exception.

In real C# apps written by an in-house team this isn't an issue, Ollie may not be the world's best programmer but he's not going to figure out how to explicity call this API with a null, he's going to be stopped by the C# compiler diagnostic saying it needs a Goose, and worst case he says "Hey tialaramex, why do I need a Goose?". But if you make stuff that's used by people you've never met it can be an issue.

Re: Pitfalls of Safe Rust

#94
post #33
post #22

Earlier quoted context omitted.

Mostly, there is a sub culture that promotes to taint everything as unsafe that could be used incorrectly, instead of memory safety related operations.

That subculture is called “people who haven’t read the docs”, and I don’t see why anyone would give a whole lot of weight to their opinion on what technical terms mean

Because of cult like belief structures growing up around rust, it's clear as day for us on the outside, I see it from the evangelists in the company I work for "rust is faster and safer to develop with when compared to c++", I'm no c++ fan but it's obviously nonsense.

I feel people took the comparison of rust to c and extrapolated to c++ which is blatantly disingenuous.

Re: Pitfalls of Safe Rust

#95
post #74

Earlier quoted context omitted.

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.…

Some of these don't strike me as particularly pragmatic. E.g. are overflow checks really that expensive, given that it's a well-known footgun that is often exploitable? Sure, you don't want, say, 10% overhead in your number-crunching codec or whatever, but surely it's better to have those cases opt in for better perf as needed, as opposed to a default behavior that silently produces invalid results?

> Some of these don't strike me as particularly pragmatic. E.g. are overflow checks really that expensive

Did you read the article? Rust includes overflow checks in debug builds, and then about a dozen methods (checked_mul, checked_add, etc.) which explicitly provide for checks in release builds.

Pragmatism, for me, is this help when you need it approach.

TBF Rust forces certain choices on one in other instances, like SipHash as the default Hasher for HashMap. But again opting out, like opting in, isn't hard.

Re: Pitfalls of Safe Rust

#96
Here's an important one: never use `mem::size_of_val(&T)`. Rust as a language strongly steers you towards ignoring double (or even triple)-referenced types because they're implicitly auto-dereferenced in most places, but the moment you try to throw one of those into this API it returns the size of the referenced reference `&T` which is very much not the same as `T`. I've been burned by this before, particularly in unsafe contexts; I only use `size_of::()` now.

Re: Pitfalls of Safe Rust

#97

Earlier quoted context omitted.

In fact "exclusively" doesn't belong in the statement at all. A very small number of successful RCE attacks use exploits at all, and of those, most target (often simple command) injection vulnerabilities like Log4Shell. If you think back to the big breaches over the last five years, though -- SolarWinds, Colonial Pipeline, Uber, Okta (and through them Cloudflare), Change Healthcare, etc. -- all of these were basic ac…

Can you back up your 'very small number " with some data? I don't think it lines up with my own experience here. It's really not an either or matter. Good security requires a multifaceted approach. Memory safety is definitely a worthwhile investment.

What do you count as data? I can keep naming big breaches that didn't involve exploits, like the Caesars and MGM ransomware attacks, or Russia getting deep into Microsoft. There aren't good public data sets, though.

As an example of a bad data set for this conversation, the vast majority of published CVEs have never been used by an attacker. CISA's KEVs give a rough gauge of this, with a little north of 1300 since 2021, and that includes older CVEs that are still in use, like EternalBlue. Some people point to the cardinality of CVE databases as evidence of something, but that doesn't hold up to scrutiny of actual attacks. And this is all before filtering down to memory safety RCE CVEs.

Probably the closest thing to a usable data set here would be reports from incident response teams like Verizon's, but their data is of course heavily biased towards the kinds of incidents that require calling in incident response teams. Last year they tagged something like 15% of breaches as using exploits, and even that is a wild overestimate.

> Memory safety is definitely a worthwhile investment.

In a vacuum, sure, but Python, Java, Go, C#, and most other popular languages are already memory safe. How much software is actively being written in unsafe languages? Back in atmosphere, there's way more value in first making sure all of your VPNs have MFA enabled, nobody's using weak or pwned passwords, employee accounts are deactivated when they leave the company, your help desk has processes to prevent being social engineered, and so on.

Re: Pitfalls of Safe Rust

#98

Earlier quoted context omitted.

Yeah, they're so common they've become a part of our culture when it comes to interacting with computers. Arithmetic overflows have become the punchline of video game exploits. Unsigned underflow is also one of the most dangerous types. You go from one of the smallest values to one of the biggest values.

Unsigned integers were largely a mistake. Use i64 and called it a day. (Rusts refusal to allow indexing with i64 or isize is a huge mistake.) Don’t do arithmetic with u8 or probably even u16.

Can you expand on your thoughts here? What is the root issue with unsigned integers? Is your complaint primarily based on the implications/consequences of overflow or underflow? I’m genuinely curious as I very often prefer u32 for most numeric computations (although in a more ‘mathematics’ domain signed ints will often be the correct choice).

Re: Pitfalls of Safe Rust

#99
post #37

I'd add memory leaks to the list. Sometimes you feel compelled to wrap your data in an Rc or Arc (reference counted pointers for those unfamiliar) to appease the borrow checker. With capture semantics of closures and futures and such it's quite easy to fall into a referential cycle, which won't be freed when dropped.

[dead]

Re: Pitfalls of Safe Rust

#100
post #71

Earlier quoted context omitted.

It's not so much Optional that deals with the bug. It's the fact that you can't just use a value that could possibly be null in a way that would break at runtime if it is null - the type system won't allow you, forcing an explicit check. Different languages do this in different ways - e.g. in C# and TypeScript you still have null, but references are designated as nullable or non-nullable - and an explicit comparison…

I think sum types in general and Option in particular is nicer. But the reason C# has nullability isn't that they disagree with me, it's that fundamentally the CLR has the same model as Java, all these types can be null, even though in the modern C# language you can say "No, not null that's never OK" at runtime on the CLR too bad maybe it's null. For example if I write a C# function which takes a Goose, specifically…

> For example if I write a C# function which takes a Goose, specifically a Goose, not a Goose? or similar - well, too bad the CLR says my C# function can be called by this obsolete BASIC code which has no idea what a Goose is, but it's OK because it passed null. If my code can't cope with a null? Too bad, runtime exception.

That's actually no different to Rust still; if you try, you can pass a 0 value to a function that only accepts a reference (i.e. a non-zero pointer), be it by unsafe, or by assembly, or whatever.

Disagreeing with another comment on this thread, this isn't a matter of judgement around "who's bug is it? Should the callee check for null, or the caller?". Rust's win is by clearly articulating that the API takes non-zero, so the caller is buggy.

As you mention it can still be an issue, but there should be no uncertainty around who's mistake it is.

Post reply on HN