Visual Studio 2015 および Visual C++ 2017 のリンク時のコード生成における最適化の不具合について

こんにちは、Visual Studio サポート チームです。

今回は、Visual C++ 2015 および Visual C++ 2017 で確認されている、C++ プロジェクトのリンク時のコード生成における最適化の不具合についてご案内します。

なお、この事象については報告が非常に少なく現在も修正に向けて調査中ですが、進展があり次第この記事を更新する予定です。

 

現象
以下の条件を満たす場合に、仮想関数呼び出しが正常に行われず基底クラスのメンバー関数が実行される場合があります。

  • 速度優先の最適化 (/O2 オプションもしくは /Ox オプション) を指定している。
  • リンク時のコード生成 (/LTCG オプション) を指定している。
  • プログラム全体の最適化 (/GL オプション) を指定している。
  • 仮想関数の呼び出しと仮想関数の実装が異なるバイナリ間で行われている。

 

原因
本現象は弊社製品の不具合に起因して発生しています。

Visual C++ コンパイラーおよびリンカーは、呼び出される仮想関数がコード生成時に静的に決定でき、かつ最適化によるパフォーマンスの向上が見込めると判断した場合、devirtualization と呼ばれる仮想関数呼び出しを直接呼び出しに置き換える最適化を行います。

リンク時のコード生成が指定されている場合、仮想関数の呼び出しと仮想関数の実装が異なるバイナリ間で行われている場合も devirtualization が試みられますが、仮想関数ではなく基底クラスの関数が呼び出されるコードが生成される場合があります。

 

回避策

以下のいずれかの方法でリンク時のコード生成における devirtualization の最適化を無効化することで、この問題を回避できます。

  • コンパイラー オプションで /d2notypeopt を指定する
  • リンカー オプションで /d2:-notypeopt オプションを指定する

 

留意事項

上記の回避策では最適化が一部行われないことにより、アプリケーションの実装によってはパフォーマンスが低下する可能性があります。また、/sdl オプションで出力される警告の一部は、上記の回避策を適用した場合コンパイラーやリンカーによって摘出されなくなる可能性があります。

そのため、現象で示した問題に該当し、アプリケーションのパフォーマンスへの影響を許容できる場合のみ、回避策の適用をご検討ください。

 

ステータス

マイクロソフトはこの問題を Visual C++ 2015 と Visual C++ 2017 における不具合と認識しています。

この問題は、Visual Studio 2017 version 15.8 以降での修正を予定しています。

修正がリリースされましたら改めてこの記事でご案内します。