Portability bug in integral conversion

Don nospam at nospam.com
Mon Jan 17 00:47:57 PST 2011


Andrei Alexandrescu wrote:
> We've spent a lot of time trying to improve the behavior of integral 
> types in D. For the most part, we succeeded, but the success was 
> partial. There was some hope with the polysemy notion, but it ultimately 
> was abandoned because it was deemed too difficult to implement for its 
> benefits, which were considered solving a minor annoyance. I was sorry 
> to see it go, and I'm glad that now its day of reckoning has come.
> 
> Some of the 32-64 portability bugs have come in the following form:
> 
> char * p;
> uint a, b;
> ...
> p += a - b;
> 
> On 32 bits, the code works even if a < b: the difference will become a 
> large unsigned number, which is then converted to a size_t (which is a 
> no-op since size_t is uint) and added to p. The pointer itself is a 
> 32-bit quantity. Due to two's complement properties, the addition has 
> the same result regardless of the signedness of its operands.
> 
> On 64-bits, the same code has different behavior. The difference a - b 
> becomes a large unsigned number (say e.g. 4 billion), which is then 
> converted to a 64-bit size_t. After conversion the sign is not extended 
> - so we end up with the number 4 billion on 64-bit. That is added to a 
> 64-bit pointer yielding an incorrect value. For the wraparound to work, 
> the 32-bit uint should have been sign-extended to 64 bit.
> 
> To fix this problem, one possibility is to mark statically every result 
> of one of uint-uint, uint+int, uint-int as "non-extensible", i.e. as 
> impossible to implicitly extend to a 64-bit value. That would force the 
> user to insert a cast appropriately.
> 
> Thoughts? Ideas?
> 
> 
> Andrei

This is a new example of an old issue; it is in no way specific to 64 bits.
Any expression which contains a size-extension AND a signed<->unsigned 
implicit conversion is almost always a bug. (unsigned - unsigned leaves 
the carry flag unknown, so sign extension is impossible).

It happens a lot with ushort, ubyte. There are several examples of it in 
bugzilla. short a=-1; a = a>>>1; is a particularly horrific example.

I think it should be forbidden in all cases. I think it can be done with 
a flag in the range propagation.


More information about the Digitalmars-d mailing list