UCameraShakeBase::RootShakePattern の有効性チェックについて

お世話になっております。

UCameraShakeBase::IsFinished() 内の RootShakePattern->IsFinished() でクラッシュすることがあったのでコードを確認してみたのですが、RootShakePattern は UCameraShakeBase::SetRootShakePattern() で外部から設定される可能性があるため、有効性チェックを厳密に行う必要があるように思いました。

UCameraShakeBase の中で何箇所か RootShakePattern が参照されていますが、例えば UCameraShakeBase::IsFinished() であれば以下のように IsValid() で有効性をチェックする必要があるのではないかと思いましたがいかがでしょうか?

bool UCameraShakeBase::IsFinished() const
{
	// ★ 修正前のコード
	//if (RootShakePattern)
	// ★ 修正後のコード
	if (IsValid(RootShakePattern))
	{
		// Ask the root pattern whether it's finished.
		return RootShakePattern->IsFinished();
	}
	else
	{
		// We have no root pattern, we don't have anything to do.
		return true;
	}
}

​以上、お手数をおかけしますがご確認頂けますでしょうか。

よろしくお願いいたします。​

お世話になっております。

ご指摘ありがとうございます。

確かに SetRootShakePattern() という Public Setter が存在する以上、外部から渡されたオブジェクトのライフタイムを完全にコントロールすることは難しく、if (A) のようなチェックを if (IsValid(A)) に書き直すことで、より堅牢なコードになりえるというご指摘はもっともかと存じます。

一方、 IsValid() が通常の null チェックに対して追加で防御できる場面は、MarkAsGarbage() 等でガベージマークされた後・GC 回収前という限られた期間になります。この期間をオブジェクトのライフタイムの一部とみなすか、ライフタイムが尽きた後とみなすかは難しいところですが、この期間中であってもオブジェクトへのアクセス自体は安全に行えることが望ましいです。

開発チームの中でも IsValid() の使用範囲については議論があり、もう少し詳細な状況をお聞かせ願えますと、当方としても変更を提起しやすくなります。 UCameraShakeBase のサブクラスにおいて、GC改修前(Destroy)の時点でアクセスがクラッシュを引き起こすような内部状態の変化がかかっていた、ということになりますでしょうか?

以上よろしくお願いいたします。

お世話になっております。

ご確認頂きありがとうございます。

返答が遅くなりまして申し訳ありません。

実は手元ではクラッシュは再現出来ておらず、他のスタッフの環境で稀に発生する状況なのですが、試しに RootShakePattern にアクセスしている UCameraShakeBase 内の全ての箇所で IsValid() を入れたところ症状は解消されたようです。

ゲーム側のコードを調査してみるとおっしゃる通り SetRootShakePattern() に渡したオブジェクトに対して MarkAsGarbage() や ConditionalBeginDestroy() を行っている箇所がありました。

おそらくその関係で、破棄したオブジェクトに対し UCameraShakeBase がアクセスしてしまうタイミングが発生していたのかなと思います。

> IsValid() が通常の null チェックに対して追加で防御できる場面は、MarkAsGarbage() 等でガベージマークされた後・GC 回収前という限られた期間になります

> 開発チームの中でも IsValid() の使用範囲については議論があり

確かにこちらはその通りですね。

IsValid() でチェックすることで多少堅牢にはなると思いますが、ゲーム側の運用で回避できる問題なので、今回はこういう事例があったということだけ共有させて頂ければと思います。

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

ご確認およびクラッシュの詳細について情報提供ありがとうございます!

本件につきましては、このような事例があったことを当方においても社内で共有させていただきます。

また、もし当該箇所におきまして抑制困難なクラッシュに遭遇した際はお知らせください。

それでは本件は回答済みとして、Closeさせていただきます。

以上、よろしくお願いいたします。