←back to thread

Pitfalls of Safe Rust

(corrode.dev)
168 points pjmlp | 1 comments | | HN request time: 0.246s | source
Show context
forrestthewoods ◴[] No.43604132[source]
> Overflow errors can happen pretty easily

No they can’t. Overflows aren’t a real problem. Do not add checked_mul to all your maths.

Thankfully Rust changed overflow behavior from “undefined” to “well defined twos-complement”.

replies(4): >>43604262 #>>43605035 #>>43605473 #>>43605491 #
LiamPowell ◴[] No.43604262[source]
What makes you think this is the case?

Having done a bunch of formal verification I can say that overflows are probably the most common type of bug by far.

replies(1): >>43605030 #
imtringued ◴[] No.43605030[source]
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.

replies(1): >>43606425 #
forrestthewoods ◴[] No.43606425[source]
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.

replies(1): >>43606973 #
throwaway17_17 ◴[] No.43606973[source]
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).
replies(1): >>43608493 #
1. forrestthewoods ◴[] No.43608493[source]
> What is the root issue with unsigned integers?

If I play "Appeal to Authority" you can read some thoughts on this from Alexandrescu, Stroustrup, and Carruth here: https://stackoverflow.com/questions/18795453/why-prefer-sign...

Unsigned integers are appealing because they make a range of invalid values impossible to represent. That's good! Indices can't be negative so simply do not allow negative values.

The issues are numerous, and benefits are marginal. First and foremost it is extremely common to do offset math on indices whereby negative values are perfectly valid. Given two indices idxA and idxB if you have unsigned indices then one of (idxB - idxA) or (idxA - idxB) will underflow and cause catastrophe. (Unless they're the same, of course).

The benefits are marginal because even though unsigned cannot represent a value below the valid range it can represent a value above container.size() so you still need to bounds check the upper range. If you can't go branchless then who cares about eliminating one branch that can always be treated as cold.

On a modern 64-bit machine doing math on smaller integers isn't any faster and may in fact be slower!

Now it can be valuable to store smaller integers. Especially for things like index lists. But in this case you're probably not doing any math so the overflow/underflow issue is somewhat moot.

Anyhow. Use unsigned when doing bitmasking or bitmanipulation. Otherwise default to signed integer. And default to i64/int64_t. You can use smaller integer types and even unsigned. Just use i64 by default and only use something else if you have a particular reason.

I'm kinda rambling and those thoughts are scattered. Hope it was helpful.