Stack around the variable 'fn' was corruptedというデバッグエラーがでます

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
アバター
MoNoQLoREATOR
記事: 284
登録日時: 13年前
住所: 東京

Stack around the variable 'fn' was corruptedというデバッグエラーがでます

#1

投稿記事 by MoNoQLoREATOR » 12年前

VisualC++2008にて下記ソースコードを実行すると、

@デバッグなし
Run-Time Check Failure #2 - Stack around the variable 'fn' was corrupted.
@デバッグあり
Run-Time Check Failure #2 - Stack around the variable 'ck' was corrupted.

というデバッグエラーが出ます。
ソースコードは、STGのリプレイのためのデータを保存・読み込みするという内容です。

コード:

#include "DxLib.h"
#include <fstream>
#include <vector>
#include <bitset>

using namespace std;

enum{TITLE, SAVE, REPLAY};
enum{KEY_Z, KEY_X, KEY_C, KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_ENTER, KEY_NUM};

struct KeyData{
	bool key[8];
};

int gSta;	//・・・・・・・・タイトル画面・リプレイデータ保存画面・リプレイ画面のどれが現在の画面かを示す	
bool menu;								//タイトル画面で リプレイデータ保存・リプレイ のどちらを選ん[だ/でいる]かを示す
char key[256];//・・・・・・・すべてのキーの押下状態を記憶する
int keyTrig;								//連続キー入力を無効にする
int arrow;//・・・・・・・・・矢印画像のハンドルを記憶
char keyLog[KEY_NUM];		//1つ前のフレームのキーの押下状態を記憶
int frameCou;							//タイトル画面から移行した後、現在何フレーム目かを示す
int nextChArr;	//・・・・・・chTime,chKey の何番目の要素を次回に取り出せばよいかを示す
vector<int> chTime;					//何フレーム目にキー状態の変更があったかを記憶
vector<KeyData> chKey;		//・・・キーが変更された時のキー状態を記憶

int x, y;	//矢印画像の座標を記憶
int gh;	//自機画像のハンドルを記憶

int bomCou;	//ボム用

void ReOpenFile(ofstream &, int);	//書き込み時、1回でファイルが開けなかった場合3回までトライ
void ReReadFile(ifstream &, int);		//読み込み時、以下同文
void KeyInit();	//キー状態のログを変数に記憶させる関数

