ループ内でのAccess Violation

[戻る]
米粒 2008/04/02(水) 13:14:16
こんにちわ。
ループの途中で突然変数のアドレスが変わってしまい、Access Violationが発生してしま
って困っています。

問題の関数は以下のような感じです。

環境:
VC++6.0
Windows 2000 Server SP4

int CClass_M::fnc_Search_Max()
{
    int    *pdt = m_SCData.m_SP_SPDATA; /* int    m_SP_SPDATA[2048 * 10]; 
*/

    int    idt_stp = (int)( m_SCData.m_SP_RW_STP/* 0.2 */ * 10.0);
    // データ間隔

    int    i_stp = 20 / idt_stp;
    int    i_mxp[MAX]; //MAX=100
    int    i_mxps = 0;
    int    i_dnn = 0;
    int    i_dnp = 0;
    int    i_dt0 = pdt[i_dnn];
    int    i_dt1;
    int    i_dtm = 0;
    int    i_df0 = 0;
    int    i_df1;
    int    i_dfs = 0;
    int i,j;
    int cnt_Rmax = 0;
    //=====ソート用ワーク
    struct person 
    {    int ix;
        int Rmax_data;
    };
    struct person temp[MAX],work;

    for(i=0;i<MAX;i++){
        i_mxp[i] =0;
    }
    while (i_dnn < m_SCData.m_SP_SPDATA_N/* データの数 */) {
        //i_dt1 = m_SCData.m_SP_SPDATA[i_dnn];
        i_dt1 = pdt[i_dnn];    /* ここで i_dnn = 4350 の時 
Access Violation */
        if (i_dt1 > i_dt0) {
            i_df1 = 1;
        } else if (i_dt1 < i_dt0) {
            i_df1 = 2;
        }else{ 
            i_df1 = 0;
        }
        if (i_dtm == 0) {
            if (i_df1 == 1) {
                i_dtm = 1;
                i_dfs = 1;
                i_dnp = i_dnn;
            }
        }else if (i_dtm == 1) {
            if (i_df1 == 1){
                if (i_df0 == 1){
                    i_dfs++;
                }
            }else{
                if (i_dfs > 2) {
                    i_dtm = 2;
                    i_dfs = 0;
                }else if ((i_df0 == 2) && (i_df1 == 2)) {
                    i_dtm = 2;
                    i_dfs = 0;
                }
            }
        }else{ 
            if (i_df1 == 2) {
                if (i_df0 == 2) {
                    i_dfs++;
                    if (i_dfs > 2) {
                        i_dt0 = i_dt1;
                        int    imaxi = i_dnn;
                        for (int ii=i_dnp; 
ii<i_dnn; ii++) {
                            if (i_dt0 < pdt
[ii]/*m_SCData.m_SP_SPDATA[ii]*/) {
                                i_dt0 
= pdt[ii]/*m_SCData.m_SP_SPDATA[ii]*/;
                                imaxi 
= ii;
                            }
                        }
                        i_mxp[i_mxps++] = imaxi;
            
                        i_dtm = i_dfs = 0;
                    }
                }
            }
        }

        i_dt0 = i_dt1;
        i_df0 = i_df1;
        i_dnn++;
    }

    /* 文字数制限に引っかかるので略 */

    return(0);
}


デバッガで変数をウォッチしていたところ、i_dnn = 4350 の所で Access Violation が
発生してしまいました。
Access Violation なので確保していないアドレスにアクセスしようとしているのはわか
るのですが、どうして突然ループの途中でi_dnn のアドレスが変更されてしまったのかが
わかりません。
何か可能性として考えられることがあればお教えください。
情報が足りなければできる範囲で提示します。
よろしくお願いします。

シャノン 2008/04/02(水) 13:35:55
詳細に検討してませんけど、ぱっと見、
> i_mxp[i_mxps++] = imaxi;
ここが怪しいような気がしました。
i_mxpsがMAXを超えていませんか?

PATIO 2008/04/02(水) 13:37:36
> デバッガで変数をウォッチしていたところ、i_dnn = 4350 の所で Access Violation が
> 発生してしまいました。
> Access Violation なので確保していないアドレスにアクセスしようとしているのはわか
> るのですが、どうして突然ループの途中でi_dnn のアドレスが変更されてしまったのかが
> わかりません。

書き間違いかもしれませんけれど、i_dnnのアドレスは変わっていないと思います。
変わったとしたらpdtがどこかの処理の影響で書き換わったと見るべきでしょう。
ただし、これに関してはデバッガで確認できるはずです。
最初にセットしてから変わったところがおかしいと言う見方は出来るのでは?
Access Violationがi_dnn = 4350のタイミングで出たからと言って
pdtが書き換えられたのがその直前とは限りません。
ですから、きちんと追跡しないと分からないのではないかと思います。
気になるのは、i_mxpが100しか確保されていない点。
この処理の中に100個で制限をするようなコードが見当たらないので
この状態だと何個でもセットに行きそうな気がするんですが、
データの中身の制限か何かでそうはならない保障があるんでしょうか。

米粒 2008/04/02(水) 13:56:40
シャノンさん
PATIOさん

回答ありがとうございます。
i_dnn = 4349 で止めてステップ実行してみたんですが、確かに

> i_mxp[i_mxps++] = imaxi;

ここでi_mxpsの値は102になっていました。
pdtの値もこの直後に変化していました。

> 気になるのは、i_mxpが100しか確保されていない点。
> この処理の中に100個で制限をするようなコードが見当たらないので
> この状態だと何個でもセットに行きそうな気がするんですが、
> データの中身の制限か何かでそうはならない保障があるんでしょうか。

だいぶ前に書かれたプログラムなので、どうしてi_mxpが100しか確保されていなかったの
かはわかりませんが、全体を見渡したところそうなる保障はないです。
だからこそAccess Violationが起きたんでしょうね。。。

100以下の制限を掛けるかMAXを十分な大きさにするかの処理を試してみます。

米粒 2008/04/02(水) 13:57:50
> 全体を見渡したところそうなる保障はないです。
すいません、「そう"ならない"保障」でした。

シャノン 2008/04/02(水) 14:10:25
簡単ですが一応解説。

今回のように「変数の値が意図せず書き換わる」ようなケースでは、真っ先に疑われるの
が「スタックの破壊」です。
スタック破壊の原因として多いのが
・memset 等を用いたメモリへの書き込み
・文字列の末尾を越えたアクセス
・配列の範囲外アクセス
です。

今回は、i_mxp がスタック上にあり、100 要素しか確保されていないにもかかわらず、そ
れを超えたアクセスをしているため、i_mxp の領域外にある変数の値が書き換わっていま
す。
アクセス違反が起きたとき、i_mxps は 102 だったということですが、i_mxp として正常
にアクセスできるのは i_mxp[ 99 ] までで、i_mxp[ 100 ] は i_stp、i_mxp[ 101 ] は 
idt_stp、そして i_mxp[ 102 ] が pdt と同じアドレスになっています。

米粒 2008/04/02(水) 14:36:19
[[解決]]
シャノンさん

解説ありがとうございます。
やっとスッキリしました。

MAXを1000に設定し、if文でMAXを超える配列のアクセスを制限したらうまく通りました。
また何かあるかもしれませんが、この件は解決とします。

ありがとうございました。

古いスレッドには追加発言できません。