none
Compiler Bug? VS2008 RRS feed

  • 質問

  • VS2008 C#コンパイラの比較演算の挙動が腑に落ちません。

    以下のコードをデバッガでトレースすると最終比較行のみが真になり、例外になってしまいます。

    // キャプチャデバイスを列挙する
    iDeviceNum = 0;
    capDevices = DsDevice.GetDevicesOfCat(FilterCategory.VideoInputDevice);
    int n = iDeviceNum + 1;
    if (n > capDevices.Length) {
    	// Skip
    	throw new Exception("No video capture devices found at that index!");
    }
    if (capDevices.Length <= iDeviceNum) {
    	// Skip
    	throw new Exception("No video capture devices found at that index!");
    }
    if (capDevices.Length < iDeviceNum + 1) {
    	// Skip
    	throw new Exception("No video capture devices found at that index!");
    }
    if (capDevices.Length < iDeviceNum + 1) {
    	// Skip
    	throw new Exception("No video capture devices found at that index!");
    }
    if (iDeviceNum > capDevices.Length - 1) {
    	// Skip
    	throw new Exception("No video capture devices found at that index!");
    }
    if ((iDeviceNum + 1) > capDevices.Length) {
    	// Pass
    	throw new Exception("No video capture devices found at that index!");
    }
    

    2018年12月13日 1:39