int WINAPI WinMain(HINSTANCE hI, HINSTANCE hP, LPSTR lpC, int nC){
	ChangeWindowMode(TRUE);
	SetOutApplicationLogValidFlag(FALSE);
	if(DxLib_Init() == -1) return(-1);
	SetDrawScreen(DX_SCREEN_BACK);

	//画像読み込み
	arrow = LoadGraph("media\\arrow.PNG");
	gh = LoadGraph("media\\me.PNG");


	while(ProcessMessage() == 0 && CheckHitKey(KEY_INPUT_ESCAPE) == 0){
        ClsDrawScreen();
		GetHitKeyStateAll(key);	//全てのキー状態を取得
		if(keyTrig) --keyTrig;		//連続キー入力の無効期間を減少

		switch(gSta){

			//タイトル画面の処理
			case TITLE:

				//↑キー又は↓キーが押されたら選択しているモードをもう一方のものにする
				if(keyTrig==0){
					if(key[KEY_INPUT_UP] || key[KEY_INPUT_DOWN]){
						menu = !menu;
						keyTrig = 15;
					}
				}

				//選択肢、矢印の描画
				SetFontSize(32);
				{
					int fx = 320-GetDrawStringWidth("リプレイデータ作成",18)/2;
					DrawString(fx,240-32, "リプレイデータ作成", GetColor(0,255,0) );
					DrawString(fx,240, "リプレイ", GetColor(0,255,0) );
					DrawGraph(fx-32,240-32+32*menu, arrow, TRUE);
				}

				//上下矢印キー以外のキーが押されていたら選択されたモードに移る
				{
					int num = 0;
					for(int i=0;i<256;++i) num += key[i];
					if(num-key[KEY_INPUT_UP]-key[KEY_INPUT_DOWN] && keyTrig==0){
						//上下矢印キー以外のキーが押されており、連続キー入力でない場合の処理
						gSta = SAVE+menu;		//選択されたモードに移るようにする

						//データの初期化
						for(int i=0;i<8;++i) keyLog[i]=0;
						frameCou=0;
						nextChArr=0;
						x=0, y=0;
						bomCou=0;
						keyTrig = 15;

						//リプレイモードが選択された場合
						if(menu){
							//リプレイデータの読み込み
							ifstream ifs("ReplayData.dat", ios::binary);	//ファイルをバイナリモードで開く
							if(!ifs) ReReadFile(ifs, 0);							//開けなかったら3回までリトライ

							//ファイルが開けたら
							if(!ifs==0){
								while(TRUE){
									{
										//「キー状態が変更されたフレーム」の情報を取得して記憶
										int fn;

										ifs.read( (char *)&fn, sizeof(int) );
										chTime.push_back(fn);
									}
									{
										char ck;
										int nowP;

										{
											KeyData kd;

											//「どのキーの状態が変更されたか」の情報を取得して記憶
											ifs.read(&ck, sizeof(kd.key) );

											memcpy(&kd.key[0], &ck, sizeof(kd.key) );
											chKey.push_back(kd);
										}

										//ファイルの終端に達していればwhile文から脱出
										nowP = ifs.tellg();	//現在の場所を記憶
										ifs.seekg(0, fstream::end);	//ファイルの終端に移動
										if(nowP>=ifs.tellg() ) break;	//while文から脱出
										else{
											//読み取る位置を元に戻す
											ifs.clear();
											ifs.seekg(nowP);
										}
									}
								}
							}
							//↑ファイルが開けたら
						}

						//リプレイデータ保存モードが選択された場合リプレイデータを空にする
						else{
							ofstream ofs("ReplayData.dat");
							if(!ofs) ReOpenFile(ofs, 0);
						}
					}
				}

				break;

			//リプレイデータ保存画面の処理
			case SAVE:
				{
					//キー状態を確認
					bool changed = FALSE;	//どのキーも変更されていない設定にする

					//以前のキー状態と比較して、違っていればキーが変更されている設定にする
					if(keyLog[KEY_Z] != key[KEY_INPUT_Z]) changed = TRUE;
					if(keyLog[KEY_X] != key[KEY_INPUT_X]) changed = TRUE;
					if(keyLog[KEY_C] != key[KEY_INPUT_C]) changed = TRUE;
					if(keyLog[KEY_UP] != key[KEY_INPUT_UP]) changed = TRUE;
					if(keyLog[KEY_DOWN] != key[KEY_INPUT_DOWN]) changed = TRUE;
					if(keyLog[KEY_LEFT] != key[KEY_INPUT_LEFT]) changed = TRUE;
					if(keyLog[KEY_RIGHT] != key[KEY_INPUT_RIGHT]) changed = TRUE;
					if(key[KEY_INPUT_RETURN] && keyTrig==0) changed = TRUE;

					KeyInit();	//キー状態のログを残す

					//キー状態が変更されていれば、フレーム数と共に保存
					if(changed == TRUE){
						ofstream ofs("ReplayData.dat", ios::binary | ios::app);
						if(!ofs) ReOpenFile(ofs, 0);
						if(!ofs == 0){
							//データ処理
							KeyData kd;
							kd.key[0] = (key[KEY_INPUT_Z]==1);
							kd.key[1] = (key[KEY_INPUT_X]==1);
							kd.key[2] = (key[KEY_INPUT_C]==1);
							kd.key[3] = (key[KEY_INPUT_UP]==1);
							kd.key[4] = (key[KEY_INPUT_DOWN]==1);
							kd.key[5] = (key[KEY_INPUT_LEFT]==1);
							kd.key[6] = (key[KEY_INPUT_RIGHT]==1);
							kd.key[7] = (key[KEY_INPUT_RETURN]==1);

							//書き込み
							ofs.write( (char *)&frameCou, sizeof(int) );
							ofs.write( (char *)&kd.key[0] , sizeof(kd.key) );
						}
					}
				}

			//↓↓ switch文から脱出せずに下の処理へ ↓↓

			//キー状態に応じた処理
			case REPLAY:

				{
					bool endFlag = 0;

					//リプレイ画面固有の処理。キー状態を改ざんして、リプレイデータと同期させる
					//変更があったフレームならばキー状態を変更する
					if(gSta==REPLAY){
						if(frameCou==chTime[nextChArr]) ++nextChArr;

						key[KEY_INPUT_Z] = chKey[nextChArr+(-1)*(nextChArr!=0)].key[KEY_Z]*(nextChArr!=0);
						key[KEY_INPUT_X] = chKey[nextChArr+(-1)*(nextChArr!=0)].key[KEY_X]*(nextChArr!=0);
						key[KEY_INPUT_C] = chKey[nextChArr+(-1)*(nextChArr!=0)].key[KEY_C]*(nextChArr!=0);
						key[KEY_INPUT_UP] = chKey[nextChArr+(-1)*(nextChArr!=0)].key[KEY_UP]*(nextChArr!=0);
						key[KEY_INPUT_DOWN] = chKey[nextChArr+(-1)*(nextChArr!=0)].key[KEY_DOWN]*(nextChArr!=0);
						key[KEY_INPUT_LEFT] = chKey[nextChArr+(-1)*(nextChArr!=0)].key[KEY_LEFT]*(nextChArr!=0);
						key[KEY_INPUT_RIGHT] = chKey[nextChArr+(-1)*(nextChArr!=0)].key[KEY_RIGHT]*(nextChArr!=0);
						key[KEY_INPUT_RETURN] = chKey[nextChArr+(-1)*(nextChArr!=0)].key[KEY_ENTER]*(nextChArr!=0);

						if(chKey[nextChArr-1].key[KEY_ENTER]) endFlag = TRUE;	//エンターキーが押されていたら問答無用で終了
					}

					//エンターキーが押されていたらタイトル画面に戻る
					if( (key[KEY_INPUT_RETURN] && keyTrig==0) || endFlag){
						gSta = TITLE;
						keyTrig = 15;
					}
				}

				//矢印キーの状態に応じて自機の座標をいじる
				x += (10-5*key[KEY_INPUT_X])*key[KEY_INPUT_RIGHT] -(10-5*key[KEY_INPUT_X])*key[KEY_INPUT_LEFT];
				y += (10-5*key[KEY_INPUT_X])*key[KEY_INPUT_DOWN] -(10-5*key[KEY_INPUT_X])*key[KEY_INPUT_UP];

				//ボムの処理
				if(bomCou==0){if(key[KEY_INPUT_C]) bomCou = 255;}
				else --bomCou;
				SetDrawBlendMode(DX_BLENDMODE_ALPHA, bomCou);
				if(bomCou) DrawCircle(x+16,y+16, 255-bomCou, GetColor(255,255,255), TRUE);
				SetDrawBlendMode(DX_BLENDMODE_NOBLEND, 0);
				
				DrawGraph(x,y, gh, TRUE);		//自機描画

				break;
		}

		++frameCou;

		ScreenFlip();
	}
	DxLib_End();
	return(0);
}


