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