8 ms·
Another (much smaller) detail is that signed overflow in C is undefined (and iirc GCC takes advantage of that when optimizing) but signed overflow in Rust is pr
by creata 6y ago
Another (much smaller) detail is that signed overflow in C is undefined (and iirc GCC takes advantage of that when optimizing) but signed overflow in Rust is precisely defined to error in debug mode and wrap in release mode.
- edflsafoiewq 6y agoAnd unsigned overflow is also error-in-debug, overflow-in-release with Rust. If you want wrapping arithmetic, you have to ask for it. In C, unsigned overflow always wraps, so even though you can compile with overflow checks, there's no way to distinguish unsigned arithmetic that is supposed to vs not supposed to wrap.
- MaxBarraclough 6y agoSounds sensible. To quote John Regehr: > Java-style wrapping integers should never be the default, this is arguably even worse than C and C++’s UB-on-overflow which at least permits an implementation to trap. • https://blog.regehr.org/archives/1401 https://blog.regehr.org/archives/1401
- saagarjha 6y agoI actually dislike Rust's "wrap in production" default, tbh. It strikes a strange balance: "we care about performance in release mode but we are also going to check and make sure this code does specific things on overflow".
- ChrisSD 6y agoI'm not sure I follow. In release mode it does the most performant thing by default. In debug mode and tests it catches potential problems with using this default. Either way there are explicit methods for doing wrapped, checked or saturating operations in every mode.
- saagarjha 6y agoUndefined behavior on overflow is always the most performant, followed closely by "the result is unspecified". Wrapping is less performant because it often forces the implementation to actually wrap if the behavior is observable, which might be extra work (e.g. i32) or interfere with loop optimizations.
- MaxBarraclough 6y agoUndefined behaviour isn't an option for Safe Rust, where the impossibility of invoking undefined behaviour is the whole point. Non-deterministic unspecified values aren't in keeping with the Safe Rust philosophy either. I imagine throw-on-overflow is slower than wrap-on-overflow. C# can be configured to throw an exception when an int is overflowed, [0] but this behaviour isn't the default and is rarely used (typically it uses wrap-on-overflow). I imagine it might have a significant performance impact, but I'm not sure. In a language like SPARK Ada, intended for formal verification, you can insist upon a rigorous proof that unintended overflow can never occur. That isn't an option for Safe Rust, at least not without significant breakthroughs in tooling. [0] https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/checked-and-unchecked https://docs.microsoft.com/en-us/dotnet/csharp/language-refe...
- bluGill 6y agoPerhaps, but I often know via information not available to the compiler (it might be to a SPARK proof) that overflow won't happen and I don't want to check for it.
- deleted 6y ago[deleted]
- nicoburns 6y agoThat option's available in Rust on a per opration basis if you want it, it's just not the default
- 6y ago
- __s 6y agoAm important thing to remember is that even with wrapping Rust maintains memory safety Still, I agree, I prefer consistent semantics between dev/prod as much as possible. Especially since there's methods to have checked/wrapping/etc arithmetic, so I can always go to those if I want the other behavior Thankfully, this behavior is a flag which you can personally configure to be consistent across dev/prod: https://doc.rust-lang.org/cargo/reference/profiles.html https://doc.rust-lang.org/cargo/reference/profiles.html It does make sense when interpreting wrapping checks in dev as debug assertions
- dathinab 6y ago> "we care about performance in release mode but we are also going to check and make sure this code does specific things on overflow". More like: > "integer overflow checks are a painful/unacceptable performance degradation for some use-cases, but we still want to cough over-/under-flow bugs during testing" Anyway luckily you can just enable integer overflow checks in release builds, which is not a uncommon setup in use-cases like server code.
- dgellow 6y agoSo, how do professional C programmers deal with this in general? Do they manually check for `x > MAX_INT || x < MIN_INT` every time they want to do some arithmetic? Do they manually check the CPU overflow flag after an operation? Or something else? (I only have limited C experience, and only for hobby projects)
- pansa2 6y agoEither you need to restrict arithmetic to values which can’t overflow, or yes, you need to check for overflow manually. Note that you need to do those checks without actually triggering the overflow because once undefined behaviour is possible, all bets are off.
- dgellow 6y agoI see, so checking for the overflow flag wouldn't be good as you now have your program in an undefined state.
- deadbytes 6y agoWhen I looked into doing this before I think the ultimate issue was that the C specification doesn't even give you any way to check the overflow flag. So even if you knew your specific C implementation handled overflow properly there is no way to check the flag afterwards anyway.
- nwellnhof 6y agoThis has nothing to do with C programming. If an arithmetic operation could overflow, you always have to add a check regardless of programming language. It's simply that a lot of high-level code doesn't care about such a level of correctness. Another exception are languages like Python that automatically upgrade your integers to arbitrary precision on overflow. That said, most of the time you end up counting objects in the current address space. If you assume that there can exist no more than `SIZE_MAX` objects in memory, you can avoid many overflow checks.