開放漏れ?未定義エラーの原因について – プログラミング – Home

開放漏れ?未定義エラーの原因について
 
通知
すべてクリア

[解決済] 開放漏れ?未定義エラーの原因について


ソイレントグリーン
 ソイレントグリーン
(@ソイレントグリーン)
ゲスト
結合: 17年前
投稿: 65
Topic starter  

いつもお世話になります、長文お許しください、原因の分からない、未定義のエラーが発
生しております、ご存知の方、似たような不具合の経験がある方がおられましたら、ご教
示願います。

環境:Windows XP SP2 / Visual Studio 2005 MFC

プログラムの動作概略:
① PreTranslateMessageを用いて、親ダイアログのキー入力を取得する
② テンキーの0~9が押下された場合、DoModal()で子ダイアログのインスタンスを生成し
ます
③ 子ダイアログの、EditBoxにコード番号を入力します
④ 子ダイアログのEnterキー押下
⑤ 子ダイアログから、EndDialog()を用いて、EditBoxに入力した、コード番号を、親ダ
イアログへ返却します
⑥ 親ダイアログは引取った、コード番号を元に、フルパス名を生成して、インターフェ
ースクラス(CDisplayInterfaceクラス)へ
⑦ インターフェースクラスは、与えられた引数を使い、ファイルからデータを読み込
み、vectorコンテナへデータを代入します
⑧ ①へ戻る

問題点:
大雑把ですが、プログラムの概要はこの様なものです、一連の動作は、しているのです
が、プログラム終了時、親ダイアログのOKボタン。または、Cancelボタン押下で、プログ
ラムを終了させると、下記の部分で、未定義のエラーが発生します。

原因の推測:
当初インターフェースクラスのデストラクタが呼ばれていないせいで、未定義のエラーが
発生したものと推測し、親ダイアログのOnBnClickedOk()、OnBnClickedCancel()が動いた
タイミングでインターフェースクラスのデクストラクタに、コンテナを自殺させるよう
に、コードを追加し呼び出しましたが、未定義のエラーは止まりませんでした。
Releaseモードでコンパイル、実行した場合は発生しません。
原因は、vectorコンテナのデストラクタに起因すると察するのですが、自力で解決できま
せん、この不具合の原因をご教示していただけないでしょうか、コードが大きく、断片的
な部分しか、提示できませんが宜しくお願い致します。

// 未定義のエラー(ハンドルされていない例外が発生しました:
// 0xC0000005: 場所 0xfdfdfdfd に書き込み中にアクセス違反が発生しました。)
// c:\program files\microsoft visual studio 8\vc\include\xutility
inline void __CLR_OR_THIS_CALL _Container_base::_Orphan_all() const
{ // orphan all iterators
_Lockit _Lock(_LOCK_DEBUG);
if (_Myfirstiter != _IGNORE_MYITERLIST)
{
for (_Iterator_base **_Pnext = (_Iterator_base **)&_Myfirstiter;
*_Pnext != 0; *_Pnext = (*_Pnext)->_Mynextiter)
(*_Pnext)->_Mycont = 0; //←ここで未定義のエラー発生
*(_Iterator_base **)&_Myfirstiter = 0;
}
}

// 親ダイアログ、キー入力部分
BOOL C***Dlg::PreTranslateMessage(MSG* pMsg)
{
INT_PTR nChar;
INT_PTR result;
if( pMsg->message == WM_KEYDOWN )
{
nChar = pMsg->wParam;
switch( nChar ) {
case VK_RETURN :
break;
case VK_ESCAPE :
break;
case VK_TAB:
break;
case VK_NUMPAD0 : // 0 キー
nChar = pMsg->wParam;
child.SetCode( nChar );
result = child.DoModal();
Show( result );
return true;
case VK_NUMPAD1 : // 1 キー
nChar = pMsg->wParam;
child.SetCode( nChar );
result = child.DoModal();
Show( result );
return true;
// 以下省略(同様に、テンキー2キー~8キーを記述)
case VK_NUMPAD9 : // 9 キー
nChar = pMsg->wParam;
child.SetCode( nChar );
result = child.DoModal();
Show( result );
return true;
default:
break;
}
return CDialog::PreTranslateMessage(pMsg);
}
return false;
}

