バグ検出ドリル(9)デバッグの基本的な心構えは「人を見たら泥棒と思え」:山浦恒央の“くみこみ”な話(109)(4/4 ページ)
バグは至るところに、しかも堂々と潜んでおり、自信満々なプログラマーほど、目の前のバグに気付かないものです。「バグ検出ドリル」の第9回では、比較的大きなソースコードである迷路探索プログラムに潜むバグを見つけ出してください!
4.解答
今回のバグは、「フィールド(配列)の領域外を書き換えている」です。
本問題は、10×10マスのフィールド上で、キーボードを入力しながら、ゴールを目指すものです。フィールドの各マス目の表現方法は、変数field[10][10]の中に、「0」、「1」、「2」、「3」をセットします。今回の問題では、10×10マスの移動、つまりfield[0][0]〜field[9][9]の添え字ならば、何も問題は起こりません。しかし、field[0][7]に移動し、「↑」キーを押すと、以下の画面が現れます(図2)。
図2は、field[0][7]にいるときに、「↑」キーを押した場合の実行結果です。これは、配列field[-1][7]という「迷路の領域外」にアクセスし、値を「2」に書き換えたため発生しました。このバグを防ぐには、配列field[0][7]の中身を「0」にせず、「1」か「3」にする必要があります。
配列に関連するバグは、かなり多く発生します。例えば、以下のような場合です。
- 配列の領域外にアクセスした。
- 配列の領域外を書き換えた。
- バッファーがオーバーフローを起こした。
上記のようなバグが発生しないよう、注意深くプログラムを作成する必要があります。また、プログラム解析ツールやコンパイラのオプションを使って、問題がありそうな箇所をあらかじめあぶりだすことも有効です※1)。バグを見つけた場合、デバッガを活用し、変数の値を見ながら、ステップ実行すると原因究明が容易になります。
また、使用するデータをミスなく入力することも大事です。例えば、次のケースが問題となり、注意が必要です。
- データベースに入力するCSVファイルなどに間違いがあった※2)
- プログラムの各種パラメータに間違った値を入力した※3)
※1)C言語には、Valgrindという動的解析ツールがあります。詳細は、本連載第98回『タダでソフト開発の生産性と品質を上げる方法(8):メモリリークを一瞬で見つける「Valgrind」(その1)』をご覧ください。
※2)筆者は、かつて小規模なショッピングサイトのシステム移行の手伝いをしたことがあります。新ソフトにするに当たって、顧客データと商品データを新しいデータ構造にマッチするように整形する必要がありました。一通り、Excelを使ってデータを整形し、データを入力しました。その後、顧客に確認をしたもらったところ、「あるはずのデータがない」「データにありえない値がある」とクレームが入りました。原因は、筆者のデータ編集ミスが原因でした。
※3)数値演算中心のソフトウェアの場合は、外部パラメータのバグに悩むことがあります。例えば、電気、物理の計算で使う係数値は、通常のプログラマーには判別困難です。
5.自己採点シート
ここまで読んで、一回も「???」とならなかった方は、マイナス20点です。上記で示した解決策、すなわち、「配列field[0][7]の中身を『0』にせず、『1』か『3』にする」は、ロジックではなく、データを変更して、領域外アクセスを防止しています。表面的にはこれで解決しますが、良い子はこんな修正をしてはいけません。きちんとロジックを修正しましょう。
今回の迷路のデータを見ると、[0,7]以外は、フェンスで囲み、進行不可に設定してあります。設計者の意図が、「迷路は『1』で囲んであるため、領域外アクセスは起きない」であれば、その旨を仕様書に記述しなければなりません。その場合、迷路データにバグがあることになります。また、仕様書にそう記述してあっても、「迷路は必ず『1』で囲ってある」と信じてはいけません。データにエラーがあり座標が領域外をアクセスする場合を考慮し、「塀の外へ行く矢印記号を無効にする」及び「最初に、迷路が『1』で囲まれていることをチェックする」必要があります。
「解答」が正しいとは限りません。自分の論理的思考に照らし、あらゆる場所に潜んでいるバグを見つけましょう。
今回の自己採点シートを下記に示します。
問題 | 内容 | 配点(点) |
---|---|---|
迷路探索プログラム | 問題文を一通り読んだ | 20 |
ソースコードを一通り読んだ | 20 | |
デバッグをした | 20 | |
配列の領域外にアクセスするバグを発見した | 20 | |
バグを修正する場合、データの修正ではなく、ロジックの修正をした | 20 | |
その他のバグを見つけた | 5×件数 | |
リスト3 自己採点シート |
6.終わりに
今回は、迷路探索プログラムのバグを探す問題を出題しました。いつもより量はありましたが、バグを見つけることはできたでしょうか。また、「解答」にだまされなかったでしょうか。
配列の領域外アクセスや書き換えは、不可解なバグの原因となります。また、データ定義のバグも、頭を悩ませる原因の1つです。このようなバグを作り込まないように注意したいですね。
過去の記事でも同じことですが、筆者が想定できていないバグも残っていると思われます。「このプログラムには必ずバグがある。バグを見つける!」との意気込みで見ていただけると、意外なバグを見つけられるでしょう。
東海大学 大学院 組込み技術研究科 非常勤講師(工学博士)
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
- ≫連載「山浦恒央の“くみこみ”な話」バックナンバー
- バグ検出ドリル(8)電卓プログラムのような小さなプログラムにもバグがいる
学生プログラミングの課題となるような小さいプログラムでもバグが潜んでいます。「バグ検出ドリル」の第8回では、学生が5分で書けるような電卓プログラムに潜むバグを見つけ出してください! - バグ検出ドリル(7)やっぱり、いろんなところにバグがいる!
重要顧客の前でデモを行う際にバグが発生すると大変です。顧客だけでなく、自社の社長まで同席していたいたときなどは、さらにものすごく焦るのではないでしょうか。「バグ検出ドリル」の第7回では、そんな状況を想定しつつ、いろんなところに潜むバグを見つけ出してください! - バグ検出ドリル(6)いろんなところにバグがいる! 2分探索法の問題
「バグ検出ドリル」の第6回で出題するのは「2分探索法」の問題です。ソフトウェア技術者の誰もが心得ておくべき常識的なアルゴリズムである2分探索法ですが、今回の問題では、いろんなところにバグがあります。問題文から、どこにバグがありそうか見つけ出してみよう! - バグ検出ドリル(5)「小さな親切、大きなお世話」な問題
「バグ検出ドリル」の第5回で出題するのは「思い込み」にまつわるバグの問題です。タイトルの「小さな親切、大きなお世話」とは一体何なのでしょうか。問題文から、どこにバグがありそうか見つけ出してみよう! - バグ検出ドリル(4)プログラミングの素質を試すのに最適!? FizzBuzz問題に挑戦
「バグ検出ドリル」の第4回で出題するのは、プログラミングの素質を試すのに最適といわれる伝説の「FizzBuzz問題」。問題文から、どこにバグがありそうか見つけ出してみよう!