Comment by steveklabnik
5 months ago
> But did the rust compiler assume that the integer would not overflow?
It did not.
> It did so in Debug mode where runtime checks were added.
It didn't assume in that case either. It did a well defined thing: add checks.
> If it's not the case in Release mode, does that mean semantics are different between Debug and Release?
Strictly speaking, the language doesn't know about "release mode", as that's a Cargo thing. But yes, in practice, the semantics are different based on various things: it could be debug vs release, it could also be flags that control the behavior. But that's still distinct from "undefined behavior" as a concept. The behavior is well defined, with multiple possible options for behaviors.
So in Rust, you are actually specificing TWO programs with a single source? Those Rust users are surely too clever for my liking!
You can tune a C compiler as well to have a very specific defined behaviour for integer overflow. You can add -fwrapv or you can add UBSAN.
The user never intended overflow to happen, because if they did, they could have used something like __builtin_mul_overflow() or whatever. Or they are an emotionally unstable user with destructive tendencies. The user also never intended the program to abort with a (nicely formatted) error message, unless they are a very very sad depressed nihilistic user who also never runs their program in Release mode.
To say that overflow would be defined in Rust is at least half a lie. We could agree that cargo has a choice of diagnostic policy though, a policy how to handle what is essentially a state with no defined or useful path forward, or in other words, UB.
Throwing errors might be a wanted property to detect oversights. C ecosystem has UBSAN too! But essentially the same is still true: Basic arithmetic operations are not closed over the numbers 0..2^N. Rust doesn't have a (unique and useful) definition for those operations for a subset of numbers. Even if you claim the operations are defined (say wrapping arithmetic in Release mode), it's not what the programmer wants. Probably the majority of algorithms work over natural numbers or integer numbers. These algorithms don't work when the arithmetic on integers modulo 2^N.
So the user has to constrain the set of valid inputs, and do manual sanitization, just like in C.
> You can tune a C compiler as well to have a very specific defined behaviour for integer overflow. You can add -fwrapv or you can add UBSAN.
This is an example of a compiler flag that adds definition to undefined behavior, which is of course, legal to do. That doesn't change that in the standard, it is undefined behavior, and in Rust, it is not.
> To say that overflow would be defined in Rust is at least half a lie.
In the context of "undefined behavior", it is not a lie at all.
> So the user has to constrain the set of valid inputs, and do manual sanitization, just like in C.
No, because the consequences of how the two languages define these behaviors are very, very different.
As you said, overflow is defined in Cargo, given a specific build type and/or specific build flags. It's not defined in Rust.
Just saying that it's defined and then not saying what the definition is, is no different from saying it's undefined.
2 replies →
> It didn't assume in that case either. It did a well defined thing: add checks.
It did. The compiler added the checks (which panic on overflow, from a quick web search) precisely so it (and importantly, the developer!) can assume the overflow didn't happen in the subsequent code. Unless you consider a panic a defined state, and consider wrap-on-overflow equally valid in all cases, it's essentially the same as UB. (panic seems to be considered "unrecoverable").
Difference is _at most_ that C spec gives compiler more freedom to "implement UB", but then again, hit any unsafe code in Rust with wrapped around integer, you probably have comparable practical result -- machine doing random things, corrupting memory and so on.
Okay, I am going to leave this here, as it’s clear to me that we’re not coming to an understanding.