none
Windows7PCでVisualstudio2008のDebugモード実行時に、VC++で作成したXXXX.dllを呼出すとAccess Violation(0x000000005)が発生する。 RRS feed

  • 質問

  • 以下環境にて、掲題の現象が発生し、困っています。

    どなたか対処方法について、ご教授お願い致します。

    開発環境
    OS Windows 7 x86 SP1
    ツール Visual Studio 2008 SP1
    DB MSSQL 2005
    言語 VC++ 8.0
    出力 XXXX.dll
    追記 msado15.dllを使用

    ① Windows XP環境ではDebug、Releaseモード共に正常に動作する      
    ② Windows7のReleaseモード時は正常に動作する      
    ③ ADOのレコードセットのClose()の後、レコードバインディングインタフェースのRelease()時に異常終了する 。

    //宣言を追記しました。

    _RecordsetPtr  m_targetRecordSet;
    IADORecordBinding   *m_targetIADOBinder;

     if( m_targetRecordSet != NULL ){    // DBにアクセスしていれば
      m_targetRecordSet->Close();   // RecordSetを閉じる
      m_targetRecordSet->Release();   // リソースを開放する
      m_targetRecordSet = NULL ;   // NULLにする
     }     
     if (m_targetIADOBinder != NULL)     
     {     
      m_targetIADOBinder->Release();   ⇒ ■Access Violation発生
      m_targetIADOBinder = NULL;    
     }     
    ④ レコードセット及びレコードバインディングインタペースはポインターメンバー変数でクラス生成時に初期化されている      
     targetRecordSet = NULL ;     
     m_targetIADOBinder = NULL;     
    ⑤ m_targetIADOBinderの値が異常値に変更される時点はレコードセットがNULLに変更される時点です      
     m_targetIADOBinderの参照アドレスが0xfeeefeeeになる     
    ⑥ 今のmsado15.dllのバージョンは6.1.7601.17514である      

    以上、宜しくお願いします。


    • 編集済み _Te 2011年6月9日 3:53
    2011年6月9日 1:28

回答

  • m_targetRecordSet がスマート ポインターなので、

     m_targetRecordSet->Release(); // リソースを開放する
    
     m_targetRecordSet = NULL ; // NULLにする
    
    

    これをやってはいけない気がします。
    NULL を代入するところで、スマート ポインターが内部で保持しているインスタンスを Release しようとするはずですので、既に破棄されたインスタンスでもって Release してしまいます。
    もしもやるなら、

     m_targetRecordSet.Release();
    
    

    なんでしょうけれど、スマート ポインターなので後始末はしない(スマート ポインターに任せる)というのではいかがでしょうか。

    # Windows 7 の Release ビルドで動いてしまうのは、Debug ビルドと違って破棄された領域にゴミが入らないから運悪く動いているように見えるのでしょうけれど、
    # Windows XP でも運悪く動いてしまっているのは、OS が違うからなのだろうか...。

    • 編集済み totojo 2011年6月10日 3:12
    • 回答としてマーク 山本春海 2011年6月24日 8:51
    2011年6月9日 5:18
  • totojoさんのおっしゃる通りで、m_targetRecordSetの定義を辿っていくと、スマートポインターの実体として_com_ptr_tクラスに行きつくと思います。このクラスのoperator=()を読むと、NULL代入などを行った際、元に保持していたポインターに対してRelease()を呼び出していることがわかると思います。

    # とはいえ、operator=()のドキュメントにはそんなこと書かれていないのではまりやすいなぁ…

    • 回答としてマーク 山本春海 2011年6月24日 8:51
    2011年6月9日 18:30
  • 基本は放っておいて構わないとおもうのですが、もしやるとしたら、

      m_targetRecordSet = NULL ;

    と NULL を代入するよりも

      m_targetRecordSet.Relase();

    とするべきだと思います。
    NULL を代入すると内部で Release() されるっていうのは、スマート ポインターの実装にまで立ち入ってしまっているので、カプセル化の観点でイケてないように思います。
    それに引き換え、後者のスマート ポインターの Release() はよく見かけるコーディングですので、驚き&疑いが少ないです。
    • 回答としてマーク 山本春海 2011年6月24日 8:51
    2011年6月10日 7:23

すべての返信

  • m_targetIADOBinder が何者なのかを明らかにした方がいいではないでしょうか。
    2011年6月9日 2:18
  • ご指摘ありがとうございました。

    本文へ宣言文の追記をさせていただきました。

    宜しくお願い致します。

    2011年6月9日 4:11
  • m_targetRecordSet がスマート ポインターなので、

     m_targetRecordSet->Release(); // リソースを開放する
    
     m_targetRecordSet = NULL ; // NULLにする
    
    

    これをやってはいけない気がします。
    NULL を代入するところで、スマート ポインターが内部で保持しているインスタンスを Release しようとするはずですので、既に破棄されたインスタンスでもって Release してしまいます。
    もしもやるなら、

     m_targetRecordSet.Release();
    
    

    なんでしょうけれど、スマート ポインターなので後始末はしない(スマート ポインターに任せる)というのではいかがでしょうか。

    # Windows 7 の Release ビルドで動いてしまうのは、Debug ビルドと違って破棄された領域にゴミが入らないから運悪く動いているように見えるのでしょうけれど、
    # Windows XP でも運悪く動いてしまっているのは、OS が違うからなのだろうか...。

    • 編集済み totojo 2011年6月10日 3:12
    • 回答としてマーク 山本春海 2011年6月24日 8:51
    2011年6月9日 5:18
  • totojoさんのおっしゃる通りで、m_targetRecordSetの定義を辿っていくと、スマートポインターの実体として_com_ptr_tクラスに行きつくと思います。このクラスのoperator=()を読むと、NULL代入などを行った際、元に保持していたポインターに対してRelease()を呼び出していることがわかると思います。

    # とはいえ、operator=()のドキュメントにはそんなこと書かれていないのではまりやすいなぁ…

    • 回答としてマーク 山本春海 2011年6月24日 8:51
    2011年6月9日 18:30
  • totojoさん、佐祐理さん お返事、ありがとうございます。
    スマート ポインターですが、確かに佐祐理さんがおっしゃった通りに_com_ptr_tクラスのoperator=()で元に保持していたポインターに対してRelease()を呼び出していました。
    スマート ポインターに対して詳しく分かりませんが、リソースの開放を内部でやってくれるみたいですね。
    その意味で今のソースを軽くした方が良いということでしょうか?
    例えば下のように

     if( m_targetRecordSet != NULL ){    // DBにアクセスしていれば
      m_targetRecordSet->Close();   // RecordSetを閉じる
      m_targetRecordSet = NULL ;   // NULLにする
     }    
     if (m_targetIADOBinder != NULL)    
     {    
      m_targetIADOBinder = NULL;   
     }    

    この場合、メモリリークの調査やWindows XPでの動作確認が必要になりますが上の順で問題なければ良いと思っています。
    お返事、ありがとうございました。

    2011年6月10日 7:11
  • 基本は放っておいて構わないとおもうのですが、もしやるとしたら、

      m_targetRecordSet = NULL ;

    と NULL を代入するよりも

      m_targetRecordSet.Relase();

    とするべきだと思います。
    NULL を代入すると内部で Release() されるっていうのは、スマート ポインターの実装にまで立ち入ってしまっているので、カプセル化の観点でイケてないように思います。
    それに引き換え、後者のスマート ポインターの Release() はよく見かけるコーディングですので、驚き&疑いが少ないです。
    • 回答としてマーク 山本春海 2011年6月24日 8:51
    2011年6月10日 7:23