Portability bug in integral conversion

Don nospam at nospam.com
Mon Jan 17 12:53:45 PST 2011


Andrei Alexandrescu wrote:
> On 1/17/11 2:47 AM, Don wrote:
>> Andrei Alexandrescu wrote:
> [snip]
>> 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.
> 
> That doesn't compile. This does:
> 
> short a = -1;
> a >>>= 1;
> 
> a becomes 32767, which didn't surprise me. Replacing >>>= with >>= keeps 
> a unchanged, which I also didn't find surprising.

Aargh, that should have been:
short a = -1;
ushort b = -1;
assert( a == b ); // passes
assert( a >>> 1 == b >>> 1); // fails


Another example:

     uint x = 3;
     uint y = 8;
     ulong z = 0;
     ulong a = (z + x) - y;
     ulong b = z + (x - y);
     assert(a == b); // Thought addition was associative, did you?

'a' only involves size-extension, so it's OK.
But 'b' has a subexpression which sets the carry bit.
Actually it doesn't even need subtraction.

     uint x = uint.max;
     uint y = uint.max;
     ulong z = 0;
     ulong a = (z + x) + y;
     ulong b = z + (x + y);
     assert(a == b); // Still thought addition was associative?

It's the same deal: you shouldn't be able to size-extend, when the state 
of the carry flag is unknown.

Once you have performed an operation which can wrap around, you have 
discarded the carry bit. This means you have made a commitment to 
arithmetic modulo 2^^32.
And then the next addition is arithmetic modulo 2^^64! Which is a 
fundamentally different, incompatible operation. It should be a type 
mismatch.

Note that because small types get promoted to int, the problem mostly 
shows up with uint -> ulong (for smaller types, the carry bit is 
retained inside the int).


>> I think it should be forbidden in all cases. I think it can be done with
>> a flag in the range propagation.
> 
> Yes, that would be awesome!
> 
> 
> Andrei


More information about the Digitalmars-d mailing list