.NET Framework 4.6 の RyuJIT の不具合がいくつか修正されてリリースされている

先日、「.NET Framework 4.6環境でx64アプリケーションが正しく動作しないことがある」として記事にした RyuJIT ですが、2015/08/12 公開のセキュリティ更新プログラムとして一部の不具合が修正されたそうです。

 

マイクロソフト セキュリティ情報 MS15-092 – 重要
.NET Framework の脆弱性により、特権が昇格される (3086251)
https://technet.microsoft.com/library/security/ms15-092.aspx

MSDN Blog に挙がっていた不具合 は直されたみたいですが、まだ .NET 4.6 環境で実行すると動きが変わるような不具合(GitHub に登録されている不具合一例)はリリースされていません。

アプリケーションによっては引き続き正しく動作しないケースがあるということは認識しておいた方が良いでしょう。(開発者の方、社内の IT 管理の方など)

.NET Framework 4.6環境でx64アプリケーションが正しく動作しないことがある

概要

.NET Framework 4.6を導入した環境、あるいは.NET Framework 4.6が標準でインストールされているWindows 10において、.NET Framework 4 ~ 4.5.2までを対象としたx64アプリケーション、.NET Framework 4.6を対象としたx64アプリケーションは期待通りに動作しないことがあります。

原因

.NET Framework 4.6を導入すると.NET Framework 4系のx64ビルドしたアプリケーションは新しいRyuJITが使用されるようになります。
しかし、このRyuJITにはネイティブコード生成の不具合、最適化の不具合がいくつか存在しており、アプリケーションが強制終了する、機能が正しく動かないといったアプリケーションの不具合を生じさせるリスクがあります。

この現象は.NET Framework 4 ~ 4.5.2までを対象にリリースした既存アプリケーションであっても、実行環境に.NET Framework 4.6を導入するか、Windows 10に既存アプリケーションをインストールすることで不具合が起きる可能性がある点、他人事とは言えない事情があります。

(Windows 10はWindows 7/8.1から無償アップグレードできるの気づかぬうちに動かなくなるとか、Visual Studio 2015インストールで勝手に入ってしまうとか)

事例情報

以下のMSDNの.NET BlogでRyuJIT最適化に関する不具合について言及されています。

RyuJIT Bug Advisory in the .NET Framework 4.6

このほか、最適化を抑制してもunsafeコードで正しくないメモリ参照を引き起こす不具合が存在しているようです。(業務的に知り得たことなので細かいことは割愛します)

対象外

以下のアプリケーションはこの問題にあたりません。

  • .NET Framework 3.5 SP1 (3.5.1) およびそれ以前を対象とするアプリケーション
  • x86指定でビルドしているアプリケーション
  • .NET Frameworkを使用していないアプリケーション

回避策

運用環境が特定少数、制御可能な範囲であれば.NET Framework 4.6をインストールしないことです。

ただ、不特定多数の市場に向けたアプリケーションの場合はそういった制御ができませんので、RyuJITを無効化することで回避することを考えます。
詳しいことはgithubのページを参照していただきたいですが、おおよそ以下の選択肢があることになります。

  1. app.configに書く。(〇〇.exeであれば、〇〇.exe.configができることになる)
    runtimeセクションに<useLegacyJit enabled="1" />を書き加える。
  2. 環境変数COMPLUS_useLegacyJitに1を設定する
  3. レジストリ(SOFTWARE\Microsoft\.NETFramework)にuseLegacyJitというDWORDの値を作り、1と書き込む。
    HKEY_LOCAL_MACHINEか、HKEY_CURRENT_USERのいずれかでよい。

これから新規に配布する、あるいはアップデートをリリースする予定のアプリケーションであれば、app.config路線が良いでしょう。これであれば、他のアプリケーションに影響を与えません。
次点として、アップデート予定がなく、エンドユーザーのフォローが必要となる場合は、HKEY_CURRENT_USERのレジストリに書くようなregファイルを作った方がユーザーサポートという観点ではやりやすいかもしれません。

回避策の有効性を確認する方法

デバッグ実行していただいて、読み込まれたDLLの一覧をVisual Studioやプロセスエクスプローラーなどで確認してください。
通常はclrjit.dllが読み込まれますが、上記の回避策を打つとcompatjit.dllが読み込まれるようになります。

.NET 2.0-3.5として作られたアプリを.NET 4ランタイムで動かせるか?

.NET 4からCLRが新しくなったことで、基本的に.NET 3.5で作られたアプリのプラグイン、アドインを.NET 4で作ることはできません。
これを回避するためにはいくつかの方法が考えられます。

  1. 対象アプリを.NET 4で動かす。
  2. .NET 3.5でプラグイン、アドインを作り、.NET 4のアプリと通信する。
  3. .NET 4で作ろうとしていた部分をネイティブ、COMで作って利用する。

まっとうな方法は2や3になるかと思いますが、.NET 4で無理矢理動かす方法を少し見てみましょう。

