none
Windows10 32bitで C#からC++ のDLLを利用の場合、トレースでのDebugが出来ない (少数が正しくセットされない) RRS feed

  • 質問

  • Visual Studio2013 です

    Debugで、 F11のステップインやF10のステップオーバーで、止めながら動かすと、
    float や double の変数に値が正しくセットされません。

    void Test(void)
    {
    	int max, flg;
    	double x, y;
    	max = 255;
    	x = 319.5;
    	y = 239.5;
    	flg = 2;
    }
    
    例えば、例題の x = 319.5; の所にブレークポイントを設定した場合、
    F5の続行では問題ありませんが、
    F10のステップオーバーで先へ進もうとすると、x には0しかセットされません。

    Windows10 32bitの2台のコンピュータで同じ現象になります。
    Windows10 64bitや Windows7 32bitでは問題ありません。
    C++ から C++ のDLL を呼び出す場合も問題ありません。

    2016年11月2日 6:41

回答

  • 現象としては浮動小数を変数にセットする箇所のアセンブラを見ると

    6B061735  movsd       xmm0,mmword ptr [__real@4073f80000000000 (6B066848h)]
    の部分でXMM0レジスタに浮動小数が入るはずなのにゼロが入るということが起きています。


    とりあえずの回避方法

    C#側を.Net Frameworkを3.5以前にしてデバッグ(.Net4以降のアセンブリを使わない)

    もしくは、

    C/C++のコード生成オプションで「拡張命令セットを有効にする」を拡張命令なしかSSEまでにする。
    (/archオプションがSSE2,AVX,AVX2だと発症する)

    とmovsd命令を使わなくなるので現象が起きなくなりました。

    他のSSE2命令を生成させたコードでもおかしな挙動をしているようなので、ネイティブと.net4以降のマネージの混合デバッガーでSSE2以降の命令の処理が無効にされてる?

    64bitCPUはSSE2は必ず搭載されているけど、32bitCPUは乗っていない可能性があるから誤判定してしまっているのかも。


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2016年11月24日 10:49