回答

  • 状況だけ確認したので。

    if (a >= b) {

    にブレークポイントを置いて、そこまで実行し、F10でステップ実行すると、カレント実行行が「throw」の所に行く(ように見える)という現象なのかな ?

    表示上、throwが実行されそうですが、実際に実行するとthrowは実行されません。

    ifのブレークポイントを外して、throwにブレークポイントを置いて実行しても、ブレークされません。デバッグ情報か何かのバグですかね ?


    Sorry, I am not good at English.

    • 回答としてマーク jundivert 2019年6月24日 4:14
    2018年12月14日 3:05
  • 当方環境でも再現しました。なお、x86 ビルドに変更した場合は問題ありませんでした(AnyCPU / x64 ビルドでのみ発生)

    • Windows 7 Pro (Build 7601: Service Pack 1) 64bit
    • Visual Studio Team System 2008 (Version 9.0.30729.4108 QFE)
    • .NET Framework 3.5 SP1

    • 回答としてマーク jundivert 2019年6月24日 4:14
    2018年12月14日 5:11
  • 念のため IL を確認。

    .method public hidebysig specialname rtspecialname instance void .ctor () cil managed
    {
    	.maxstack 2
    	.locals init (
    		[0] int32 a,
    		[1] int32 b,
    		[2] bool CS$4$0000
    	)
    
    	IL_0000: ldarg.0
    	IL_0001: ldnull
    	IL_0002: stfld class [System]System.ComponentModel.IContainer CameraCapture.Form1::components
    	IL_0007: ldarg.0
    	IL_0008: call instance void [System.Windows.Forms]System.Windows.Forms.Form::.ctor()
    	IL_000d: nop       // なにもしない
    	IL_000e: nop       // なにもしない
    
    	// int a = 0;
    	IL_000f: ldc.i4.0  // 32ビット整数値 0 をスタックにロード
    	IL_0010: stloc.0   // スタックから 0 番目のローカル変数(int32 a)へ値を取り出す
    
    	// int a = 1;
    	IL_0011: ldc.i4.1  // 32ビット整数値 1 をスタックにロード
    	IL_0012: stloc.1   // スタックから 1 番目のローカル変数(int32 b)へ値を取り出す
    
    	// if (a >= b)
    	IL_0013: ldloc.0   // スタックに 0 番目のローカル変数をロード
    	IL_0014: ldloc.1   // スタックに 1 番目のローカル変数をロード
    	IL_0015: clt       // value0 < value1 なら「整数 1」、それ以外は「整数 0」を評価スタックにプッシュ
    
    	IL_0017: stloc.2   // スタックから 2 番目のローカル変数(bool CS$4$0000)へ値を取り出す
    	IL_0018: ldloc.2   // スタックに 2 番目のローカル変数をロード
    	IL_0019: brtrue.s IL_0027  // true, not null, or non-zero の場合は IL_0027 に分岐
    
    	IL_001b: nop       // なにもしない
    
    	// throw new Exception("No video capture devices found at that index!");
    	IL_001c: ldstr "No video capture devices found at that index!"
    	IL_0021: newobj instance void [mscorlib]System.Exception::.ctor(string)
    	IL_0026: throw
    
    	.try
    	{
    		IL_0027: nop       // なにもしない(if 条件を満たした場合のジャンプ先)
    		IL_0028: nop       // なにもしない
    		IL_0029: leave.s IL_0030  // コードの保護領域を終了し、IL_0030 へ制御を転送
    	} // end .try
    	catch [mscorlib]System.Object
    	{
    		IL_002b: pop       // 現在評価スタックの一番上にある値を削除
    		IL_002c: nop       // なにもしない
    		IL_002d: nop       // なにもしない
    		IL_002e: leave.s IL_0030  // コードの保護領域を終了し、IL_0030 へ制御を転送
    	} // end handler
    
    	IL_0030: nop         // なにもしない(try~catch 終了後のジャンプ先)
    	IL_0031: nop         // なにもしない
    	IL_0032: ret         // 現在のメソッドから戻る
    }
    2018年12月14日 5:20
  • 今度は VS 2017 でコンパイルした場合。

    .method public hidebysig specialname rtspecialname instance void .ctor () cil managed 
    {
    	.maxstack 2
    	.locals init (
    		[0] int32 a,
    		[1] int32 b,
    		[2] bool
    	)
    
    	IL_0000: ldarg.0
    	IL_0001: ldnull
    	IL_0002: stfld class [System]System.ComponentModel.IContainer CameraCapture.Form1::components
    	IL_0007: ldarg.0
    	IL_0008: call instance void [System.Windows.Forms]System.Windows.Forms.Form::.ctor()
    	IL_000d: nop
    	IL_000e: nop
    
    	// int a = 0;
    	IL_000f: ldc.i4.0  // 32ビット整数値 0 をスタックにロード
    	IL_0010: stloc.0   // スタックから 0 番目のローカル変数(int32 a)へ値を取り出す
    
    	// int a = 1;
    	IL_0011: ldc.i4.1  // 32ビット整数値 1 をスタックにロード
    	IL_0012: stloc.1   // スタックから 1 番目のローカル変数(int32 b)へ値を取り出す
    
    	// if (a >= b)
    	IL_0013: ldloc.0   // スタックに 0 番目のローカル変数をロード
    	IL_0014: ldloc.1   // スタックに 1 番目のローカル変数をロード
    	IL_0015: clt       // value0 < value1 なら「整数 1」、それ以外は「整数 0」を評価スタックにプッシュ
    
    	IL_0017: ldc.i4.0  // 32ビット整数値 0 をスタックにロード
    	IL_0018: ceq       // value0 = value1 なら「整数 1」、それ以外は「整数 0」を評価スタックにプッシュ
    
    	IL_001a: stloc.2   // スタックから 2 番目のローカル変数(bool)へ値を取り出す
    	IL_001b: ldloc.2   // スタックに 2 番目のローカル変数をロード
    	IL_001c: brfalse.s IL_002a // false, a null reference, or zero の場合は IL_002a に分岐
    
    	IL_001e: nop       // 何もしない
    	IL_001f: ldstr "No video capture devices found at that index!"
    	IL_0024: newobj instance void [mscorlib]System.Exception::.ctor(string)
    	IL_0029: throw
    
    	IL_002a: nop       // 何もしない(if 条件を満たさない場合のジャンプ先)
    	.try
    	{
    		IL_002b: nop       // 何もしない
    		IL_002c: nop       // 何もしない
    		IL_002d: leave.s IL_0034  // コードの保護領域を終了し、IL_0034 へ制御を転送
    	} // end .try
    	catch [mscorlib]System.Object
    	{
    		IL_002f: pop       // 現在評価スタックの一番上にある値を削除
    		IL_0030: nop       // 何もしない
    		IL_0031: nop       // 何もしない
    		IL_0032: leave.s IL_0034  // コードの保護領域を終了し、IL_0034 へ制御を転送
    	} // end handler
    
    	IL_0034: ret         // 現在のメソッドから戻る
    }
    • Windows 10 Pro Version 1803 (Build 17134.471)
    • Visual Studio Enterprise 2017 (Version 15.9.4)
    • .NET Framework 3.5 SP1

    ジャンプ命令が try の先頭か try の直前か、とか、if 文の条件判定の方法が異なるものの、意味としては同じような…。

    /* 2008 の場合のコンパイル結果イメージ */
    int a = 0;
    int b = 1;
    bool c = a < b;
    if(c) { goto IL_0027; }
    throw new Exception();
    try {
      IL_0027:
    }
    catch {
    }
    

    /* 2017 の場合のコンパイル結果イメージ */
    int a = 0;
    int b = 1;
    bool c = ((a < b) == false);
    if (!c) { goto IL_002a; }
    throw new Exception();
    IL_002a:
    try {
    }
    catch {
    }
    

    • 回答としてマーク jundivert 2019年6月24日 4:14
    2018年12月14日 5:55
  • ステップ実行の話だったんですね。
    前回の私の検証は「実際に例外がスローされるかどうか」で判断していましたので、起きないと書きました。
    デバッグのステップ実行であれば起きますね。(例外がスローされるわけではなく、実行位置が不思議な順序に見えてしまうという意味で)

    ただ、Visual Studio の話になってくることと、Visual Studio の不具合修正は最新版でしか修正されないので、基本的に VS2017 を使っていただくことになるかと思います。

    • 回答としてマーク jundivert 2019年6月24日 4:15
    2018年12月14日 14:10
    モデレータ

すべての返信

  • いろいろと削った結果、以下のコードでも奇妙な結果になりました。

    int a = 0;
    int b = 1;
    if (b<= a) {
    	// Pass
    	throw new Exception("No video capture devices found at that index!");
    }
    

    2018年12月13日 1:48
  • 別のマシンでも再現しますか? さすがに当該マシン固有の問題ではないかと思われるのですが…。
    2018年12月13日 1:56
  • 同じPC上ではありますが、同じコードでVSのバージョンをあげてみていったところ、

    VS2008: NG

    VS2013: NG

    VS2015: OK

    VS2017: OK

    という結果になりました。安心して使えるC#はVS2015以降ということらしいです。

    2018年12月13日 2:14
  • C# / .NET FrameworkはCIL; 中間共通言語を採用しています。実際の演算を行うコード生成はOSに含まれている.NET Framework Runtimeです。さらに、Visual Studio2013以前はOSに含まれている.NET Framework Compilerを呼び出しているだけです。

    以上を踏まえて被疑は

    • 世界中の.NET Framework Compilerが設計から壊れている
    • 質問者さんのPCの.NET Framework Compilerがファイル破損等で壊れている
    • 世界中の.NET Framework Runtimeが設計から壊れている
    • 質問者さんのPCの.NET Framework Runtimeがファイル破損等で壊れている

    いずれかと思われます。とりあえず、私の手元のPCでは再現しませんので、設計から壊れている可能性は低く、質問者さんのPCに原因があると考えています。

    2018年12月13日 3:23
  • 中間言語の件は一応理解しているつもりです。前後のコードを整理しシンプルにして実験を繰り返しておりました。

    Visual Studio 2013 + Net3.5 の組み合わせで3台のPCで実験。うち1台は新規にVS2013をインストールしたものです。3台とも同じ現象が発生しました。さらに4台目としてプロジェクトをVS2017に読込み、リビルドせずに実行したところ現象再現、しかしながらリビルド後は問題は解決しました。この場合もNetは3.5のままです。

    以上を踏まえますと、どうやら世界中で私の所有する数台のPCのみNET Framework Compiler or Runtimeが壊れているということになりそうです。

    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Text;
    using System.Windows.Forms;
    
    namespace CameraCapture {
    	public partial class Form1 : Form {
    		public Form1() {
    //			InitializeComponent();
    			int a = 0;
    			int b = 1;
    			if (a >= b) {
    				// Pass
    				throw new Exception("No video capture devices found at that index!");
    			}
    			try {
    			}
    			catch {
    			}
    		}
    	}
    }
    

    2018年12月13日 16:15
  • 新規に Windows フォームアプリケーションを .NET 3.5 で作り、そのコードを書いた場合でも再現するのですか?
    プロジェクトのプロパティは特に変更せず。
    (現状、実験されているコード群が元のプロジェクトをベースにされている可能性を疑ったため)

    また、コンパイル・実行されている環境に関する詳細も明かしてみてください。
    Windows のバージョンや常駐しているソフト、ウィルス対策ソフトなどの介入してきそうなものなど。


    手元の Win10 1803 + VS2013 で .NET 3.5 をターゲットにした Windows フォームアプリケーションを新規作成し、上記のように Form1 を変更し、ビルド、デバッグ開始 or デバッグなしで開始などではおかしなことになりませんね。(x86/x64、Debug/Release と切り換えても再現しない)
    2018年12月13日 21:18
    モデレータ
  • 以上を踏まえますと、どうやら世界中で私の所有する数台のPCのみNET Framework Compiler or Runtimeが壊れているということになりそうです。

    不幸にもそのようですね。他の誰も困らない現象ですし、質問者さんにしか調査できないことなので、第三者の立場からは情報提供しかできません。

    .NET Framework Compilerはいくつも存在します。

    • "C:\Windows\Microsoft.NET\Framework\v2.0.50727\csc.exe"
      Windowsに付属。Visual Studio 2005が呼び出す
    • "C:\Windows\Microsoft.NET\Framework\v3.5\csc.exe"
      Windowsに付属。Visual Studio 2008が呼び出す
    • "C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe"
      Windowsに付属。Visual Studio 2010~Visual Studio 2013が呼び出す
    • Visual Studioインストール先にあるcsc.exe
      Visual Studio 2015以降に付属。当該バージョンが呼び出す

    .NET Framework Runtimeは既に述べたようにWindowsに付属しています。

    以上を踏まえて、どのマシンのどのVisual Studioでビルドを行ったバイナリが失敗するか。どのマシンで実行したら失敗するか、パターンを割り出し、被疑を特定してみてください。

    今までの投稿から、Visual Studio 2015以降に付属しているcsc.exeでは問題が発生していないようで、裏返すとWindows付属のcsc.exe辺りが怪しそうです。その場合、ウィルス感染の可能性もあるかもしれませんね。

    2018年12月13日 21:54
  • Azulean様、実験いただきありがとうございます。

    1台のPCでは新規プロジェクトで実験しました。

    1. Visual Studio 2013をダウンロードしてインストール
    2. 新規プロジェクト作成
    3. NET3.5に設定
    4. using System.Threading.Tasks; をコメントアウト
    5. 問題のソースはコピペせずに手入力
    6. デバッガでステップ実行

    ちなみにif文内をthrow以外のコードにしたり、try/catchを取ったりしますと症状は出ません。

    Windows 10 1803、ウィルス対策ソフトはESET INTERNET SECURITYを導入しております。


    • 編集済み jundivert 2018年12月14日 1:27
    2018年12月14日 0:46
  • 状況だけ確認したので。

    if (a >= b) {

    にブレークポイントを置いて、そこまで実行し、F10でステップ実行すると、カレント実行行が「throw」の所に行く(ように見える)という現象なのかな ?

    表示上、throwが実行されそうですが、実際に実行するとthrowは実行されません。

    ifのブレークポイントを外して、throwにブレークポイントを置いて実行しても、ブレークされません。デバッグ情報か何かのバグですかね ?


    Sorry, I am not good at English.

    • 回答としてマーク jundivert 2019年6月24日 4:14
    2018年12月14日 3:05
  • 当方環境でも再現しました。なお、x86 ビルドに変更した場合は問題ありませんでした(AnyCPU / x64 ビルドでのみ発生)

    • Windows 7 Pro (Build 7601: Service Pack 1) 64bit
    • Visual Studio Team System 2008 (Version 9.0.30729.4108 QFE)
    • .NET Framework 3.5 SP1

    • 回答としてマーク jundivert 2019年6月24日 4:14
    2018年12月14日 5:11
  • 念のため IL を確認。

    .method public hidebysig specialname rtspecialname instance void .ctor () cil managed
    {
    	.maxstack 2
    	.locals init (
    		[0] int32 a,
    		[1] int32 b,
    		[2] bool CS$4$0000
    	)
    
    	IL_0000: ldarg.0
    	IL_0001: ldnull
    	IL_0002: stfld class [System]System.ComponentModel.IContainer CameraCapture.Form1::components
    	IL_0007: ldarg.0
    	IL_0008: call instance void [System.Windows.Forms]System.Windows.Forms.Form::.ctor()
    	IL_000d: nop       // なにもしない
    	IL_000e: nop       // なにもしない
    
    	// int a = 0;
    	IL_000f: ldc.i4.0  // 32ビット整数値 0 をスタックにロード
    	IL_0010: stloc.0   // スタックから 0 番目のローカル変数(int32 a)へ値を取り出す
    
    	// int a = 1;
    	IL_0011: ldc.i4.1  // 32ビット整数値 1 をスタックにロード
    	IL_0012: stloc.1   // スタックから 1 番目のローカル変数(int32 b)へ値を取り出す
    
    	// if (a >= b)
    	IL_0013: ldloc.0   // スタックに 0 番目のローカル変数をロード
    	IL_0014: ldloc.1   // スタックに 1 番目のローカル変数をロード
    	IL_0015: clt       // value0 < value1 なら「整数 1」、それ以外は「整数 0」を評価スタックにプッシュ
    
    	IL_0017: stloc.2   // スタックから 2 番目のローカル変数(bool CS$4$0000)へ値を取り出す
    	IL_0018: ldloc.2   // スタックに 2 番目のローカル変数をロード
    	IL_0019: brtrue.s IL_0027  // true, not null, or non-zero の場合は IL_0027 に分岐
    
    	IL_001b: nop       // なにもしない
    
    	// throw new Exception("No video capture devices found at that index!");
    	IL_001c: ldstr "No video capture devices found at that index!"
    	IL_0021: newobj instance void [mscorlib]System.Exception::.ctor(string)
    	IL_0026: throw
    
    	.try
    	{
    		IL_0027: nop       // なにもしない(if 条件を満たした場合のジャンプ先)
    		IL_0028: nop       // なにもしない
    		IL_0029: leave.s IL_0030  // コードの保護領域を終了し、IL_0030 へ制御を転送
    	} // end .try
    	catch [mscorlib]System.Object
    	{
    		IL_002b: pop       // 現在評価スタックの一番上にある値を削除
    		IL_002c: nop       // なにもしない
    		IL_002d: nop       // なにもしない
    		IL_002e: leave.s IL_0030  // コードの保護領域を終了し、IL_0030 へ制御を転送
    	} // end handler
    
    	IL_0030: nop         // なにもしない(try~catch 終了後のジャンプ先)
    	IL_0031: nop         // なにもしない
    	IL_0032: ret         // 現在のメソッドから戻る
    }
    2018年12月14日 5:20
  • 今度は VS 2017 でコンパイルした場合。

    .method public hidebysig specialname rtspecialname instance void .ctor () cil managed 
    {
    	.maxstack 2
    	.locals init (
    		[0] int32 a,
    		[1] int32 b,
    		[2] bool
    	)
    
    	IL_0000: ldarg.0
    	IL_0001: ldnull
    	IL_0002: stfld class [System]System.ComponentModel.IContainer CameraCapture.Form1::components
    	IL_0007: ldarg.0
    	IL_0008: call instance void [System.Windows.Forms]System.Windows.Forms.Form::.ctor()
    	IL_000d: nop
    	IL_000e: nop
    
    	// int a = 0;
    	IL_000f: ldc.i4.0  // 32ビット整数値 0 をスタックにロード
    	IL_0010: stloc.0   // スタックから 0 番目のローカル変数(int32 a)へ値を取り出す
    
    	// int a = 1;
    	IL_0011: ldc.i4.1  // 32ビット整数値 1 をスタックにロード
    	IL_0012: stloc.1   // スタックから 1 番目のローカル変数(int32 b)へ値を取り出す
    
    	// if (a >= b)
    	IL_0013: ldloc.0   // スタックに 0 番目のローカル変数をロード
    	IL_0014: ldloc.1   // スタックに 1 番目のローカル変数をロード
    	IL_0015: clt       // value0 < value1 なら「整数 1」、それ以外は「整数 0」を評価スタックにプッシュ
    
    	IL_0017: ldc.i4.0  // 32ビット整数値 0 をスタックにロード
    	IL_0018: ceq       // value0 = value1 なら「整数 1」、それ以外は「整数 0」を評価スタックにプッシュ
    
    	IL_001a: stloc.2   // スタックから 2 番目のローカル変数(bool)へ値を取り出す
    	IL_001b: ldloc.2   // スタックに 2 番目のローカル変数をロード
    	IL_001c: brfalse.s IL_002a // false, a null reference, or zero の場合は IL_002a に分岐
    
    	IL_001e: nop       // 何もしない
    	IL_001f: ldstr "No video capture devices found at that index!"
    	IL_0024: newobj instance void [mscorlib]System.Exception::.ctor(string)
    	IL_0029: throw
    
    	IL_002a: nop       // 何もしない(if 条件を満たさない場合のジャンプ先)
    	.try
    	{
    		IL_002b: nop       // 何もしない
    		IL_002c: nop       // 何もしない
    		IL_002d: leave.s IL_0034  // コードの保護領域を終了し、IL_0034 へ制御を転送
    	} // end .try
    	catch [mscorlib]System.Object
    	{
    		IL_002f: pop       // 現在評価スタックの一番上にある値を削除
    		IL_0030: nop       // 何もしない
    		IL_0031: nop       // 何もしない
    		IL_0032: leave.s IL_0034  // コードの保護領域を終了し、IL_0034 へ制御を転送
    	} // end handler
    
    	IL_0034: ret         // 現在のメソッドから戻る
    }
    • Windows 10 Pro Version 1803 (Build 17134.471)
    • Visual Studio Enterprise 2017 (Version 15.9.4)
    • .NET Framework 3.5 SP1

    ジャンプ命令が try の先頭か try の直前か、とか、if 文の条件判定の方法が異なるものの、意味としては同じような…。

    /* 2008 の場合のコンパイル結果イメージ */
    int a = 0;
    int b = 1;
    bool c = a < b;
    if(c) { goto IL_0027; }
    throw new Exception();
    try {
      IL_0027:
    }
    catch {
    }
    

    /* 2017 の場合のコンパイル結果イメージ */
    int a = 0;
    int b = 1;
    bool c = ((a < b) == false);
    if (!c) { goto IL_002a; }
    throw new Exception();
    IL_002a:
    try {
    }
    catch {
    }
    

    • 回答としてマーク jundivert 2019年6月24日 4:14
    2018年12月14日 5:55
  • FC-Shiro様
    魔界の仮面弁士様

    追試していただきありがとうございます!私のサイトのみの現象であると断定され若干凹んでおりましたので。

    >FC-Shiro様

    実際にはthrowしないとのご指摘ですが、試しに以下のコードをステップ実行したところ、デバッガはC=1行を飛ばしてthrow行に移動しました。デバッガの問題かもしれません。実害はなさそうですがステップ実行して検証する時に混乱しそうです。

    	public partial class Form1 : Form {
    		public Form1() {
    			InitializeComponent();
    			int a = 0;
    			int b = 1;
    			int c = 0;
    			if (a >= b) {
    				// Pass
    				c = 1;
    				throw new Exception("No video capture devices found at that index!");
    			}
    			try {
    			}
    			catch {
    			}
    		}
    		// c == 0
    	}
    

    2018年12月14日 7:10
  • ステップ実行の話だったんですね。
    前回の私の検証は「実際に例外がスローされるかどうか」で判断していましたので、起きないと書きました。
    デバッグのステップ実行であれば起きますね。(例外がスローされるわけではなく、実行位置が不思議な順序に見えてしまうという意味で)

    ただ、Visual Studio の話になってくることと、Visual Studio の不具合修正は最新版でしか修正されないので、基本的に VS2017 を使っていただくことになるかと思います。

    • 回答としてマーク jundivert 2019年6月24日 4:15
    2018年12月14日 14:10
    モデレータ
  • 皆さんのご協力のおかげで、今回の不思議な挙動はVisual Studioのデバッガの不具合であろうことがはっきりしました。再現性があり、私の環境の問題ではないことが判っただけでも収穫です。これ以上深く調査しても不具合修正はなされないでしょうから、新しいバージョンのVisual Studioを使用するか、仕事の都合上古いバージョンを使わざるを得ない場合は、ステップ実行に関しては疑いつつ慎重に利用することとし、今回の質問はクローズとさせていただきたいと思います。ありがとうございました。
    2018年12月14日 15:52
  • 私のリプライで混乱させてしまい申し訳ありませんでした。

    1点確認なのですが、最初の質問文に「最終比較行のみが真になり、例外になってしまいます。」と記されていますが、これは「カーソルがthrow文に移動する(実際にはthrowされず、真にもなっていない)」というだけの意味だったんですね? さすがに読み取れませんでした。

    C#言語に限らず、高級言語ではソースコード行がCPU命令と1:1対応していませんし、{}やコメントは対応するCPU命令が存在しないこともあります。そのため、ソースコード上のカーソル位置は厳密には表現できません。forやforeachループなどでもその動きは顕著です。今回の現象もその一環とお考え下さい。

    # F#言語だとカーソル位置を明確にするためにCILのNOPを埋め込んで、そのNOP命令とソースコード行の対応を追跡していたりもしますが、それはそれでパフォーマンスに問題がありますし…。

    2018年12月15日 0:26