7 ms·
I'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 defau
by ChrisSD 6y ago
I'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
- MaxBarraclough 6y agoProgrammers can't be trusted to do this kind of free-form reasoning correctly, as attested by the unending stream of security vulnerabilities arising from undefined behaviour in C and C++ codebases. The push for safe languages is motivated by pragmatism, not theoretical purity.
- bluGill 6y agoThe push back that performance matters in the real world still exists. I want a secure language, but I don't have enough spare CPU for some
- MaxBarraclough 6y agoThe performance of modern Rust is competitive with C++.
- bluGill 6y agoWhich is why I told my boss I want some time to play with rust to see how it works in our real world.
- renox 6y ago> I imagine it might have a significant performance impact, It depends on the CPU: MIPS has(had if you consider MIPS dead) some integer operations which trapped in case of integer overflow AFAIK the 'trapping operations' were as fast as the non-trapping operations (when no overflow occurred of course). Unfortunately even though RISC-V is MIPS successor, it doesn't have those trapping operations :-( I must admit I don't understand why no modern CPU ISA has these trapping instructions: explicit checks have an 'instruction cache cost', so users won't enable them which reduces security..
- littlestymaar 6y agoZero UB in safe code is a core design constraint of Rust so I think it makes sense. Having integer overflow being implementation defined would sound more logical to me than the current behavior, but maybe there are arguments against it also.
- MaxBarraclough 6y agoIntroducing implementation-defined behaviour would undermine the advantages of Safe Rust. If I understand the goals of the Safe Rust project correctly, it aims to be a truly safe language, like Java or JavaScript. This means it must have no undefined behaviour, and beyond that, it should be as close to 'totally defined' as possible, without leaving program behaviour up to the particular platform, which would open the door to subtle bugs. (Concurrency is an exception here, as it really can't be made to be deterministic. Floating point might be another.) An obvious example: does this code result in a divide-by-zero? (I'll use C syntax.) int myInt = INT_MAX; ++myInt; int myOtherInt = 1000 / myInt; If signed overflow is permitted to result in myInt holding zero, then we have a divide-by-zero. Not the kind of thing that should be left up to the particular platform. The behaviour of your Java code does not change when you move it from a 32-bit x86 machine to a 64-bit ARM machine. That's part of the appeal of Java. The same should be true of Safe Rust. To put that another way: Safe Rust is remarkable because of its ambition: to be a truly safe language, while also having excellent real-world performance. It seems to be succeeding in doing both, without trading off on performance (Java, Go, C#) or safety (C++, and even Ada). If it starts compromising on either dimension, it becomes 'just another language'.
- steveklabnik 6y agoTo be clear, it actually is implementation defined. The rules are: Integer overflow is a "program error." This case is handled by either "default" or "enabled" overflow checking: * If checks are "enabled", then overflow must panic * If checks are "default", then you'll get two's compliment wrapping For implementations, if debug_assertions are enabled, then so must overflow checking be, unless the user specifically requests otherwise. According to these rules, rustc today has "enabled" checking when debug_assertions is on, or when the user requests it via a flag. Otherwise, it leaves it to "default." If these checks ever become cheap enough, rustc may move to "enabled" in all cases by default. We'll see if that ever happens.
- renox 6y agoSure but in practice Rust is as performant as C/C++ in benchmarks, so IMHO 'integer overflow is UB' should be scrapped..
- MaxBarraclough 6y agoThe same argument applies to various other instances of undefined behaviour. Integer division in Java never results in undefined behaviour. Divide-by-zero results in an exception, as does (Integer.MIN_VALUE / -1). In C/C++, both of those operations result in undefined behaviour. Modern JVMs have to generate some additional instructions to implement this [0], but I wonder if the real-world performance penalty is that substantial. Another example is reading an uninitialized variable, which is undefined behaviour in C/C++. Does this footgun really improve performance, with modern compilers? I don't have a solid answer here but I suspect not. > IMHO 'integer overflow is UB' should be scrapped The C committee is opposed to radical change, they never want to step on the toes of exotic compilers and exotic hardware architectures, so I doubt they'll ever change it. I think it would be more realistic to ask the major compiler vendors to commit to never doing anything unsafe on signed integer overflow. I believe GCC has an 'opt-in' flag for this. I wonder what the performance cost is, if any. Perhaps it breaks some optimisations, but as you say, other fast languages like Rust seem to get by fine. [0] https://www.javaer101.com/en/article/3166570.html https://www.javaer101.com/en/article/3166570.html