Why does Environment.Exit() not terminate the program any more? Ask Question

Why does Environment.Exit() not terminate the program any more? Ask Question

This is something I discovered just a few days ago, I got confirmation that it isn't just limited to my machine from this question.

The easiest way to repro it is by starting a Windows Forms application, add a button and write this code:

    private void button1_Click(object sender, EventArgs e) {
        MessageBox.Show("yada");
        Environment.Exit(1);         // Kaboom!
    }

The program fails after the Exit() statement executes. On Windows Forms you get "Error creating window handle".

Enabling unmanaged debugging makes it somewhat clear what's going on. The COM modal loop is executing and allows a WM_PAINT message to be delivered. That's fatal on a disposed form.

The only facts I've gathered so far are:

  • It isn't just limited to running with the debugger. This also fails without one. Rather poorly as well, the WER crash dialog shows up twice.
  • It doesn't have anything to do with the bitness of the process. The wow64 layer is pretty notorious, but an AnyCPU build crashes the same way.
  • It doesn't have anything to do with the .NET version, 4.5 and 3.5 crash the same way.
  • The exit code doesn't matter.
  • Calling Thread.Sleep() before calling Exit() doesn't fix it.
  • This happens on the 64-bit version of Windows 8, and Windows 7 does not seem to be affected the same way.
  • This should be relatively new behavior, I haven't seen this before. I see no relevant updates delivered through Windows Update, albeit that the update history isn't accurate on my machine any more.
  • This is grossly breaking behavior. You would write code like this in an event handler for AppDomain.UnhandledException, and it crashes the same way.

このクラッシュを回避するために何ができるかに特に興味があります。特に、AppDomain.UnhandledException のシナリオは困惑します。.NET プログラムを終了する方法は多くありません。Application.Exit() または Form.Close() の呼び出しは、UnhandledException のイベント ハンドラーでは無効であるため、回避策にはならないことに注意してください。


更新: Mehrdad は、ファイナライザー スレッドが問題の一部である可能性があると指摘しました。私もこの現象が発生していると思います。また、CLR がファイナライザー スレッドに実行を完了するための 2 秒のタイムアウトを与えるという証拠もいくつか見受けられます。

ファイナライザはNativeWindow.ForceExitMessageLoop()内にあります。そこには、32ビットモードでマシンコードを見ると、コード位置のオフセット0x3cにほぼ対応するIsWindow() Win32関数があります。IsWindow()はデッドロックしているようです。内部のスタックトレースはうまく取得できませんが、デバッガーはP/呼び出し呼び出しが返されました。これは説明するのが難しいです。もっと良いスタック トレースが取得できれば、ぜひ見せていただきたいです。私のは:

System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.ForceExitMessageLoop() + 0x3c bytes
System.Windows.Forms.dll!System.Windows.Forms.NativeWindow.Finalize() + 0x16 bytes
[Native to Managed Transition]
kernel32.dll!@BaseThreadInitThunk@12()  + 0xe bytes
ntdll.dll!___RtlUserThreadStart@8()  + 0x27 bytes
ntdll.dll!__RtlUserThreadStart@8()  + 0x1b bytes

ForceExitMessageLoop 呼び出しの上には何もないので、アンマネージ デバッガーが有効になっています。

ベストアンサー1

この問題について Microsoft に問い合わせたところ、どうやら解決したようです。少なくとも、私はそう思いたいです :)。Microsoft から解決の確認は得られませんでしたが、Windows グループに直接連絡を取るのは難しく、仲介者を使わなければなりませんでした。

Windows Update を通じて配信された更新により、問題は解決しました。クラッシュ前の顕著な 2 秒の遅延はなくなりました。これは、IsWindow() デッドロックが解決されたことを強く示唆しています。また、プログラムはクリーンかつ確実にシャットダウンします。更新により、Windows Defender、wdboot.sys、wdfilter.sys、tcpip.sys、rpcrt4.dll、uxtheme.dll、crypt32.dll、wintrust.dll のパッチがインストールされました。

Uxtheme.dll は異端です。これは Visual Styles テーマ API を実装し、このテスト プログラムで使用されます。確信はありませんが、これが問題の原因であると私は考えています。C:\WINDOWS\system32 のコピーのバージョン番号は 6.2.9200.16660 で、私のマシンでは 2013 年 8 月 14 日に作成されました。

事件は解決しました。

おすすめ記事