LoginSignup
1
1

More than 5 years have passed since last update.

C++ Builder > 通信台数を4から1に変更した時 > Error: モジュール '何がしのプログラム.exe'のアドレスXXXXでアドレスYYYYに対する読み取り違反がおきました。' > 特定方法 | 原因 | 技術的負債

Last updated at Posted at 2017-10-05
動作環境
C++ Builder XE4

変更内容

  • 四台の装置との通信ソフトをベースに一台の装置との通信ソフトを作成
    • static const int定義を4から1に変更

実行すると以下となる。

qiita.png

関連

C++ Builder > Error: モジュール '何がしのプログラム.exe'のアドレス0044392Eでアドレス000005B5に対する読み取り違反がおきました。' > 原因の特定 | 原因

リンク先の方法で原因を特定しようとしたが分からなかった。
VCLのソースにリンクされるだけで、自前実装のソースのエラーは特定できない。

原因の特定方法 (今回の思いつき)

  1. gitでチェックインしておく
    • 元に戻せるように
  2. 二..四台目関連のフォームコンポーネントを削除
  3. IDEでビルド
    • 削除コンポーネント関連のエラーが出るので、削除していく
  4. 削除後ビルド
    • 実行できた
  5. gitで差分を見る
    • 関連関数のリストアップ
  6. gitで元に戻す
  7. 手順5でリストアップした処理を逐次コメントアウトしビルド・実行
    • エラーが出なくなる部分が問題箇所

問題の箇所

void __fastcall TXXXForm::SetTPanelPointers(TPanel *srcPtr, int DEVidx, int panelIndex)
{
    m_panelPointers[DEVidx][panelIndex] = srcPtr;
}

上記が問題。インデックスの範囲をチェックする実装がもれている。
加えて、下記の処理があるために、DEVidx=1以降でメモリ関連エラーが発生したということだった。

    SetTPanelPointers(P_DEV1_group1, /* DEVidx=*/ 0, /*panelIndex=*/ 0);
    SetTPanelPointers(P_DEV1_group2, /* DEVidx=*/ 0, /*panelIndex=*/ 1);
    SetTPanelPointers(P_DEV2_group1, /* DEVidx=*/ 1, /*panelIndex=*/ 0);
    SetTPanelPointers(P_DEV2_group2, /* DEVidx=*/ 1, /*panelIndex=*/ 1);
    SetTPanelPointers(P_DEV3_group1, /* DEVidx=*/ 2, /*panelIndex=*/ 0);
    SetTPanelPointers(P_DEV3_group2, /* DEVidx=*/ 2, /*panelIndex=*/ 1);
    SetTPanelPointers(P_DEV4_group1, /* DEVidx=*/ 3, /*panelIndex=*/ 0);
    SetTPanelPointers(P_DEV4_group2, /* DEVidx=*/ 3, /*panelIndex=*/ 1);

今後の予防策

SetTPanelPointers()内において「DEVidxの範囲外エラー」、「panelIndexの範囲外エラー」チェックを追加する。
範囲外エラー発生時にはデバッグウィンドウなりにエラーメッセージが表示されるようにする。

void __fastcall TXXXForm::SetTPanelPointers(TPanel *srcPtr, int DEVidx, int panelIndex)
{
    if (DEVidx > kNumDEV) {
        String msg = L"XXXUnit: Line985 > Error: [DEVidx] out of range";
        OutputDebugString(msg.c_str());
        return; // error
    }
    if (panelIndex > kNumPanel) {
        String msg = L"XXXUnit: Line990 > Error: [panelIndex] out of range";
        OutputDebugString(msg.c_str());
        return; // error
    }
    m_panelPointers[DEVidx][panelIndex] = srcPtr;
}

実際に実行すると、IDEにて下記の表示がされるようになった。

デバッグ出力
デバッグ出力: XXXUnit: Line985 > Error: [DEVidx] out of range プロセス XXX.exe (1364)
デバッグ出力: XXXUnit: Line985 > Error: [DEVidx] out of range プロセス XXX.exe (1364)
デバッグ出力: XXXUnit: Line985 > Error: [DEVidx] out of range プロセス XXX.exe (1364)
デバッグ出力: XXXUnit: Line985 > Error: [DEVidx] out of range プロセス XXX.exe (1364)

同じような失敗をしていそうなコードを探して対処する。

技術的負債

(追記 2017/10/06)

およそ700の関数のうちで13の関数で同じ失敗をしていた。
対策をしておいた。

将来的にstatic const int変数を変更時に発生する「技術的負債」を自分が作ってしまったのは残念ではある。
一つ一つの関数作成時にもっと集中して行わないといけない。

@nonbiri15 さんの品質は作りこまないかぎり実現できない
は金科玉条として胸に叩き込んでおいた方が良さそうです。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1