« Linuxでシリアル通信 (cygwinでもできる) cuコマンド活用 | トップページ | C言語で作るシューティングゲーム »

2018年9月19日 (水)

C言語 厄介なバグ第一位 不定値のリード

SDL2でゲームを作っていたら突然謎の画面フラッシュが発生。

※C言語でありがちな、メモリ系の厄介なバグを久しぶりに見たので、ついでに記事にすることにしました。似たような自作ゲームを作っている人に、謎の現象に見舞われて困っているときの参考になればと思います。

※SDL2とはPCでゲームを作るときに便利なマルチメディアライブラリです。Androidに移植することができるなど柔軟性が高いです。日本ではDXライブラリが有名で、私も最初使っていましたが、あえて英語のドキュメントを読みながらトライしています。


バグの現象
プレイヤーと敵キャラの当たり判定を実装したあとしばらく触っていると、キャラクター同士が当たって爆発のアニメーションが終わった瞬間に、画面が黄色くフラッシュする事に気がついた。

頻度としては10回やると3、4回は出る。毎回必ずではないらしい。

解析
メインループをデバッガで止めて1フレームずつ回すと、黄色フラッシュの部分が捉えられる。背景の一部に横帯が入ったように黄色でベタ塗りされている。ただのチラツキだったらフレームが静止していたら出ないだろうから、この時点でライブラリの不具合やらビデオ性能起因のチラツキと言った外的な要因は消え、ロジックが原因であろう事がわかった。

Ws000038

ちらつきが発生した瞬間の画面の様子。
黄色帯の部分のピクセル数を調べることで、マップ表示に関連するところが悪さをしていないかを追いかけたり、意図せずこのサイズの長方形を描画しているところがないかを調べたりできる。

残念ながらこのサイズの長方形も、マップ表示との関連も見られなかった。
他に、キャラクタやマップ表示処理の中断や、ほかの描画要素との関連、タスクを制御している部分の暴走など色々仮説を立てて確認したが、当てはまらなかった。

※まずは色々なログを仕込み、その結果から問題箇所を推定する。と言う方法が思いつくのだが、のべつログを出していると何を見ていたのかを見失う事も多い。見るときは仮説を立てて、仮説一つにつきワンセットのログとした方が、出てきたログを解釈しやすい。

問題の現象を再現させる。

現象をなるべく確実に出す方法を作り、再現データを沢山用意する。
色々条件を変えてみて、どういう条件が揃った時に再現するか、というプロファイリングが重要になる。デバッガを使って再現時点の状態を記録、解析する。

再現時のタスクリストを一つずつ調べると、アニメーション機能が実装されているキャラクターオブジェクトの、どの絵を表示するかを決めるインデックスの値が、読み込んだ絵の枚数を越えていた。つまり意図しないアドレスの値、不定値を絵のパラメータに使っていた。ササッと絵を出そうとして書いたコードにろくでもないバグが入り込んでいたのだ。

メモリ境界を越える系統のバグは、不定値を読むことで発生する。100%再現する訳ではなく、毎日運用していて一年に一回だけとか、リリース直前になって突如噴火したりとか、どんなタイミングで出るかは誰も予想出来ない。今回はたまたま、ゲームと言う閉じた世界で、どのパラメータも頻繁に書き換えが起こるジャンルだったために、再現が容易で囲い込みやすかった。不幸中の幸いと言えるだろう。

マイコンでこういうバグに見舞われると、デバッガは使えないし、現象が出た瞬間のデータダンプも簡単ではない。不定値バグを仕込まないようにしっかりチェックするのが大事。


« Linuxでシリアル通信 (cygwinでもできる) cuコマンド活用 | トップページ | C言語で作るシューティングゲーム »

C言語」カテゴリの記事

コメント

コメントを書く

(ウェブ上には掲載しません)

トラックバック

この記事のトラックバックURL:
http://app.cocolog-nifty.com/t/trackback/518723/67185740

この記事へのトラックバック一覧です: C言語 厄介なバグ第一位 不定値のリード:

« Linuxでシリアル通信 (cygwinでもできる) cuコマンド活用 | トップページ | C言語で作るシューティングゲーム »