
大変困っています。
アプリケーションが終了するときに「アクセス違反」がワトソン博士によって取得されています。
当方アプリケーションなどに弱く、解決策の想像が付きません。どなたかご教授お願いいたします。
<解決策例>
・どういったスキルを持った人にどの様な調査を進めさせれば良いのか。。。
・以前同様な事があり原因は○○だった
・恐らく○○だろう
など、お願いいたします。
<ユーザ報告>
処理終了し、画面が消えたところでワトソン博士のメッセージが表示された
<ログ抜粋>
例外番号c0000005(アクセス違反)
ファンクション:RtlDestroyHeap
~略~
フォールト → 77f6d672 8908 mov [eax],ecx ds:09000001=00000000
<備考>
開発環境:MSVC6.0
動作環境:Windows NT4.0 SP6a
発生頻度:2回/年
使用頻度:2~3回/(平日)
以上、よろしくお願いします。
No.5ベストアンサー
- 回答日時:
発生頻度が年2回というのはなかなか厳しい条件ですね。
さて・・・
「私であれば、次の手順で調査を行います。」という書き始めで延々とデバッグ方法を書いていたのですが、書き終わってからちょっとGoogleで検索したら、ひょっとするとちょうど質問者さんのトラブルと同じかもしれない現象がMicrosoftのKBにありました。
場所はここです: http://support.microsoft.com/kb/168006/ja
要点をかいつまんで書くと、MSVCRT/MFCのDLLのバージョン不整合でエラーが発生することがある、という内容です。KB自体は特定のアプリケーションについて書かれていますが、記述されている現象と原因の関係から考えるに、他のアプリケーションでも同様の現象が発生すると思われます。
さてさて。
せっかく書いた文章を捨てるのがもったいないので(貧乏性)、邪魔かもしれませんが下に続けることにします。もし上のKBの内容がそれらしいようであれば、読み飛ばしてください。
========
私であれば、次の手順で調査を行います。
1. MAPファイル、CODファイル作成
「ワトソン博士のログを取得した際に実行していたEXEファイル」をビルドした際、一緒にMAPファイルやCODファイル(リスティングファイル)を作成していれば、そのファイルを用意しておきます。
もし作成していない場合は、「ワトソン博士のログを取得したEXEファイル」と、バイナリレベルで全く同じEXEファイル(バイト単位で比較すると、ファイルに埋め込まれたタイムスタンプ・チェックサム以外は一致する)が作成可能かどうか調べます。(ビルドに必要なソースファイルやビルドオプションに変更を加えていなければ作成可能です。)
作成可能であれば、コンパイルオプションに「リスティングファイルタイプ:マシン語コードとソースを含む」、リンクオプションに「MAPファイル作成」を追加してEXEを再作成してください。これで、「ワトソン博士のログを取得した際に実行していたEXEファイル」に対応するMAPファイルとCODファイルが得られます。
2. エラー発生行を特定
ワトソン博士のログがどれだけ取れているかにもよりますが、スタックダンプが含まれていればたいていエラー発生行を特定できます。
まず「フォールト->」が含まれる逆アセンブルリストを探します。次に、その下にある「スタックバックトレース」を探します。
スタックバックトレースを上から下に順にたどっていくと、そのうち「ReturnAd」(リターンアドレス)がアプリケーションのアドレス範囲(VC++6の標準オプション設定を変更していなければ0x00400000~)に入るところが出てきます。見つかったら、そのアドレスの直前にあるcall命令が例外を発生させたAPIを直接呼び出している場所です。
さて、仮にリターンアドレスが0x00401234だったとします。そうしたら、次はMAPファイルを見てこのアドレスがどの関数に属しているか探します。ちょうど0x00401234というアドレスは見つからないでしょうけれども、これに近いアドレスは見つかるはずです。そのアドレスに対応する関数名もMAPファイルにあります。
次はその関数名をCODファイルから探します。見つかったら、MAPファイルにあるアドレスがCODファイルにあるマシン語コードの先頭アドレスになるので、そこからリターンアドレス0x00401234に対応するはずの場所まで順番にアドレスを辿っていきます。関数の先頭アドレスが0x00401200であれば、0x34バイト先を探すわけです。
そうすると、その探した場所にある命令の直前の命令がcall命令になっているはずです。CODファイルには、その場所のC++ソースでの行番号とソース文もコメントとして入っているはずなので、あとは対応するソースをよーく見てエラーの見当をつけてください。
アセンブラの知識があれば、そこでcallを使った(他の関数を呼び出した)ときの引数の内容もある程度分かります。(ポインタ渡しだと、そのポインタの先の内容までは分かりませんが。)
3. 置き換え用EXEファイルと対応するMAPファイル作成
これ以降は将来への備えです。
コンパイルオプションでデバッグ情報を「プログラムデータベースを使用」、リスティングファイルタイプを「マシン語コードとソースを含む」、リンクオプションで「MAPファイルを作成する」、デバッグ情報「他の種類」を追加してビルドし、出来たEXEファイルを本番用として使用します。同時に作成されるMAPファイル、CODファイル、PDBファイルは保管しておきます。
MAPファイル、CODファイルの使い方は上記2.のとおりです。PDBファイルは、もし完全なクラッシュダンプが取得できればWinDbgを使って事後ソースレベルデバッグが可能になりデバッグ作業が非常に楽になるので、念のため取っておきます。
4. ワトソン博士のオプション変更
drwtsn32.exeを起動し、「クラッシュダンプファイルの作成」をチェックします。(デフォルトは、チェックが入っています。)
クラッシュダンプファイルとEXEとPDBがあればWinDbgで事後ソースレベルデバッグができます。(いわゆるポストモーテムデバッグです。UNIX系でコアダンプしたコアをデバッガで読み込んでデバッグするのと同じ種類のものです。)
普段何とも思わずに行っていることでも、文章にすると長いですね・・・
えーと、「どういうスキルを持った人に調査させればいいか」については、上記の内容を読んで『なるほど!』と言える人でしょうか。
参考URL:http://support.microsoft.com/kb/168006/ja
No.7
- 回答日時:
問題点の調査方法ではないですし抜本的な解決策でもないですけど、アクセス違反が発生するのが処理中ではなく終了時(終了処理によるもの)なら、終了時のメモリ解放処理を省いてしまうという解決策もあります。
実のところC/C++でもメモリ解放処理は結構複雑で、データ構造によってはエラーを起こさずに解放するのが難しいこともあります。どうせプロセスが終了すれば全解放されるのでプログラム上での解放処理を省いてしまうのが簡単な場合も多いです。
No.6
- 回答日時:
No.4に対する「回答者へのお礼」のコードを見ると、
何処かで
char *p = new char[256];
p += 10;
...
delete [] p; // 加算したポインタで開放
などとしているということはないでしょうね?
これだとポインタの演算が入るような場合にのみアクセス違反が発生しますよ。
No.4
- 回答日時:
あと、この場合、一番可能性の高いのがどこかの処理でメモリを破壊している、という可能性です。
たまたま壊した箇所にアクセスに行かない限り落ちないので落ちたり落ちなかったり、壊した箇所がデータであればフラグを書き換えたりして誤動作の原因になったりと始末に終えません。
ほかにもいろいろあるとおもいますがとりあえず思いつく原因はこんなところです。
ー あらかじめ確保したバッファのサイズを越えて書き込みを行っている箇所はないか
ー 基本クラスのインスタンスに追加のメンバ変数をもつ派生クラスのポインタでアクセスしたりしていないか
ー 未初期化ポインタで処理されている箇所はないか
あたりまえの回答でもうしわけありませんが、
VCがわかる人に、メモリを壊している箇所がないか調査してもらう、ということになるのでは?
早速ありがとうございます。
当たり前の回答とおっしゃりますが、非常に助かります。こちらはその当たり前も。。。
実は、あまりわからないなりにも解析していたところ、作成していた方のレベルが。。。だった為か、以下のような記述を発見しました。。
FuncA(CString strSrc){
char szA[50];
memcpy(szA, strSrc, strSrc.GetLength());
}
(もちろん呼び側でもlength未精査)。。
また、少しわからないのが、原因不明だったためか、
InitInstanceでダイアログをmodalする時(DialogBase)にtry文で例外を取得しているのですが、効果がはなかったみたいです。(以下参照)
解釈としては、「上記のような箇所がある為InitInstanceのメモリ開放時に落ちている」でよろしいですかね?
InitInstance() {
CADialog ADlg;
try {
nRet = ADlg.DoModal();
}
catch(...){
}
}
すみません。。たびたび。
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
このQ&Aを見た人はこんなQ&Aも見ています
-
読み込み中にアクセス違反が発生しました、と出ます。これを回避することは
C言語・C++・C#
-
「AccessViolationException」と出てしまい、困っています
Visual Basic(VBA)
-
VC++スレッドの正しい終了のさせかた
C言語・C++・C#
-
-
4
画面を強制的に再描画させる方法
C言語・C++・C#
-
5
deleteで開放するとエラーになる原因がわからない
C言語・C++・C#
-
6
WaitForSingleObjectの使い方について
C言語・C++・C#
-
7
CStringの文字列検索&抜き出しについて
C言語・C++・C#
-
8
ファイルマッピング関数で失敗
C言語・C++・C#
-
9
CString から LPCTSTRの型に変換
C言語・C++・C#
関連するカテゴリからQ&Aを探す
おすすめ情報
このQ&Aを見た人がよく見るQ&A
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
C言語初心者の質問失礼します。
-
csvファイルを開かずに文字を検...
-
ファイル名の先頭にアンダース...
-
ドラッグアンドドロップでファ...
-
C言語で、エクセルの中身を読み...
-
unlinkしたファイルを元に戻す...
-
グローバル変数のよくない使い...
-
バッチファイルでD&Dしたファイ...
-
C言語初心者です。ファイルの入...
-
C言語のfopenについて教えてく...
-
Iniファイルを使用したAccessVB...
-
CSVファイルへの保存の際、デー...
-
大きいサイズのテキストファイ...
-
VC++の外部依存関係
-
COM相互運用機能のON,OFFによる...
-
「VBScript」ADODB.Streamにお...
-
VB.NETのサンプルコードが知りたい
-
ファイルからサイズ不明の行デ...
-
Excelマクロでの再読込み方法
-
iniファイルに追記がしたいです。
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
C言語初心者の質問失礼します。
-
dataファイルをxtxファイルにす...
-
csvファイルを開かずに文字を検...
-
ファイル名の先頭にアンダース...
-
CSVファイルへの保存の際、デー...
-
グローバル変数のよくない使い...
-
バッチで118項目のCSVを処理し...
-
テキストファイルの最終行を削...
-
VBAにてEXCEL以外のファイル(テ...
-
VBに、Cのincludeのようなもの...
-
分割コンパイルの#defineについて
-
RPGでファイル名(もしくはレコ...
-
SGファイルって何ですか?
-
マウスポインタの変更
-
Excelマクロでの再読込み方法
-
【C#】リソースファイルの埋め...
-
ダイアログボックスで複数フォ...
-
C言語のfopenについて教えてく...
-
ドラッグアンドドロップでファ...
-
「VBScript」ADODB.Streamにお...
おすすめ情報