void ReOpenFile(ofstream &ofs, int num){
	ofs.open("ReplayData.dat", ios::binary | ios::app);
	++num;
	if(!ofs){
		if(num<3) ReOpenFile(ofs, num);
	}
}

void ReReadFile(ifstream &ifs, int num){
	ifs.open("ReplayData.dat", ios::binary);
	++num;
	if(!ifs){
		if(num<3) ReReadFile(ifs, num);
	}
}

void KeyInit(){
				//キー状態のログを残す
				keyLog[KEY_Z] = key[KEY_INPUT_Z];
				keyLog[KEY_X] = key[KEY_INPUT_X];
				keyLog[KEY_C] = key[KEY_INPUT_C];
				keyLog[KEY_UP] = key[KEY_INPUT_UP];
				keyLog[KEY_DOWN] = key[KEY_INPUT_DOWN];
				keyLog[KEY_LEFT] = key[KEY_INPUT_LEFT];
				keyLog[KEY_RIGHT] = key[KEY_INPUT_RIGHT];
}

原因・解決方法がわかる方、よろしくお願いいたします。
また、デバッグ方法もぜひ教えてください。

アバター
h2so5
副管理人
記事: 2212
登録日時: 13年前
住所: 東京
連絡を取る:

Re: Stack around the variable 'fn' was corruptedというデバッグエラーがで

#2

投稿記事 by h2so5 » 12年前

原因は、sizeof(bool) ≠ sizeof(char) だからです。
バッファオーバーランしていると思われます。

追記:念のため
115行目の

コード:

memcpy(&kd.key[0], &ck, sizeof(kd.key) );
ここです。

デバッグ方法というか、ググればバッファオーバーランが原因で出ることの多いメッセージだとすぐ分かりますので、
バッファオーバーランしそうな箇所を調べればいいと思います。

アバター
a5ua
記事: 199
登録日時: 13年前

Re: Stack around the variable 'fn' was corruptedというデバッグエラーがで

#3

投稿記事 by a5ua » 12年前

h2so5さんの指摘した箇所とは別に、
nextChArr == 0 の状態で、207行目の処理が行われているため、範囲外アクセスが生じています。

アバター
MoNoQLoREATOR
記事: 284
登録日時: 13年前
住所: 東京

Re: Stack around the variable 'fn' was corruptedというデバッグエラーがで

#4

投稿記事 by MoNoQLoREATOR » 12年前

>> h2so5さん
ありがとうございます。解決しました。

>>a5uaさん
ありがとうございます。気づきませんでした^^;

閉鎖

“C言語何でも質問掲示板” へ戻る