Weekly-meetings/2015-01-13 (fott; homu; integer overflow; i/o; 1.0; comment rfc)


#1

#2

Hey, I love the evolving discussion around how to handle integer overflow. It’s super-important.

However, I think there may have been a bit of confusion in that meeting around the behavior for shifting. There are two opportunities to “overflow” during shifting. The first is what happens to the bits that get shifted out of the register. The second is overflow in the “shift count” operand itself. In C, using a shift count equal to or greater than the number of bits of the being-shifted value results in “implementation-defined behavior”. C says that something sensible will happen (it’s not UB, but it’s not well-defined either), but C does not say what will happen; it’s left to the compiler vendor.

In practice, everyone just compiles down to whatever shift instruction the underlying hardware uses. x86/x64 hardware masks off all bits except for the bottom N bits of the shift count. For 32-bit operands, N=5, so x as u32 << 32 results in x, not 0u32. For 64-bit operands, N=6, so similarly 'x as u64 << 65is equal tox << 1`. But this is the behavior of only one (admittedly important) processor family; other processors are free to make different decisions, such as setting a result to 0 when shifting by a value >= the number of bits in the operand.

Some languages / platforms provide stronger guarantees. I believe CIL / MSIL (the platform spec for .NET / C#) specifies that the shift count operand is always treated in the way that x86/x64 works, and on non-x86/x64 platforms MSIL adds a mask operation to the shift count itself, when it cannot guarantee statically that the shift count won’t overflow.

So it would be really helpful if Rust also used the equivalent of debug_assert!(shift_count <= sizeof(T) / BITS_PER_BYTE), or some such equivalent.

Separately, I believe the correct behavior for shifting should be that any “overflow” caused by shifting bits out of the main operand is simply ignored. This is the desired behavior for every shift operation that I have ever written. If you want overflow semantics, then you should probably be using multiplication or division.