7 ms·
Why are arithmetic overflows and underflows not exceptions/crashes by default, like divison by 0? Aren't the cases where you actually want an over/underflow th
by VMG 11y ago
Why are arithmetic overflows and underflows not exceptions/crashes by default, like divison by 0?
Aren't the cases where you actually want an over/underflow the exception? Why not resort to special instructions/macros/operators for these operations?
- CUViper 11y agoRust debated this for a while, and eventually did decide to make overflows panic -- but they are checked only in debug builds. https://github.com/rust-lang/rfcs/blob/master/text/0560-integer-overflow.md https://github.com/rust-lang/rfcs/blob/master/text/0560-inte...
- ploxiln 11y agoPerformance. That's an extra branch on every arithmetic operation.
- barrkel 11y agoThat's not how you'd implement it if you had a choice though. You'd rely on a certain page of memory not being mapped on the target platform (the page that starts at address 0 is often a fine choice) and you'd issue a conditional move that touches that address. You'd rely on the CPU exception interrupt mechanism to branch. I know modern ARM instruction sets don't have conditional instructions like that, but they may have something similar for extremely infrequently triggered control flow. The same kind of trick can be handy in a variety of programming language and GC implementation techniques.
- zurn 11y agoThere's a performance cost now because processor instruction sets have dropped hardware overflow detection due to disuse. Current processors are largely engineered to just run legacy C code fast. See eg. https://news.ycombinator.com/item?id=7847980 https://news.ycombinator.com/item?id=7847980
- johncolanduoni 11y agoI think it is time for this removal to be reexamined, considering popular scripting languages like Python and Ruby (which check for overflows on all integer operations) face significant performance hits because of lack of hardware support for these instructions.
- zurn 11y agoThe naive check-and-branch approach on current x86 only costs a couple of percent in integer-heavy and well tuned C code (see http://danluu.com/integer-overflow/ http://danluu.com/integer-overflow/). Integer operations in Python and Ruby are so glacially slow compared to C that the overflow checking overhead doesn't register at all due to all the other overhead there.
- acqq 11y agoNo, overflow is still properly detected by common CPU instructions. There are flags that are set on overflow after the addition and subtraction and they can be tested. It's only hard to test the flags in "standard" C (I don't know if it's better with newer standards or those in progress) but the CPUs do their work on the hardware level.
- zurn 11y agoBut like ploxiln said you now need a conditional branch to test for the overflow flag after the arithemetic operation, unlike the old overflow traps on x86/MIPS/Alpha etc.
- acqq 11y agoI'm not aware that integer operations ever made traps on x86 and nobody actually uses floats for allocation sizes (in C). And checking the flag would be more than enough IF the languages supported it. It's the languages that should be changed to be able to simply check the overflow after the critical operations, not the CPUs. The overflow checks are needed only where something can "go wrong" not everywhere.
- captainmuon 11y agoYou could actually have runtime checks by default (in a hypothetical language), and have a smart compiler elide them whenever possible. int32 a, b = ...; a+b; // there is a check // implicitly: // if (MAX_INT32 - a <= b) throw OverflowException; // a+b; but int32 a = ...; // after here: typeof(a) = int32 int32 b = rand_int(0, 1000); // after here: typeof(b) = int32[x|where x >=0 and x < 1000] if (a < 500) { // in here: typeof(a) = int32[x|where x < 500] a+b; // the overflow check can be elided } So the compiler would be able to narrow down the type of a variable, and know what operations are safe to perform. This is probably impossible in the general case (halting problem and so on), but I believe it is very doable if you restrict yourselves to a limited number of subranges. This is like a kind of dependent types, but completely internal (you could expose them, if you wanted though). The compiler can't only use this extra information to remove overflow checks, but you can also have a language that guarantees there is no overflow - add two int32 and the result is an int64, and so on. And if it can infer that the result fits in an int16, then it can put it in there. But most of the time you would just use int, which means: integer variable of enough length to store my data. int8, int16, int32, maybe a BigNum. Kind of like python does it, but with the ability to pick optimized native types if needed.
- cautious_int 11y agoBecause unsigned overflow will not happen in C, and will instead wrap the value. The variables in question were unsigned. This is defined and perfectly normal. However signed integers will cause undefined behavior on overflow and there is a common flag in most compilers to trap on overflow.