// インターフェースクラスのデストラクタ
CDisplayInterface::~CDisplayInterface()
if( !containerWork.empty() )
containerWork.clear();
if( !containerFirst.empty() )
containerFirst.clear();
if( !containerSecond.empty() )
containerSecond.clear();
// 以下省略(同様にCDisplayInterfaceクラスで、定義されている、コンテナを全て列挙
し自殺させる)


引用未解決
トピックタグ
ソイレントグリーン
 ソイレントグリーン
(@ソイレントグリーン)
ゲスト
結合: 17年前
投稿: 65
Topic starter  

お世話になります、補足させていただきます、
「(*_Pnext)->_Mycont = 0; vector」で検索して調べていますと、日本語サイトは一軒も
Hitしないのですが、
http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=2019491&SiteID=1&pageid=0
このような事例に、巡りあいました、Googleの翻訳エンジンの力を借りながら、自分なり
に脳内で咀嚼していきますと、コンパイラの範囲チェック機能が働き、未定義のエラーが
発生しているのではないかと思い、インターフェースクラスのヘッダーファイルのマクロ
部分に
#define _HAS_ITERATOR_DEBUGGING 0
を追加して、範囲チェック機能を無効にしてみました、
コンパイルしますと
warning C4005: '_HAS_ITERATOR_DEBUGGING' : マクロが再定義されました。
c:\program files\microsoft visual studio 8\vc\include\yvals.h
(94) : '_HAS_ITERATOR_DEBUGGING' の前の定義を確認してください

warning C4005: '_HAS_ITERATOR_DEBUGGING' : マクロが再定義されました。
この警告を無視して、実行しますと、デッバグモードでコンパイル、実行を行っても
落ちなくなりました、やはり原因は、私の書いた、vectorコンテナの実装にありそうで
す。

// CDisplayInterfaceクラスのマクロ定義変更
#ifndef _CDISPLAYINTERFACE_H_ // 二重インクルードガード
#define _CDISPLAYINTERFACE_H_
#define _HAS_ITERATOR_DEBUGGING 0 // ここを追加しました
ソース
#endif


返信引用
RAPT
 RAPT
(@RAPT)
ゲスト
結合: 21年前
投稿: 310
 

// 未定義のエラー(ハンドルされていない例外が発生しました:
// 0xC0000005: 場所 0xfdfdfdfd に書き込み中にアクセス違反が発生しました。)
まずこれは、VC++のデバッガによる不正アクセスのエラー報告です。
よくあるのが、

char* p = new char[ 10 ];
delete[] p;
p[ 1 ] = 0; // ここでアクセス違反

おそらく、すでにポインタを削除しているのに、NULL を入れてなくて、
デストラクタで非NULLなので参照しようとして落ちているのでしょう。

肝心のコンテナの実装部分が書かれていないので憶測ですが。


返信引用
RAPT
 RAPT
(@RAPT)
ゲスト
結合: 21年前
投稿: 310
 

追記。
これは解放漏れではなく、逆の二重解放でしょう。


返信引用
ソイレントグリーン
 ソイレントグリーン
(@ソイレントグリーン)
ゲスト
結合: 17年前
投稿: 65
Topic starter  

RAPTさんお世話になります、ご教示ありがとうございます
RAPTさんの、見解を参考に試行錯誤検証しています、
>>肝心のコンテナの実装部分が書かれていないので憶測ですが。
下記のような、状況故、当該不具合が、直接コンテナの実装に起因して、発生しているよ
うではないので、しばしご容赦願います。
ということで、早速ですが、検証中に、このような事実が判りました
検証A
① プログラム起動
② 親のダイアログのOK(Cansel)ボタン押下
③ 正常終了

検証B
① プログラム起動
② テンキー操作にて、子ダイアログ起動
③ 子ダイアログの、EditBoxには何も入力しない
(即ち、vectorコンテナを使う関数は、直接アクセスを行わないという事です、しかし起
動した時点で、それらのコンストラクタも動いていますから、全く無関係とは、考えてい
ません)
④ 子ダイアログ、×ボタン押下
⑤ 親のダイアログのOK(Cansel)ボタン押下
⑥ 異常終了、未定義エラー発生

