checked-unchecked uint32 to int64 conversion bug
От: fddima  
Дата: 25.07.12 21:03
Оценка:
В общем, компилятор 1.1.772 генерирует неправильный IL код.
Попытался оформить ближе к тестам но поскольку я их не запускал (в смысле те что с компилятором), просто оформил по образу и подобию, но не факт что правильно.
Основная проблема в неверной конвертации uint32 в int64 в unchecked контексте.
Any comments?

using System;
using System.Console;

module Program
{
    // At this moment all fine with this method.
    CheckedUInt32ToInt64Conversion() : long
    {
        checked
        {
            def a : uint = 0xAA000000;
            def b : uint = 0x00BB0000;
            def c : uint = 0x0000CC00;
            def d : uint = 0x000000DD;

            def r = (a | b | c | d) :> long;

            r
        }
    }

    // UncheckedRound:
    // Check generated IL code for this method:
    //
    // .locals init (
    //    [0] uint32 a,
    //    [1] uint32 b,
    //    [2] uint32 c,
    //    [3] uint32 d,
    //    [4] int64 r
    // )
    //
    // def a : uint = 0xAA000000;
    //     IL: GOOD!
    //     > ldc.i4 -1442840576
    //     > stloc.0
    //
    // SECONDARY BUG:
    // def b : uint = 0x00BB0000;
    //     IL: BAD!
    //     ldc.i4 12255232
    //     conv.ovf.u4          // hey! we are in unchecked! Using unwanted coversions it is bad.
    //     stloc.1
    //     ...same for def c and def d.
    //
    // PRIMARY BUG:
    // def r = (a | b | c | d) :> long;
    //     IL:
    //     ldloc.0      //
    //     ldloc.1      //
    //     or           //
    //     ldloc.2      //
    //     or           //
    //     ldloc.3      //
    //     or           // right

    //     conv.i8      // WRONG! This opcode now convert's signed int32 to signed int64 (i.e. with sign bit extension)
                        // but we need conversion unsigned int32 to signed int64
                        // while stack always stores signed values 
                        // we just need use conv.u8 instead of conv.i8 (it always safe when convert uint32->int64, and same thing do C# compiler).
                        // btw, in checked mode nemerle generates conv.ovf.i8.un that looks fine, but redundant while this conversion type (conv.u8 enough)

    //     stloc.s r    // good. (note that we store unsigned int64 as signed int64 but it is exact that we want in this case)
    //
    UncheckedUInt32ToInt64Conversion() : long
    {
        unchecked
        {
            def a : uint = 0xAA000000;
            def b : uint = 0x00BB0000;
            def c : uint = 0x0000CC00;
            def d : uint = 0x000000DD;

            def r = (a | b | c | d) :> long;

            r
        }
    }

    Main() : void
    {
        WriteLine("0x{0:X16}", CheckedUInt32ToInt64Conversion());
        WriteLine("0x{0:X16}", UncheckedUInt32ToInt64Conversion());
    }
}

/*
BEGIN-OUTPUT
0x00000000AABBCCDD
0x00000000AABBCCDD
END-OUTPUT
*/
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.