none
デバッグビルドでのみ発生するエラーについて RRS feed

  • 質問

  • いつもお世話になっております。

    プログラムをデバッグしていて、ちょっと気になることがあったのでかきこみしました。
    現在、Windows 7 Enterprise(64bit) + VS2010 Professional のVC++でSDKで開発を行っております。

    作成したプログラムをデバッグしていると、途中でエラー終了になることがあります。
    その時の内容なのですが、「dbgdel.cpp の52行目で_BLOCK_TYPE_IS_VALID(pHead->nBlockUse なる例外が発生している」という感じなのですが…

    なぜかリリース版のビルドにすると、このエラーが全く発生しなくなるんです。

    これは、どこかメモリの解放などの処理におかしな部分がある、と思って調査したほうがいいんですよね?
    同様の経験をされた方、何か情報をお持ちの方がいらっしゃいましたら、情報をいただけると幸いです。

    2011年2月23日 2:34

回答

  • デバッグ版にあるエラーチェック機能が働いたために発生している、アサートと呼ばれる実行時エラー(即座に対処すべき重大な問題への警告のようなもの)が発生しています。

    アサートは、チェック機能の実行に時間がかかるため、デバッグ版にだけ仕込まれており、リリース版では機能しません。そのため、リリース版では発生しないように見えているだけで不具合がなくなるわけではありません。

    さて、まずはそのアサートが出るのがどこがトリガー(自分の書いたプログラムが何を呼び出したときにそこに到達したか)を調べる必要があります。エラー発生個所からおそらくは、delete あるいは、free の呼び出しがトリガーになっていると思います。

    まずは、このメモリーがオーバーランあるいはアンダーランしていないか?もしくは複数回解放処理を呼び出していないか?などを調査します。基本的に読み取る以外のメモリ操作すべてが疑わしいと思ってください。

    そこに問題がない(確保したバッファを超えて操作しない)のなら、その前後に確保されたメモリーも同様に調査します。

    それでも見つからない場合はさらに範囲を広げる。。。という形で少しずつ地道に調べていくことになります。


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    • 回答としてマーク どらちん 2011年2月23日 23:37
    2011年2月23日 4:22
  • こんにちは

    その時の内容なのですが、「dbgdel.cpp の52行目で_BLOCK_TYPE_IS_VALID(pHead->nBlockUse なる例外が発生している」という感じなのですが…

    delete 時に assert で止まっているのだから、普通に誰かがメモリを破壊しているのではないかと思われます。

    assert で止まったときに ALT+7 を押して呼び出し履歴を見てみれば、どこの delete 命令で止まったかはわかるんじゃないかと思います。


    電柱一家
    • 回答としてマーク どらちん 2011年2月23日 23:37
    2011年2月23日 5:10
  • すでに皆さん書かれていますが、リリース版だとエラーが出ないというのはプログラムが正常に動作している証明にはなりません。

    むしろデバッグ版で出ているのは幸運な事で、
    デバッグ版ですら顕在化しないような不具合は見つけるきっかけすらつかめない状態にあるわけです。
    ASSERTで出ているのであれば、更に良い状況で少なくとも問題が起こっている箇所を直接確認でき、呼出履歴を使って
    どういう呼出で起こっているのかまで追いかける事ができる状況にあります。

    基本的には、リリース版でもデバッグ版でも正常に動作している状況が不具合が可能な限り取り除かれている状態と呼べる状況であって、
    どちらかの版でおかしな動作が発生する場合は取り除けていない不具合が存在している状態になります。
    厳密には全ての不具合を取り除けている事を証明するのは不可能なので少なくとも顕在化している不具合は取り除けている
    としか表現できないわけです。

    とにかく、メモリ破壊絡みの不具合は実際に破壊している箇所と顕在化している箇所が違っているケースが多く、
    地道な調査が必要になります。まずはASSERT周りから呼出履歴を使った調査を行い、
    顕在化している箇所を特定します。運がよければ、そこから破壊されているメモリ領域が特定でき、
    そのメモリの確保から開放までを追いかける事で実際に破壊している箇所を特定できる場合があります。

    静的な解析によってメモリリークやメモリ破壊を見つけてくれるソフトや
    実際に動作させてメモリ関連の不具合を検出するツールもありますが、
    値段が高いので予算との相談になります。
    あれば便利なツールですが、必須とまでは言い切れないのでその辺はそういう物があると言う話として
    覚えておけば良いのではないかと思います。


    解決した時は、参考になったレスポンスの所にある[回答としてマーク]ボタンをクリックしてスレッドを締めましょう。
    • 回答としてマーク どらちん 2011年2月23日 23:37
    2011年2月23日 6:03

すべての返信

  • デバッグ版にあるエラーチェック機能が働いたために発生している、アサートと呼ばれる実行時エラー(即座に対処すべき重大な問題への警告のようなもの)が発生しています。

    アサートは、チェック機能の実行に時間がかかるため、デバッグ版にだけ仕込まれており、リリース版では機能しません。そのため、リリース版では発生しないように見えているだけで不具合がなくなるわけではありません。

    さて、まずはそのアサートが出るのがどこがトリガー(自分の書いたプログラムが何を呼び出したときにそこに到達したか)を調べる必要があります。エラー発生個所からおそらくは、delete あるいは、free の呼び出しがトリガーになっていると思います。

    まずは、このメモリーがオーバーランあるいはアンダーランしていないか?もしくは複数回解放処理を呼び出していないか?などを調査します。基本的に読み取る以外のメモリ操作すべてが疑わしいと思ってください。

    そこに問題がない(確保したバッファを超えて操作しない)のなら、その前後に確保されたメモリーも同様に調査します。

    それでも見つからない場合はさらに範囲を広げる。。。という形で少しずつ地道に調べていくことになります。


    わんくま同盟,Microsoft MVP for Visual C++(Oct 2005-) http://blogs.wankuma.com/tocchann/
    • 回答としてマーク どらちん 2011年2月23日 23:37
    2011年2月23日 4:22
  • こんにちは

    その時の内容なのですが、「dbgdel.cpp の52行目で_BLOCK_TYPE_IS_VALID(pHead->nBlockUse なる例外が発生している」という感じなのですが…

    delete 時に assert で止まっているのだから、普通に誰かがメモリを破壊しているのではないかと思われます。

    assert で止まったときに ALT+7 を押して呼び出し履歴を見てみれば、どこの delete 命令で止まったかはわかるんじゃないかと思います。


    電柱一家
    • 回答としてマーク どらちん 2011年2月23日 23:37
    2011年2月23日 5:10
  • すでに皆さん書かれていますが、リリース版だとエラーが出ないというのはプログラムが正常に動作している証明にはなりません。

    むしろデバッグ版で出ているのは幸運な事で、
    デバッグ版ですら顕在化しないような不具合は見つけるきっかけすらつかめない状態にあるわけです。
    ASSERTで出ているのであれば、更に良い状況で少なくとも問題が起こっている箇所を直接確認でき、呼出履歴を使って
    どういう呼出で起こっているのかまで追いかける事ができる状況にあります。

    基本的には、リリース版でもデバッグ版でも正常に動作している状況が不具合が可能な限り取り除かれている状態と呼べる状況であって、
    どちらかの版でおかしな動作が発生する場合は取り除けていない不具合が存在している状態になります。
    厳密には全ての不具合を取り除けている事を証明するのは不可能なので少なくとも顕在化している不具合は取り除けている
    としか表現できないわけです。

    とにかく、メモリ破壊絡みの不具合は実際に破壊している箇所と顕在化している箇所が違っているケースが多く、
    地道な調査が必要になります。まずはASSERT周りから呼出履歴を使った調査を行い、
    顕在化している箇所を特定します。運がよければ、そこから破壊されているメモリ領域が特定でき、
    そのメモリの確保から開放までを追いかける事で実際に破壊している箇所を特定できる場合があります。

    静的な解析によってメモリリークやメモリ破壊を見つけてくれるソフトや
    実際に動作させてメモリ関連の不具合を検出するツールもありますが、
    値段が高いので予算との相談になります。
    あれば便利なツールですが、必須とまでは言い切れないのでその辺はそういう物があると言う話として
    覚えておけば良いのではないかと思います。


    解決した時は、参考になったレスポンスの所にある[回答としてマーク]ボタンをクリックしてスレッドを締めましょう。
    • 回答としてマーク どらちん 2011年2月23日 23:37
    2011年2月23日 6:03
  • とっちゃんさん、電柱一家さん、PATIOさん

    レスありがとうございます。
    やっぱりそうですよね…

    地道にログをはくなどして調査していきます。
    ありがとうございました^^

    2011年2月23日 23:37