この様な状況です、故にコンテナの実装というよりも、RAPTさんに、教えて頂いた、二重
開放させるようなプログラムを組んでしまったのかも知れません、子ダイアログの起動、
終了周りの実装は下記のような感じです、何か、おかしなことをしていないか、お気付き
のことがあれば指摘願えませんでしょうか。

ダイアログ上のリソースアイテム
親ダイアログ
OKボタン 表示
Canselボタン 表示
Custom Control 表示

子ダイアログ
EditBox 入力部分はサブクラス化して、特定のキー入力しか受付けないように実装
OKボタン 非表示
Canselボタン 非表示

子ダイアログの起動、終了処理周りの実装
子ダイアログの実装
BOOL CChild::OnInitDialog()
{
// CChild メッセージ ハンドラ
CDialog::OnInitDialog();
m_NEdit.SubclassDlgItem( IDC_EDIT1, this); // サブクラスの定義
GetDlgItem(IDOK)->ShowWindow(SW_HIDE); // 非表示
GetDlgItem(IDCANCEL)->ShowWindow(SW_HIDE); // 非表示
Proc();
return TRUE;
}

void CChild::Proc()
{
m_codeNum = static_cast<int>( m_code ); // EditBoxに値を設定
SetDlgItemInt( IDC_EDIT1, m_codeNum );
UpdateData(false);
}

void CChild::OnBnClickedOk()
{
UpdateData();
m_result = GetDlgItemInt( IDC_EDIT1 ); // EditBoxから、値を取得
EndDialog( m_result ); //親ダイアログに値を返却
}

void CChild::OnBnClickedCancel()
{
OnCancel();
}


返信引用
たいちう
 たいちう
(@たいちう)
ゲスト
結合: 22年前
投稿: 662
 

> >>肝心のコンテナの実装部分が書かれていないので憶測ですが。
> 下記のような、状況故、当該不具合が、直接コンテナの実装に起因して、発生しているよ
> うではないので、しばしご容赦願います。

不具合が何に起因しているか、あなたに正しい判断ができるなら
こんな投稿はしていないのでは?
メモリ関係のエラーは、原因と結果(異常の発覚)が離れているのが
大半ですよ。

「肝心のコンテナの実装部分」なしに、直接役に立つアドバイスは
付かないと思いますが。ちょっと見ただけの私の印象ですが。


返信引用
ソイレントグリーン
 ソイレントグリーン
(@ソイレントグリーン)
ゲスト
結合: 17年前
投稿: 65
Topic starter  

たいちうさん、お世話になります
>>不具合が何に起因しているか、あなたに正しい判断ができるなら
>>こんな投稿はしていないのでは?
ごもっともです、しかしvectorコンテナの実装部分だけでコメントも含めて、
400行強、ヘッダーファイルだけで180行もありこの様なものを、掲示しても皆さんのご迷
惑というか、読む気もならないと思い、掲示することをためらいました。
しかし、なんとか不具合の原因が判明しました。
原因は、vectorコンテナではありませんでした
子ダイアログの戻り値をEndDialog( INT_PTR )で受取り、そのデータから
親ダイアログで、フルパス名を生成してインターフェースクラスに引渡す部分で、
うっかり(上記Show( result );の部分です)
その、インターフェースクラスのファイルオープン処理を行う
ifstream ifs;
ifs.open( m_fname, ios::in );
に引き渡す、第一引数である、m_fnameをconst char*型に変換すべきものを
char buffer[40];
strcpy_s(buffer, 40, m_fname.c_str() );
勘違いから、わざわざ、このような変換を行い。且つ、
ファイル名が40バイト以上あったので
メモリーバッファーオーバーフローを誘引していました、原因はここでした
単純にm_fname.c_str()で引き渡せばいいものを、余分なことをして失敗していました。
みなさんどうも、ありがとうございました。


返信引用

返信する

投稿者名

投稿者メールアドレス

タイトル *

プレビュー 0リビジョン 保存しました
共有:
タイトルとURLをコピーしました