3
0

More than 3 years have passed since last update.

C#(.NET Frameworks) - 0x80000000以上の値をもつIntPtrをuintにキャストするとuintに収まる値なのにOverflowExceptionが発生するので解析してみた

Last updated at Posted at 2020-08-25

経緯

Windows APIを使ってるときに、タイトルの現象に遭遇したので原因を探ってみた。

実験用コード


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; // ここで例外が発生する
            Console.WriteLine(t2Cast);
        }
        catch(OverflowException e){
            Console.WriteLine(e);
        }
    }
}

実行結果


2147483648
2147483647
System.OverflowException: 算術演算の結果オーバーフローが発生しました。
   場所 CastTest.Main(String[] args)

原因 - 内部的にはintにキャストしている

ildasmで uint t2Cast = (uint)t2; に該当する処理のコンパイル後コードを確認したところ、下記となっている。
intにキャストしてらっしゃる。。


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

ILSpyで上記のメソッドをみると、下記となっている。ご丁寧にもcheckedが付いている。ので、オーバーフロー例外を投げる。


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

回避方法(暫定)

とりあえずlong型へのキャストを経由する。
(checkedの有効な中から呼ばれた場合、63bit目が立ってると多分同じ目に遭う…)

ちなみに ILSpyでlongにキャストしているメソッドらしきものをみると、


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

となっている。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0