ページ 11

Debug実行時は問題なくRelease実行時にエラー

Posted: 2014年3月19日(水) 22:08
by EKISUKE
件名どおりなのですが、Debug実行時は問題はなく、Release実行時にエラーが出る場合考えられる原因を教えてください。
エラーの詳細はRelease実行時にnullptrを代入した変数がどこかでnullptrじゃなくなりアクセス違反になるというものです。
プロジェクトは大きいので書ききれないのですが、アクセス違反になったコード部分を記載します。

コード:


//-----------------------------------------------------------------------------
//! 更新
//-----------------------------------------------------------------------------
void SystemScene::update()
{
	// 次のシーンへのジャンプリクエストがある場合は切り替える
	if( _pNextScene ) {

		// 同じタイプのシーンを取得
		_pScene = getSameTypeScene(*_pNextScene);
		// なければ
		if( _pScene == nullptr ) {
			// 新規作成
			_pScene = (SceneBase*)_pNextScene->createInstance();
			// スタック情報作成
			StackData*	stack = new StackData();
			stack->_pScene    = _pScene;
			stack->_typeData  = (Type*)_pNextScene;
			// スタックする
			_pSceneStack.push_back(stack);
		}
		// メモリ確保できていたら
		if( _pScene != nullptr ) {
			// 初期化
			if( _pScene->init() == false ) {
				// 失敗したら削除
				_pScene->cleanup();
				GM_RELEASE(_pScene);
			}
		}
		_pNextScene = nullptr;	// リクエストを消す
	}

	//-------------------------------------------------------------
	// 更新
	//-------------------------------------------------------------
	if( _pScene ) {
		_pScene->update();
	}
}

シーン遷移システムのプログラムで_pNextSceneというのはゲーム中に次に飛びたいシーンを指定した場合その次のリクエスト情報が入ります
その情報をシーンをスタックしているリストの中から検索して、あればそのシーンを使い、なければ新しく作成してリストに追加するというものです。

このプログラムの

コード:

_pScene = getSameTypeScene(*_pNextScene);
という部分でクラッシュしてしまいます。原因は_pNextSceneにnullptrを入れているのですが、

コード:

if( _pScene ) {
		_pScene->update();
}
この部分で_pNextSceneに適当なポインタがはいり、次にループ時に適当クラッシュしてしまいます。
_pNextSceneはprivate変数で変更するための関数はありますが、その部分を呼んでいる気配はなかったです。

この場合考えられる原因があれば教えていただけないでしょうか。
こういったクラッシュの仕方は初めてで調べていますが、まだ原因がうまくつかめていません。
思いつくことがありましたら、回答お願いいたします。

開発環境 : windows7 visual studio 2010 C++

再現率 : Releaseなら100%

Re: Debug実行時は問題なくRelease実行時にエラー

Posted: 2014年3月19日(水) 23:08
by softya(ソフト屋)
様々な要因が考えられます。
ポインタの管理ミスや配列の添字の範囲外などです。
ReleaseとDebugでメモリでの変数の配置が変わるため表面化することは良くあります。

デバッガでReleaseビルドだとトレースが困難だと思いますがデータブレークしてみるのも方法です。
それでもダメなら、printfデバッグ法などで書き換わる瞬間を追い詰めるとか、添字チェックを全コードに入れるなどが必要です。

Re: Debug実行時は問題なくRelease実行時にエラー

Posted: 2014年3月19日(水) 23:50
by EKISUKE
>>softyaさん
回答ありがとうございます。
データブレイクというのは始めて聞きました。勉強になります。
追加質問で申し訳ないのですが、3つ質問があります。

① データブレイクというのはこのサイト(http://www.platinumgames.co.jp/programmer_blog/?p=165)の「データブレークポイント」ですか?
② データブレイクというのはデータが変更された瞬間にブレークするという認識で大丈夫ですかね。
③printfデバッグ法のprintfの代わりにこのサイト(http://marupeke296.com/DBG_No3_OutputDebugWindow.html)の実装したマクロでも代用できますか?

③についてですが、なぜprintfの代わりに使うのかと言いますと、今作っているプロジェクトの設定のサブシステムがWINDOWSなのでprintfの出力は出力ウィンドウに出ると思っていたのですが、出なかったためです。

Re: Debug実行時は問題なくRelease実行時にエラー

Posted: 2014年3月19日(水) 23:54
by softya(ソフト屋)
全部あっています。そういう感じです。

あと黒いコンソールウィンドウをサブウィンドウとして出すことも出来ます。
「簡単RPG講座 番外編。 デバッグ入門 • C言語交流フォーラム ~ mixC++ ~」
http://dixq.net/forum/blog.php?u=114&b=982&c=2

Re: Debug実行時は問題なくRelease実行時にエラー

Posted: 2014年3月20日(木) 00:20
by EKISUKE
>>softyaさん
回答ありがとうございます。

デバッグ方法を教えていただいてありがとうございます。
根気よく見ていきます。

Re: Debug実行時は問題なくRelease実行時にエラー

Posted: 2014年3月20日(木) 15:08
by EKISUKE
>>softyaさん
原因判明しました!

原因は以下コードでした

コード:

//-----------------------------------------------------------------------------
//! 分割距離の更新
//-----------------------------------------------------------------------------
void CascadedShadow::updateSplitDist(f32 nd, f32 fd)
{
	f32	lambda  = _split_weight;
	f32	ratio   = fd/nd;
	f[0]._neard = nd;

	for( s32 i=0; i<SPLIT_COUNT; i++ )
	{
		f32 si = i / (f32)SPLIT_COUNT;

		f[i]._neard  = lambda*(nd*powf(ratio,si)) + (1-lambda)*(nd + (fd - nd)*si);
		f[i-1]._fard = f[i]._neard * 1.005f;
	}
	f[SPLIT_COUNT-1]._fard = fd;
}

これはカスケードシャドウの視錐台を分割し、近クリップ面と遠クリップ面を求める関数です。
その中の

コード:

f32 si = i / (f32)SPLIT_COUNT;
この部分で0を割っていました。
s32(signed int) i = 0からfor文を開始していたためでした。
なので

この部分を
[code = Cpp]
for( s32 i=0; i<SPLIT_COUNT; i++ )
[/code]

以下のように変更したところ解決しました。
[code = Cpp]
for( s32 i=1; i<SPLIT_COUNT; i++ )
[/code]
このコードはnvidiaのカスケードシャドウのコードを参考にしていたところで、参考にしていたコードと見比べてみたら修正後と同じようにしてありました。

データブレークポイントは本当に強力ですね。本当に勉強になりました。ありがとうございます。

Re: Debug実行時は問題なくRelease実行時にエラー

Posted: 2014年3月20日(木) 17:36
by ISLe
EKISUKE さんが書きました:この部分で0を割っていました。
s32(signed int) i = 0からfor文を開始していたためでした。
0『で』割ることは問題ですが、0『を』割ることは何の問題もありません。

問題は15行目でf[-1]に書き込んでいることですね。

Re: Debug実行時は問題なくRelease実行時にエラー

Posted: 2014年3月20日(木) 18:25
by EKISUKE
>>ISLeさん
そうでした、指摘ありがとうございます。
単純なことでしたね。Debugではたまたまf[-1]でもメモリが取れていたんですね。

Re: Debug実行時は問題なくRelease実行時にエラー

Posted: 2014年3月20日(木) 19:11
by ISLe
デバッグビルドだと、不正なアクセスを検出しやすいように、初期値のない変数が特定の値で埋められたり、メモリが連続しないようにあいだをあけて配置されたりします。

そういうのを検出するツールがあります。
たいてい高価なものですが。