Access Violationが出ている場所の特定

解決


JUN  2010-06-28 19:56:16  No: 38712

デバックモードで実行してブレイクポイントで止めるとAccess Violation エラーがでないため、特定できません。
ブレイクポイントで止めないと何回かに1回出てしまうというものです。
そのため確実に出す方法もわからず困っています。

Access Violationのエラーが出てしまう場所の特定をしたいのですが、エラーの情報から特定できますでしょうか?
例えばAccessViolation at address ------ Read of address ------
の-----の部分から特定したり、他になにか良い方法等ありますか?
よろしくお願いします。


tor  2010-06-28 21:35:28  No: 38713

とりあえず
・エラーで止まったところから履歴ウィンドウで遡る(表示>デバッグ>呼び出し履歴)
・履歴が得られないようなら、デバッグ用ライブラリを使ってみる
(プロジェクト>オプション>コンパイラで「デバッグ用DCUを使う」をチェックして再構築)
・アクセス違反は範囲外アクセスに起因していることが多いので「範囲チェック」を有効にして実行する
あたりを試してみてはどうでしょう。


Quest  2010-06-28 23:07:54  No: 38714

まず、プロジェクトオプションのリンカにある、マップファイルの項目で「詳細」を選択します。
この状態でコンパイルすると、<プロジェクト名>.mapというファイルができます。
これはテキストファイルで、メモ帳など開くと、その先頭が

 Start         Length     Name                   Class
 0001:00401000 00247960H .text                   CODE
 0002:00649000 00002174H .itext                  ICODE
 0003:0064C000 00016C04H .data                   DATA
 0004:00663000 000304A4H .bss                    BSS
 0005:00000000 00000040H .tls                    TLS

 のようになっているので、1行目のStartのアドレス、00401000の部分をメモします。
 (ほとんどこの数値だと思いますが、違う場合もあるかもしれません)
 で、エラーメッセージの"AccessViolation at address $AAAAAAAA"の
 $AAAAAAAAからメモした値(つまり00401000)を引きます。
 たとえば、メッセージのアドレスが$0051A084だったら
 $0051A084 - $00401000 = $00119084 となります。
 
 次に、マップファイルの
 
Detailed map of segments

 0001:00000000 00006C55 C=CODE     S=.text    G=(none)   M=System   ACBP=A9
 0001:00006C58 00000105 C=CODE     S=.text    G=(none)   M=SysInit  ACBP=A9
 0001:00006D60 00000145 C=CODE     S=.text    G=(none)   M=Types    ACBP=A9
 0001:00006EA8 0000113C C=CODE     S=.text    G=(none)   M=Windows  ACBP=A9
 0001:00007FE4 00000315 C=CODE     S=.text    G=(none)   M=ActiveX  ACBP=A9
        ・
        ・
        ・

の部分から、この値(例では$00119084)が含まれるユニットを探します。
計算されたアドレスが$00006EA8から$00007FE4の間であれば、Windowsユニットと
いうことになります。このリストはアドレス順なので、すぐに分かるでしょう。
で、ユニット名が分かったら、そのユニット名で検索するとマップファイルの終わりの方に

Line numbers for <ユニット名>(<ユニット名>.pas) segment .text

    52 0001:0024682C    53 0001:00246850    54 0001:0024685D    55 0001:0024686A
    57 0001:0024687A    58 0001:0024689B    59 0001:002468A9    60 0001:002468C5
        ・
        ・
        ・

という部分が見つかります。
ここで、また計算されたアドレスを探します。
ドンピシャの箇所があれば、その前に書かれた数値がソースの行数です。
ピッタリ一致しなくても、次の行のアドレスより小さければその行となります。
例えば、計算されたアドレスが$00246858だったら、上のリストでは00246850と
0024685Dの間なので、"53 0001:00246850"の部分が該当し、53行目という事になります。

もし、出てきたユニット名が自分で作ったものではない(SystemやWindows等の)場合は
標準の関数や手続きを呼び出すときに、メモリ領域確保や初期化をしてない等が考えられます。
自作のユニットの場合は、該当の行辺りで原因を探せるでしょう。


JUN  2010-06-28 23:39:01  No: 38715

回答ありがとうございます。

私のほうで1行目のStartを確認してみました。
Start
 0001:00000000 00132DA8H .text                   CODE

となっていましたので、00000000がQuestさんの言っているアドレスですね。

実際に出ているエラーはAccessViolation at address 780149CEなのですが、

780149CE  - 00000000  =  780149CEとなります。

ただ780149CEがDetailed map of segmentsに該当する箇所がありません。
まず、00000000がおかしいのでしょうか?
こういったこともありますか?


Quest  2010-06-29 00:24:29  No: 38716

プロジェクトオプションのリンカにある、メモリーサイズのイメージベースは
いくつになっていますか?
ここの値が(ほぼ)コードのスタートアドレスになると思います。
ただこの場合は、アドレスの範囲が00000000〜00132DA8なのに
780149CEなんてアドレスを実行しているので、とんでもない場所を
アクセスしている事になります。
Createせずに呼び出そうとしているクラスのメンバーとか、動的にDLLを読み込んで
関数の割り当てに失敗したまま呼び出しているとか、心当たりはないでしょうか。
エラーが出るときに行っている処理から、ある程度ユニットが絞れませんか?
ブレークポイントで止めればエラーが出ないという事であれば、タイミングに
絡んだ問題かもしれません。
タイマーイベントとか、フォームなどのイベントが発生する順番が、想定した順番どおりに起きていないとか。


JUN  2010-06-29 03:13:35  No: 38717

Questさん

イメージベースは$00400000になっています。
Createせずに呼び出していればその時点でAccess Violationになるので、それが原因ではない気がします。
確かにQuestさんいわれているとおり、タイミングで出る問題と予想できますので、確実に出る方法がわかるず、なかなかつかめない状況にあります。

エラーが出るタイミングとしてはCloseしたときに出ます。
Closeしたときにエラーが何個も出続けてしまうことから、Timerなどでエラーになっているのではないかと考えています。
ですが、ここに書き込みしてからまったく調子が良くなってしまい、エラーが出ません。
とにかくもう一度コードを確認し、色々な処理を行って、エラーが出るように見てみます。


Quest  2010-06-29 03:35:16  No: 38718

イメージベースが$0040000なのに、
Start
 0001:00000000 00132DA8H .text                   CODE
ってのは変ですねぇ。
うーん、すみません、これ以上突っ込むノウハウは持ってないです。^^;

Closeしたときにエラーになるって事は、2重にFreeしてしまうクラスやモジュールがありませんか?
再現できない不具合って、本当に厄介ですね。


JUN  2010-06-29 22:07:50  No: 38719

やはりあれ以降エラーが出なくなったので、ソフトを変更しているうちに解消されたのかな(こういう考えはよくないですが)と思います。

とりあえずはこういった調べ方があるのか、ということがわかり、勉強になりました。

ありがとうございます。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加