すべての返信

  • C++ DLLがリリース構成でビルドされた場合、最適化により不要な処理は省略されることがあります。
    2016年11月2日 8:29
  • C++ DLL も C#のWindows フォームアプリケーションも Debug でビルドしています。

    2016年11月4日 0:27
  • 簡単なプログラムでも、Windows10 32bitの2台のコンピュータで起こっています。
    どなたか、そういうことは起こっていないとか、起こっているとかお知らせ頂けませんか。
    2016年11月15日 8:11
  • Visual C#のプロジェクト設定で、[デバッグ]-[ネイティブ コード デバッグを有効にする]にチェックを入れていますか?
    2016年11月17日 16:05
  • C++ ネイティブ部分にブレークを貼れるということは、混合デバッグ(C# プロジェクトのデバッグプロパティにおけるネイティブデバッグも同等)、ネイティブデバッグのいずれかだと思います。
    「0 になる」のはウォッチだけの話か、実際に 0 なのか、どちらなのでしょうか?

    ウォッチ機能(カーソルを合わせたときのツールチップなども含む)の不具合とみるべきなのか、ステップ実行における不具合とみるべきなのかを気にしての発言です。

    // 私自身は最近、64bit Windows ばかりなので、32bit 限定と言われると…。
    // 64bit Windows 10 の 32bit プロセスに対する VS2013 は特に問題を見受けられず。
    // .NET 側で CallConversion をミスっている…というわけではないですよね?

    2016年11月17日 22:23
    モデレータ
  • [デバッグ]-[ネイティブ コード デバッグを有効にする]にチェックは入っています。

    >「0 になる」のはウォッチだけの話か、実際に 0 なのか、どちらなのでしょうか?
    実際に 0 になっています。
    本番のプログラムは関数の引数で値を得ていて、その値でグラフィックを描いていますが、
    トレースすると 0が返ってきて、グラフィックが正しく描けなくなります。

    Windows 10 64bit の OSで、32bit のプロジェクトを動かした場合は正常に動いています。

    // .NET 側で CallConversion をミスっている…というわけではないですよね?
    C#から呼ばれる C++の関数は intの戻り値だけで何も引数が無い関数で、
    間違いは無いと思います。
    今回の Windows10 32bit の2台のコンピューで初めて起こっている現象です。

    2016年11月21日 9:16
  • 新規プロジェクトを作って再現性がある状態であれば、Microsoft のサポートに問い合わせてもらった方が良さそうです。
    • 回答の候補に設定 星 睦美 2016年11月24日 2:00
    2016年11月21日 21:46
    モデレータ
  • 質問文には「F5の続行では問題ありません」と書かれていましたが、今回「トレースすると 0が返ってきて、グラフィックが正しく描けなくなります」とのことで、どう違うのでしょうか?

    「トレースすると0が返ってきて」からよくわかりません。問題を切り分けてください。C++に問題があるのか、C++からC#への戻り値・境界部分に問題があるのか、どちらでしょうか? C++部分については_RPTF系マクロを使用することで「出力ウィンドウ」にメッセージを出力できます。もしくは_ASSERTEマクロなどで変数の値を確認してください。どちらもリリースビルドでは実行されないためコードを残しておいても問題になりません。境界部分についてはMDA; マネージデバッグアシスタントで検出できる場合があります。

    2016年11月21日 22:26
  • > 新規プロジェクトを作って再現性がある状態であれば、
    > Microsoft のサポートに問い合わせてもらった方が良さそうです。
    新規プロジェクトで簡単なプログラムを作りました。
    やはり、同様な問題が起こります

    Microsoft のサポートに問い合わせたら、有償なのですね。
    普段は、Windows10の64bitで開発していますので、私の方ではこれ以上追及しません。


    C# のプログラム

            [DllImport("TestDll", EntryPoint = "DllProg")]
            public static extern void DllProg();
            
            private void button1_Click(object sender, EventArgs e)
            {
                DllProg();
            }
    

    C++ のプログラム

    __declspec(dllexport) void DllProg(void)
    {
    	int max, flg;
    	double x, y;
    	max = 255;
    	x = 319.5;
    	if (x == 0)
    		MessageBeep(MB_ICONEXCLAMATION);
    	y = 239.5;
    	flg = 2;
    }
    

    > ・質問文には「F5の続行では問題ありません」と書かれていましたが、
    > 今回「トレースすると 0が返ってきて、グラフィックが正しく描けなくなります」
    > とのことで、どう違うのでしょうか?
    グラフィックは私の本番のプログラムです。
    そちらで問題があったので、先日提示の簡単なプログラムを作りました。
    グラフィックのことは忘れて頂いて、本日提示のプログラムを見てください。
    トレースすると、if 文のところにおいて、0が返ってくるのでビープ音がします。

    > C++に問題があるのか、C++からC#への戻り値・境界部分に問題があるのか、どちらでしょうか?
    境界の所で起こっているのではなく、C++の関数の中で起こります。
    また、C#の方に命令を書きトレースしても問題は起こりません。

    2016年11月24日 1:10
  • 回答ではありませんが、私の環境でも再現しました。doubleの変数への代入をステップ実行するかどうかで挙動が変わるので、不具合の可能性が高い気がします。

    再現環境は以下です。

    OS: Windows 10 x86 バージョン 1511 ビルド 10586.0

    開発環境:

    Visual Studio 2013 update 5 (12.0.40629.00)

    Visual Studio 2015 update 3 (14.0.25431.01) ←こちらでも再現

    呼び出し側の.NET Frameworkのバージョン: 4~4.6.1(バージョンにはあまり依存しない?)

    以上。

    C++のEXEから同じDLLをロードしたときは再現しませんでした。(検証に使ったプロジェクトはこちら

    すでに不具合報告が上がっているかまだ調べられていませんが、Visual Studio 2015でも再現しますので下記のリンクから不具合登録を行ってみるのもありかもしれません。

    https://connect.microsoft.com/VisualStudio/content/content.aspx?ContentID=25941
    2016年11月24日 10:08
  • 現象としては浮動小数を変数にセットする箇所のアセンブラを見ると

    6B061735  movsd       xmm0,mmword ptr [__real@4073f80000000000 (6B066848h)]
    の部分でXMM0レジスタに浮動小数が入るはずなのにゼロが入るということが起きています。


    とりあえずの回避方法

    C#側を.Net Frameworkを3.5以前にしてデバッグ(.Net4以降のアセンブリを使わない)

    もしくは、

    C/C++のコード生成オプションで「拡張命令セットを有効にする」を拡張命令なしかSSEまでにする。
    (/archオプションがSSE2,AVX,AVX2だと発症する)

    とmovsd命令を使わなくなるので現象が起きなくなりました。

    他のSSE2命令を生成させたコードでもおかしな挙動をしているようなので、ネイティブと.net4以降のマネージの混合デバッガーでSSE2以降の命令の処理が無効にされてる?

    64bitCPUはSSE2は必ず搭載されているけど、32bitCPUは乗っていない可能性があるから誤判定してしまっているのかも。


    個別に明示されていない限りgekkaがフォーラムに投稿したコードにはフォーラム使用条件に基づき「MICROSOFT LIMITED PUBLIC LICENSE」が適用されます。(かなり自由に使ってOK!)

    2016年11月24日 10:49
  • > C/C++のコード生成オプションで「拡張命令セットを有効にする」を拡張命令なしかSSEまでにする。
    ということで、問題は起こらなくなりました。

    他のOSは起こらないですし、VS2013の方が早くリリースされていますので、
    OSがおかしいということもあるかも知れませんね?

    深いところまで理解されているようですので、
    gekka さんの方でMicrosoftとやり取りしていただけませんか?

    mnicksashimisan

    2016年11月25日 7:34