バグ検出ドリル(13)のたうち回る地獄、煮詰まったバグを解決せよ山浦恒央の“くみこみ”な話(113)(3/3 ページ)

» 2018年12月25日 10時00分 公開
前のページへ 1|2|3       

4.今回の解答

 バグの原因は、「バッファオーバーランによるメモリ破壊」です※2)。以下、詳細を解説します。

※2)バッファオーバーランは、確保しているデータ領域を超えて、隣接するデータ領域を書き換えてしまうバグです。バッファオーバーフローとか、「爆撃」とも呼びます。

 本プログラムは、「examdata.txt」をカンマ区切りで読み出し、コンソールに表示するプログラムです。「YAMADA YUYA」と「YAMAMOTO AOI」の理科(science)のデータが正しく表示できていません。正しく表示できない原因は、ソースコードの以下の部分です。

//生徒の名前を取得する
strcpy(name[no],token);
リスト4 ソースコード内の正しく表示できない原因

 strcpy関数は、nameにtokenの文字列をコピーする関数です。名前の変数は、name[N][15]」と宣言してあります。つまり、名前は14文字までしか入力できません。3人目のデータ「WATANABE SHUICHIRO」は、18文字あり、strcpy関数を使用してしまうと、領域外の場所にデータを上書きする可能性があります。今回の場合は、メモリ上にnameの次のアドレスに理科のデータ(science)が入っており、その部分まで上書きしています。つまり、メモリ内は以下の表1のようになっており、理科のデータが壊れています※3)

表1 表1 「WATANABE SHUICHIRO」を入力したときのメモリ内の状態(クリックで拡大)

※3)今回の問題は、お手持ちの環境によっては動作が一致しない可能性があります。今回は、CygwinのGCC 7.3.0を使用しています。

 1人目の「YAMADA YUYA」の理科の点数が70ではなく、79となっているのは、3人目のデータのアルファベットの「O」をコピーしているためです。コンソールへの表示は、10進数表記ですから、アルファベットの「O」は、ASCIIコードで「4F」で、「4F」を10進に変換すると「79」になります。

 2人目の「YAMAMOTO AOI」の理科の点数が0となっているのは、3人目のデータの末尾「'\0'」が入っているためです。「\0」は、ASCIIコードで0を表すので、コンソールには数字の「0」が出ます。

 このバグのトリッキーなところは、生徒の名前が「渡辺一郎」なら正常に表示し、「渡辺秀一郎」なら表示不正になる点です。最初の動作確認テストで、「渡辺一郎」をテストデータにしていれば「たまたま」正常動作し、プログラム作成者のAさんは「このプログラムでOK」と思ったはずです。で、実際のデータに「渡辺秀一郎」があると、メモリ破壊が発生し、渡辺秀一郎と関係がない生徒のデータが壊れます。この現象から「渡辺秀一郎のアルファベットの文字数が多いことが原因となり、他者のメモリを破壊した」とは思い付かないでしょう。OSのバグや、ハードウェアの不良まで疑い、Aさんは煮詰まってしまいます。

 さらに、「渡辺太一郎(ワタナベタイチロウ)」と「渡辺秀一郎」の場合では、データの壊れ方が異なりますし、テストで「松本明子(マツモトアキコ)」を使い、実際のデータに「松本吉彦(マツモトヨシヒコ)」が入っている場合、「2人の名前の漢字の文字数は同じで、性別が違う」とミスリードの要素が増え、「名前のアルファベットの文字数が多く、バッファを破壊した」という原因特定に至りません。バグと無関係の場所に異常現象が現れるバグは、タチが悪く、原因究明に時間がかかります※4)

 上記のバグを引き起こさないためには、「配列nameの領域を増やす」「領域内までしかコピーしない」などの対策をせねばなりません。strcpy関数の使用方法を誤るとバグにつながるので、注意が必要です。

※4)連載「山浦恒央の”くみこみ”な話」の第64回、「クイズ!! バグはどこだ? 〜ちょっと休憩して、バグ探しに挑戦〜」では、ミスリードが非常に多く、バグの解決に時間がかかったケースとして、筆者の体験談を取り上げました。

5.自己採点シート

 今回の自己採点シートを以下に示します。

問題 内容 配点(点)
テストデータ表示プログラム 問題文を一通り読んだ 50
バッファオーバーランのバグであると推察できた 50
リスト6 自己採点シート

6.終わりに

 今回は、バッファオーバーランのバグを仕込んだ、テストデータ表示プログラムを出題しました。皆さんは、バグを見つけることができたでしょうか。バッファオーバーランは、関係のない場所に異常が現れる「タチの悪いバグ」だと思います。筆者も、プログラムが想定通りにいかないことがありました。「おかしいなぁ」と数時間悩み、あらゆる場所にprintf関数を仕掛け、バッファオーバーランを見つけた経験があります。

 組み込みソフトの開発では、メモリ領域を参照したり、書き換えたりすることが多くあります。メモリの領域を誤って書き換えると、プログラムは通常では考えられない不可解な動作をします。筆者のように、煮詰まって苦労する前にバッファオーバーランを見つける嗅覚を備えていただければと思います。

【 筆者紹介 】
山浦 恒央(やまうら つねお)

東海大学 大学院 組込み技術研究科 非常勤講師(工学博士)


1977年、日立ソフトウェアエンジニアリングに入社、2006年より、東海大学情報理工学部ソフトウェア開発工学科助教授、2007年より、同大学大学院組込み技術研究科准教授、2016年より非常勤講師。

主な著書・訳書は、「Advances in Computers」 (Academic Press社、共著)、「ピープルウエア 第2版」「ソフトウェアテスト技法」「実践的プログラムテスト入門」「デスマーチ 第2版」「ソフトウエア開発プロフェッショナル」(以上、日経BP社、共訳)、「ソフトウエア開発 55の真実と10のウソ」「初めて学ぶソフトウエアメトリクス」(以上、日経BP社、翻訳)。


前のページへ 1|2|3       

Copyright © ITmedia, Inc. All Rights Reserved.