対象のアプリがhogehoge.exeだとすると、hogehoge.exe.configに以下のような記述を作ります。

<configuration>
   <startup useLegacyV2RuntimeActivationPolicy="true">
      <supportedRuntime version="v4.0"/>
   </startup>
</configuration>

参考URL:http://msdn.microsoft.com/ja-jp/library/jj152935(v=vs.110).aspx

これでたいていのアプリは.NET 4で動きます。
ただし、勝手に.NET 4で動かしているので無保証となる点にご留意いただき、利用者の自己責任で使うことを前提としてください。

なお、プラグイン・アドイン方式でセキュリティ問題をケアしている場合、CAS周りでNotSupportedExceptionが発生する可能性があります。
loadFromRemoteSourcesを使って脆弱にして動かすか、素直に2や3のアプローチを採るか、よく考えましょう。

WebClient トラブル調査:ヘッダーの差異を調べる

わんくま同盟さんの質問掲示板の「C++.NetでWebClientのOpenReadについて」からのネタです。

今回の事例では、IE からは閲覧できて、WebClient では 503 エラーとなるものでした。
そこで、かんたんにコードを書いて実験することにします。

var wc = new WebClient();
using (var stream = wc.OpenRead(url))
{
}

※url はリクエストを投げる URL を示す文字列変数。

実際に質問に上がっていた URL で試すと、確かに 503 エラーを内包する Exception がスローされます。

ここで、Fiddler を使って差分を見ることにします。

まずは、上記のサンプルコードで試したときの通信内容です。

左側でセッションを選択すると右側に詳細が表示されますので上のビューの Headers を確認します。

非常にシンプルなリクエストになっていることがわかります。

image

次に IE で同じ URL にアクセスしてみて、多数のセッションが表示される中で、同じ URL に対するリクエストを選択して、同じように上のビューの Headers を確認します。

(掲載画像は関係ない部分をモザイクでつぶしています)

image

Accept, Accept-Encoding, Accept-Language, User-Agent などが増えていることがわかります。

1 つのヘッダーを追加するだけで足りるかもしれませんし、複数のヘッダーを追加しないとダメなケースもあるかもしれません。組み合わせを考えて試してみましょう。

今回の事例では User-Agent を何か指定すれば OK だったみたいですので、1 個ずつ試していけばそのうち解決しますね。

なお、この方法でわかるのは、その時点の相手のページがどのようなヘッダー、値を条件にしているかだけであり、将来的に変更される恐れがあります。これは相手の方針やメンテナンス・リニューアルなどの事情によるので不確か(リスク)です。

もしも、相手側がブラウザー以外の閲覧を好ましく思っていないのであれば、無理にやらない方がいいかと思います。

MS12-025によって .NET Windows Forms で印刷設定(プリンター設定)が反映されないことがあるらしい

Update 2012/06/04: KB から Hotfix のリンクが出ています。それを適用することでこの問題を修正することができるようです。実行環境への適用が必要です。

4/11 に公開された MS12-025 を適用すると、.NET の Windows フォームアプリケーションで印刷設定(プリンターの設定)が反映されないことがあるようです。用紙の向きとか、2in1とか、縮小印刷などはうまくいかないようです。(情報源)
もし、.NET(VB.NET/C# 問わず) の Windows フォームアプリケーションで印刷設定が効かないといった不具合に遭遇された、問い合わせを受けた場合は、この更新プログラムによる影響を疑っておきましょう。

なお、http://support.microsoft.com/kb/2671605/ja には以下の記載が追加されています。

マイクロソフトでは、Windows フォーム アプリケーションからの印刷に問題あることを認識しています。これらのセキュリティ更新プログラムをインストールした後で、特定の Windows フォーム アプリケーションで印刷できないか印刷時に指定したプリンターの設定が優先されないことがあります。.NET Framework Windows フォーム アプリケーションから印刷する機能を使用しないシステムには影響はありません。この問題は現在調査中です。

また、GrapeCity さんも一部コンポーネントで同様の問題が生じているとして技術情報を公開されています。

http://www.grapecity.com/tools/support/technical/knowledge_detail.asp?id=32272

本現象の影響を受ける弊社製品は下記の通りです。
・ActiveReports for .NET
・ComponentOne Studio
・SPREAD for Windows Forms
・FlexGrid for Windows Forms
・MultiRow for Windows Forms
・El Tabelle Sheet for Windows Forms
・TrueChart for Windows Forms
・LEADTOOLS
※旧バージョンを含みます。

この一連の問題が影響しているかどうかは、MS12-025 を一度アンインストールすればわかる。ただ、エンドユーザーにセキュリティ更新プログラムを削除してくれとはいえないので、ソフトウェアベンダーとしては対応に困ります。Microsoft は大きな用紙設定で XPS/PDF に印刷してから、別のソフトで印刷し直してくれとのことですけどね…。早いこと修正されてほしいものです。

※この情報は 4/22 投稿時点のものです。将来的には更新プログラムがアップデートされて、問題が発生しなくなると予想されます。