こんにちわ。
ループの途中で突然変数のアドレスが変わってしまい、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 のアドレスが変更されてしまったのかが
わかりません。
何か可能性として考えられることがあればお教えください。
情報が足りなければできる範囲で提示します。
よろしくお願いします。
詳細に検討してませんけど、ぱっと見、
> i_mxp[i_mxps++] = imaxi;
ここが怪しいような気がしました。
i_mxpsがMAXを超えていませんか?
> デバッガで変数をウォッチしていたところ、i_dnn = 4350 の所で Access Violation が
> 発生してしまいました。
> Access Violation なので確保していないアドレスにアクセスしようとしているのはわか
> るのですが、どうして突然ループの途中でi_dnn のアドレスが変更されてしまったのかが
> わかりません。
書き間違いかもしれませんけれど、i_dnnのアドレスは変わっていないと思います。
変わったとしたらpdtがどこかの処理の影響で書き換わったと見るべきでしょう。
ただし、これに関してはデバッガで確認できるはずです。
最初にセットしてから変わったところがおかしいと言う見方は出来るのでは?
Access Violationがi_dnn = 4350のタイミングで出たからと言って
pdtが書き換えられたのがその直前とは限りません。
ですから、きちんと追跡しないと分からないのではないかと思います。
気になるのは、i_mxpが100しか確保されていない点。
この処理の中に100個で制限をするようなコードが見当たらないので
この状態だと何個でもセットに行きそうな気がするんですが、
データの中身の制限か何かでそうはならない保障があるんでしょうか。
シャノンさん
PATIOさん
回答ありがとうございます。
i_dnn = 4349 で止めてステップ実行してみたんですが、確かに
> i_mxp[i_mxps++] = imaxi;
ここでi_mxpsの値は102になっていました。
pdtの値もこの直後に変化していました。
> 気になるのは、i_mxpが100しか確保されていない点。
> この処理の中に100個で制限をするようなコードが見当たらないので
> この状態だと何個でもセットに行きそうな気がするんですが、
> データの中身の制限か何かでそうはならない保障があるんでしょうか。
だいぶ前に書かれたプログラムなので、どうしてi_mxpが100しか確保されていなかったの
かはわかりませんが、全体を見渡したところそうなる保障はないです。
だからこそAccess Violationが起きたんでしょうね。。。
100以下の制限を掛けるかMAXを十分な大きさにするかの処理を試してみます。
> 全体を見渡したところそうなる保障はないです。
すいません、「そうならない保障」でした。
簡単ですが一応解説。
今回のように「変数の値が意図せず書き換わる」ようなケースでは、真っ先に疑われるの
が「スタックの破壊」です。
スタック破壊の原因として多いのが
・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 と同じアドレスになっています。
シャノンさん
解説ありがとうございます。
やっとスッキリしました。
MAXを1000に設定し、if文でMAXを超える配列のアクセスを制限したらうまく通りました。
また何かあるかもしれませんが、この件は解決とします。
ありがとうございました。