関数から抜けるだけでエラーが発生します(通常ではあり得ない?)

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
smly
記事: 7
登録日時: 10年前

関数から抜けるだけでエラーが発生します(通常ではあり得ない?)

#1

投稿記事 by smly » 10年前

いつもお世話になっております。
DXライブラリを使用したゲームを作成しているのですが、どうしても理解できないエラーが発生するためご教示願いたく書き込み致します。

ゲームのメインループ内から、ある関数を呼び出した際、その関数を抜けメインループ内に戻る時に
「ハンドルされない例外が 0x0109B028 (xxxxx.exe) で発生しました: 0xC0000005: 場所 0x0109B028 の実行中にアクセス違反が発生しました。」
(位置: xxxxx.exe!WinMainCRTStartup() 行 164)

という例外が発生します。(デバッグをVisualStudioのDebugモードで実行した場合です)

プロジェクトが大きく全体を公開することができないため一部だけの公開になり、あまり参考にならないかもしれませんが、下に該当箇所のコードを示します。
(loadScenario関数は、メインループからこんな関数が呼ばれますよ、という程度で実行時にはエラー無くこの関数の最後まで実行される、ということだけご理解頂けたら良いかと思います。長いですしこの関数だけで完結する処理でないので。)

メインループにてloadScenario()に入り、loadScenario()の最後の行からメインループに戻る際に上記のエラーが発生します。

また、VisualStudioのReleaseモードでデバッグを行った場合は、メインループからloadScenario()に入り、loadScenario()から抜け出す際にエラーは発生しませんが、
呼び出し元と異なる位置に戻されてしまいます。(メインループ内の全く見当違いの行にジャンプします)
また、loadScenario()の戻り値をvoidでなくintに変更しても同様の問題が発生しました。

こういった問題は何故発生するのでしょうか。
関数はエラーなく最終行まで行けば、当然呼び出し元にエラーなく戻るものだと思っているのですが…
せめて解決の手がかりを頂ければと思います。

宜しくお願いします。

(main.cpp)メインループ内

コード:

if(CheckHitKey(KEY_INPUT_F9) && clickedF9 == 0){
    clickedF9 = 1;
    loadScenario(); // ← ここで問題の関数を呼び出します
    user_execute_command = 1;
    break;
}
(savedata_load.cpp)のloadScenario関数

コード:

void loadScenario(){

	//cmdInitimage(NULL);

	//データのロードサンプル
	FILE *fin;
	static SaveData SD;
	static int j;
	int decode_img;

	savedata_loading_flg = 1;

	fin = fopen("./save/save1.data", "rb");
	
	fread(&SD, sizeof(SD), 1, fin);
	fclose(fin);

	decode_img = CreateGraphFromMem(SD.thumbnail, sizeof(SD.thumbnail));
	//DrawGraph(0, 0, decode_img, FALSE);

	script.filename = SD.scenario_file;
	strcpy(last_loaded_script_file, SD.scenario_file);
	
	memcpy(g_message_backlog, SD.backlog_message, sizeof(g_message_backlog));
	memcpy(g_message_backlog_icon, SD.backlog_message_icon, sizeof(g_message_backlog_icon));


	InitGraph();
	for(int i = 0; i < GRAPHIC_MAX_NUM; i++){
		g_graphicManager[i].id = 0;
		g_graphicManager[i].graphicHandle = 0;
		strcpy(g_graphicManager[i].graphicName, "");
	}


	//マクロ読み込み履歴をリセット
	for(int i = 0; i < 10; i++){
		strcpy(loaded_macro_file[i], "");
	}


	//マクロを再ロード
	for(j = 0; j < 10 && SD.loaded_macro_file[j][0] != '\0'; j++){
		c = setjmp(jmpbuf1);//@returnタグの戻り先
		if(c == 0){
			loadMacroForCharArg(SD.loaded_macro_file[j]);
			longjmp(jmpbuf2, 1);//シナリオメインループの先頭へジャンプ
		}else{
			c = 0;//@returnタグが出現したらここへ
		}
		
	} //この時点でgraphicManagerが上書きされる

	//上書きされたgraphicManagerを元にvisibleGraphicを復元する
	memcpy(g_visibleGraphic, SD.g_visibleGraphic, sizeof(g_visibleGraphic));
	//visibleGraphicと同名ファイルを持つgraphicManagerのハンドルを取得する

	for(int j = 0; j < GRAPHIC_MAX_NUM; j++){
		for( int k = 0; k < VISIBLE_GRAPHIC_MAX_NUM; k++){
			if(g_graphicManager[j].graphicName != NULL && g_graphicManager[j].graphicName != "" && g_visibleGraphic[k].graphicName != NULL && g_visibleGraphic[k].graphicName != ""){
				if(strcmp(g_graphicManager[j].graphicName, g_visibleGraphic[k].graphicName) == 0){
					g_visibleGraphic[k].graphicHandle = g_graphicManager[j].graphicHandle;
					break;
				}
			}
		}
	}

	//未実装
	//memcpy(g_visibleFace, SD.g_visibleFace, sizeof(g_visibleFace));
	//memcpy(g_bgGraphicManager, SD.g_bgGraphicManager, sizeof(g_bgGraphicManager));

	script.currentLine = SD.current_line;

	savedata_loading_flg = 0;

}

