[過去ログ] C#, C♯, C#相談室 Part96 (1002レス)
上下前次1-新
抽出解除 レス栞
このスレッドは過去ログ倉庫に格納されています。
次スレ検索 歴削→次スレ 栞削→次スレ 過去ログメニュー
142(1): デフォルトの名無しさん (ワッチョイ 1232-IMun) [sage] 2022/03/15(火) 21:00:09.00 ID:ZTE9InWz0(1/3) AAS
>>137137(2): デフォルトの名無しさん (ワッチョイ a236-8qwV) [sage] 2022/03/15(火) 17:49:18.74 ID:uT8cdwkS0(1/4) AAS
相談させてください。
IntPtr を ref int に変換するために以下のようなコードを書くと、期待通り False と表示されます。
IntPtr ptr = Marshal.AllocCoTaskMem(4);
ref int x = ref Unsafe.AddByteOffset(ref Unsafe.NullRef<int>(), ptr);
Console.WriteLine(Unsafe.IsNullRef(ref x)); // False と表示される
Marshal.FreeCoTaskMem(ptr);
しかし、以下のように意味のない for 文を追加すると、コードの最適化が有効な場合のみ True と表示されます。
for (int i = 0; i < 0; i++) { } // 意味のない for 文
IntPtr ptr = Marshal.AllocCoTaskMem(4);
ref int x = ref Unsafe.AddByteOffset(ref Unsafe.NullRef<int>(), ptr);
Console.WriteLine(Unsafe.IsNullRef(ref x)); // 最適化が有効な場合のみ True と表示される
Marshal.FreeCoTaskMem(ptr);
ただし、意味のない for 文があっても
Unsafe.AddByteOffset(ref Unsafe.NullRef<int>(), ptr)
→ Unsafe.SubtractByteOffset(ref Unsafe.NullRef<int>(), -(nint)ptr)
のように書き換えると常に False と表示されるようになります。
なぜこのようなことが起こるのかさっぱり見当がつかないので、お知恵を拝借できないでしょうか。
私の環境を分かる範囲で書くと以下のとおりですが、他に何か必要な情報があればお教えください。
Windows 10 Pro (21H2)
Microsoft Visual Studio Community 2022 (64 ビット) Version 17.1.1
コンソール アプリケーション、.NET 6.0
どうぞよろしくお願いいたします。
JIT最適化を抑制せずF11でデバッグして逆アセンブルすると
先にConsole.WriteLine(Boolean)がTrue固定で呼び出されて
その後にMarshal.IsNullOrWin32Atom(IntPtr)となってるね
未定義動作はタイムトラベルを…彷彿とさせるがC#なんだよなぁ
MSIL的にも&とnative intの結果型は&に定められている筈だし
とはいえ、管理下ポインタはnullになりえないとか有った気もするし
null参照への演算が未定義なら道理なのかもしれない、あるいはバグか
144(1): デフォルトの名無しさん (ワッチョイ a236-8qwV) [sage] 2022/03/15(火) 21:24:27.40 ID:uT8cdwkS0(3/4) AAS
>>142
null参照への演算が未定義というのは、AddByteOffset メソッド内の話でしょうか。
下記のページの AddByteOffset<T>(ref T, IntPtr) のところをみると
ldarg.0
ldarg.1
add
ret
とコメントされていて、少なくとも IL 的には一つ目の引数が null でも特に問題はないように思えてしまいます。
IL 的に問題がないかどうかは私は自信がないのですが、
もし IL に問題がないのに JIT 最適化で問題が起きてしまうとすれば、
バグと考えてもよいのでしょうか。
参考
外部リンク[cs]:github.com
上下前次1-新書関写板覧索設栞歴
スレ情報 赤レス抽出 画像レス抽出 歴の未読スレ AAサムネイル
ぬこの手 ぬこTOP 1.704s*