C # (.NET Frameworks) –When I cast an IntPtr with a value of 0x80000000 or more to uint, an OverflowException occurs even though the value fits in uint, so I analyzed it.

1 minute read

Background

When I was using the Windows API [https://qiita.com/kob58im/items/0273632e96afceca7d0a), I encountered the phenomenon of the title, so I searched for the cause.

Experimental code


using System;

class CastTest
{
    [STAThread]
    static void Main(string[] args)
    {
        IntPtr t1 = new IntPtr(0x7FFFFFFFu);
        IntPtr t2 = new IntPtr(0x80000000u);

        try{
            uint tmp = 0x80000000u;
            Console.WriteLine(tmp);
            uint t1Cast = (uint)t1;
            Console.WriteLine(t1Cast);
            uint t2Cast = (uint)t2; //An exception occurs here
            Console.WriteLine(t2Cast);
        }
        catch(OverflowException e){
            Console.WriteLine(e);
        }
    }
}

Execution result

```Execution result

2147483648
2147483647
System.OverflowException:An overflow occurred as a result of an arithmetic operation.
Location CastTest.Main(String[] args)


# Cause-Internally casting to int

 When I checked the compiled code of the process corresponding to ʻuint t2Cast = (uint) t2; `in ildasm, it is as follows.
 You are casting to <b> int. .. </b>

call int32 [mscorlib]System.IntPtr::op_Explicit(native int)


 Looking at the above method in ILSpy, it is as follows. <b> It is politely marked with `checked`. </b>, so throw an overflow exception.

```csharp

public unsafe static explicit operator int(IntPtr value)
{
	long num = (long)value.m_value;
	return checked((int)num);
}

Workaround (provisional)

For the time being, go through the cast to long type.
(If you are called from among the valid checked, you will probably encounter the same thing if the 63rd bit is standing …)

By the way, if you look at what seems to be a method cast to long with ILSpy,


public unsafe static explicit operator long(IntPtr value)
{
	return (long)value.m_value;
}

It has become.