beatle
記事: 1281
登録日時: 12年前
住所: 埼玉
連絡を取る:

Re: 関数から抜けるだけでエラーが発生します(通常ではあり得ない?)

#2

投稿記事 by beatle » 10年前

setjmp/longjmpは本当に使う必要ありますか?
できるだけ避けるのが懸命です.

それでも使うなら,いろいろ注意点があります.
例えば現在のソースコードではsetjmpの戻り値をcに代入していますが,ダメです.
[迷信] setjmp マクロの返却値は変数に代入できる

smly
記事: 7
登録日時: 10年前

Re: 関数から抜けるだけでエラーが発生します(通常ではあり得ない?)

#3

投稿記事 by smly » 10年前

beatle様

ありがとうございます。
構造が複雑なので、可能であればsetjmp/longjmpを使いたいという思いがあります。
これを使うと、使わなかった場合に比べ格段に読みやすくなるので…
このsetjmpの使い方は間違っていたのですね。
ただ、ご紹介いただいたURLに記載のあるようにsetjmpの戻り値を変数に格納せずswitch文にて判定を行うように変更しましたが、
問題が解決しないままの状態です。
せめてsetjmp/longjmpが原因のエラーである、ということだけでも判れば良いのですが、使用しない場合の書き換え箇所が非常に多いため、逆に問題の特定が困難になってしまいそうです。

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

Re: 関数から抜けるだけでエラーが発生します(通常ではあり得ない?)

#4

投稿記事 by h2so5 » 10年前

jmpbuf2 に対してはどこでsetjmpしているのでしょうか。

smly
記事: 7
登録日時: 10年前

Re: 関数から抜けるだけでエラーが発生します(通常ではあり得ない?)

#5

投稿記事 by smly » 10年前

h2so5 さんが書きました:jmpbuf2 に対してはどこでsetjmpしているのでしょうか。
jmpbuf2に対しては、メインループの先頭にて setjmp(jmpbuf2); をしています。
毎ループごとにsetjmpされますが、少なくとも longjmpされる前には必ずsetjmp(jmpbuf2)されるので問題はないだろうという認識です。

beatle
記事: 1281
登録日時: 12年前
住所: 埼玉
連絡を取る:

Re: 関数から抜けるだけでエラーが発生します(通常ではあり得ない?)

#6

投稿記事 by beatle » 10年前

longjmpで戻ると対応するsetjmp呼び出しの直後に飛ぶわけですが,
その時点でローカル変数の値は未定義ですので利用してはいけません.
そこは大丈夫でしょうか?

例えば
longjmp(jmpbuf1);
によって
setjmp(jmpbuf1);
に戻ると,fin, SD, j, decode_imgの値は使えなくなります.

直後memcpyでSDを使っているように見えるので,ご注意ください.

アバター
softya(ソフト屋)
副管理人
記事: 11677
登録日時: 13年前
住所: 東海地方
連絡を取る:

Re: 関数から抜けるだけでエラーが発生します(通常ではあり得ない?)

#7

投稿記事 by softya(ソフト屋) » 10年前

longjmpの私の教訓は、エラー処理以外に便利に使うとろくな目に合わない。
「Super Technique 講座~longjmpと例外」
http://www.nurs.or.jp/~sug/soft/super/longjmp.htm
少なくとも関数間のgoto代わりに使うものではないと言うことです。
by softya(ソフト屋) 方針:私は仕組み・考え方を理解して欲しいので直接的なコードを回答することはまれですので、すぐコードがほしい方はその旨をご明記下さい。私以外の方と交代したいと思います(代わりの方がいる保証は出来かねます)。

閉鎖

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