IT ニュース&コラム 2017/ 7/31 通巻743号 技術版 ソフトウェアデザイン館 Sage Plaisir 21  ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ̄ ■■ 人が死んだバグ、セラック25の事故から学ぶべき Nancy 教授の教訓 ■■ 2017年 7月、cpprefjp - C++日本語リファレンスの bool 型に対するインクリメント 演算子が C++17 から仕様から削除された理由を推測する文において、バグによって 3人が死亡した放射線被曝事故が紹介され、「人が死ぬバグ」としてツイートされた。 しかし、実際は、風が吹けば桶屋が儲かると揶揄されるように、因果関係はない。 bool 型に対するインクリメントのサンプルとして以下の C++14(2014年版 C++言語) のコードが挙げられている。 #include #include int main() {  std::vector v{};  //append elements to v  int8_t flag = 0; // as bool type  for ( auto&& i : v ) { // range-based for loops (for each)   if ( flag++ ) { std::cout << ','; }   std::cout << i << std::endl;  } } このコードは、for 文の中の if ( flag++ ) にバグを含んでいるらしい。 変数 v は、STL (Standard Template Library) による整数の配列である。 for 文のループ変数 i には、v の配列要素が入る。 なお、この for 文の書き方は、 range-based for loops という言語仕様であり、一般的には for each 文として 知られている。(一般に知られている for each というキーワードを使わないことに C++ の仕様策定者のセンスの無さを感じる)。 ここでは、STL とか for each とか、 配列の実装方法については関係ないので無視していい。 flag は 8ビット整数型(int8_t)であり、for 文の中でインクリメント(++演算子 によって、変数の値を+1)している。 if 文が真になる条件は、flag 変数を インクリメントする前の値が 0 以外のときである。 int8_t 型が扱える値の範囲は、 一般的な CPU では、-128 〜 +127 であり、+127 から +1 するとオーバーフローを 起こしてエラーもなく -128になる。 よって、最初(1回目)と 257回目と… (1 + 256 * n 回目)に、if 文が偽になる。 最初だけ if 文が偽になる仕様に対するコードであれば、このコードにはバグがある ということになるというわけだ。 ただし、1 + 256 * n 回目にコンマを出力しないという仕様であれば、バグではない のだが、一旦伏せておく。 問題は、コンマが出力されないために、前の出力値と結合した値が出力されて しまったことである。 たとえば、256回目の値が 123、257回目の値が 45 なら、256回目の値が 12345 という値に大きくなってしまい、おそらく放射線の出力が 100倍近く通常より大きい値になってしまったことで、死亡事故になったのだろう。 この死亡事故は、史上最悪のソフトウェア バグの1つとして知られている 1987年の「セラック25」という放射線治療装置の誤作動として知られている。 (本当にこのコードが原因であるかは不明) 当時は、C++言語は普及していなく、実際のコードはアセンブラで記述されていた。 当時の CPU は、インクリメント命令がよくあり、アセンブラの1命令で簡単に記述 でき高速に動作したのだろう。 ちなみに、現在の CPU は +1 や -1 だけ特別な命令 にはなっていないものも多くあり、高速でもない。 C言語の ++/-- 演算子は、この 古い CPU 仕様やその背景にある +1, -1 が多かったことから生まれているのだが、 現在では特に多いわけでもなく、for each が多く使われるので、たまに ++ が 書いてあって何だこれとなることがないように、Python のように += 1 のように 書くのがいい。 また、1が明示されていて読みやすい。 インクリメントの不具合から得られる再発防止策や教訓を考えるとすると、bool 型 (として扱う変数やレジスター)にはインクリメントしないようにしようとか、 オーバフローに気を付けようとか考えるのが一般的であろう。 ソフトウェアがよく 分からない人に説明するときは、この説明のほうが明快でいいだろう。 しかし、 実際はそんなに簡単なことではなく、再発防止にはつながらない。 なぜなら、 前述のとおり、1 + 256 * n 回目にコンマを出力しない(または、改行に変える) という仕様であれば、バグではないからだ。(よく分からない人には混乱を生む だけなので説明しないほうがいいだろう。 つまり、相手によっては、明快な説明 だけで不具合ゼロと自信をもって断言するのがよい。) バグであるかそうでないかは、内部実装だけでは決まらない。 外部仕様と違っているか どうかで決まるのである。 よく、プロセスが品質を上げると言っているが、プロセス という言葉からは内部実装や実務をイメージしがちであるので、内部実装だけ時間を かけてレビューしがちであるが、それは見当違いである。 もっと積極的に優先的に 外部仕様に関わるべきであるり、それゆえ、要求者は、外部仕様が神であると押し 付けてはならないし、実装者は、要求の変更を多少は受け入れを覚悟すべきである。 (ただし、開発の最終段階では Fix を優先し、次のバージョンで変更を反映する。) セラック25の事故を調査したマサチューセッツ工科大学の Nancy Leveson 教授は、 事故調査を終えて次のような教訓を書き残している。 まさに、バグであるかそう でないかは、内部実装の品質だけでは決まらないのである。 プログラミングの 教科書に是非とも載せるべき内容である。 ・ソフトウェアはどんなに慎重に作っても満足できるほどに完璧にはならないため、  ソフトウェアがどんな動きをしたときでも、人命に危険が及ばないようにシステム  を設計する必要がある(フェールセーフ、独立した安全装置の設置など) ・ソフトウェアの信頼性をできるだけ高めるのは悪いことではないが、それで  ソフトウェアが安全になるわけではない。プログラマは要求を満たすようにコード  を書くが、要求が正しいとは限らない。事故のほとんどは、プログラミングの  エラーではなく、要求が間違っていたり、不完全であったりしたために起きている ・われわれの目標は、だれもがこの経験を生かせるようにすることであり、装置の  メーカーや他の人を批判することではない。間違いは、このメーカーにだけ起きた  のではなく、残念ながら、安全が最優先されるべきその他のシステムにも、  きわめて日常的に起きている ・いくつかの出来事が複雑に絡み合って起きた事故が、一つの原因にされることが  多すぎる。ほとんどの事故は、システム事故、つまり、さまざまな構成部分や  機能が複雑に作用しあって起きるものだ。事故の原因を一つに特定することは、  大きな間違いだ。 セラック25の時代は、ソフトウェアのほうが劣化するハードウェアよりも信頼性が 高いと信じられていたため、実はソフトウェアは安全ではない、という感じで 書かれている。 現在では、ソフトウェアかハードウェアかは関係ない。 それぞれのレベルで独立したチェックすること、多重化することが重要なのである。 セラック20(25の前)では、時折ヒューズが飛んで結果的に事故を防いでいた。 しかし、ヒューズというハードウェアが重要なのではない。 放射線の出力を制御 する範囲を制限したり、放射線の出力を計測して警告するシステムを追加したり することが重要だ。 ヒューズは前者の1つの方法にすぎない。 TDD(テスト駆動開発)では、Nancy 教授の教訓を最優先に考慮している状況にある ため、開発コストの割には品質が高い。 要求の例がそのままテストのコードになる ため、要求の問題が見つけやすいからだ。 逆に、内部仕様やコードから要求に 合っていることを確認することは難しい。 私はこの内部仕様と要求にある性質を 「内包と外延のギャップ」と呼んでおり、そのギャップに矛盾がないこと(ギャップ を埋めること)をテストプログラムなどで実証し、その品質保証の範囲を現実的かつ 広くすることが品質向上のカギであると考えている。 内部仕様をいくら厳密に 長時間レビューしても、不具合ゼロという要求に対する悪魔の証明(ないことの証明) はできないので、現実的な範囲での実証が不具合ゼロの要求に対する現実解なのである。 (これを理解できない人には説明するだけ無駄なので、不具合ゼロと断言する。) 多重化したシステムの安全装置は、セルフ テストと呼ぶことがあるが、TDDで 品質を確保するために開発するテストとは異なる。 なぜなら、品質を上げるためには、 内包と外延のギャップを埋めなければならず、安全装置のコードは内包的定義で 記述され、テストは外延的定義で記述するから、全く別物だ。 つまり、安全装置が 何かのテストに相当するかもしれないが、安全装置自体のテストは別途必要だ。 また、多くの開発プロセスに見られるような、ユニット テストを先に完璧に仕上げれば、 後の工程から戻らないから効率的である、という主張は、誤りであることも、 Nancy 教授の教訓から言える。 事故のほとんどは要求の問題なので、スパイラル開発や、 スケルトンやプロトタイプを用いた結合テストやフィールド テストを早期に行うべき なのである。 そうしないと、ユニット テストが無駄になるので、非効率なのである。 ちなみに、IPA(独立行政法人情報処理推進機構)は、「大規模・複雑化した組込み システムのための障害診断手法」を発行しているが、最も重要である Nancy 教授の 教訓がない。 また、FTA/FMEA は、要因事象の発生頻度を集計してその重大事象の 発生頻度を計算する手法、つまり劣化するハードウェアの保守の話なのに、ソフト ウェアの問題を発見する手法であると見当違いなことを書いている。 単に現象には 原因があるだけのことなので、学ぶことは特にない。 対象が古いシステムから抜け 出せていないのではないだろうか。 マスコミの批判もそうだが、日本人は優先度 が低い古い価値観を無視できないために多くの無駄を生んでいるように見える。 https://cpprefjp.github.io/lang/cpp17/remove_deprecated_increment_of_bool.html http://ecompliance.co.jp/MedicalDevice/SW/Therac-25.html http://codezine.jp/article/detail/3699 http://qiita.com/rinse_/items/cdfce8aa6a685a8ebe0c http://www.ipa.go.jp/files/000045158.pdf http://www.geocities.jp/takaro_u/fta.html ■■ 注目ニュース 一覧 ■■ ◇ グーグルの2段階認証、SMSからプロンプト方式への移行を推奨。 https://japan.cnet.com/article/35104345/ http://gootara.org/library/2016/07/g2fa.html … 多くのアカウントを作成することの防止には使えるが、セキュリティ強化には使えないSMS。 ◇ Tesla車の事故は自動運転機能のせいではない。運転者が当初説明を撤回。 http://www.itmedia.co.jp/news/articles/1707/18/news063.html … Autopilot 機能を解除していたことを忘れたという新しい状態が危険なのでは。 ◇ 車載システム向けのUSB Power Deliverについて。 http://ednjapan.com/edn/articles/1707/25/news017.html … USB Type-C 対応 PC のように、USB Type-C 対応車と呼ぶ日が来る。 ◇ 家の戸締まりをLINEで確認できる leafee Premium の先行版が公開。 https://japan.cnet.com/article/35104094/ … IoT の端末の地位を狙う LINE。 ◇ Microsoft、Windows 10 の秋の更新で、ペイントのプリインストールは終了へ。 http://www.itmedia.co.jp/news/articles/1707/25/news050.html … ペイント 3D でも、2D 画像を編集できるため。 ◇ IDC Japan 国内3Dプリンティング市場予測。3Dプリンタ市場は終わったのか? http://techfactory.itmedia.co.jp/tf/articles/1707/28/news004.html … バブル期が終わって安定成長へ。 ■■ ソフトウェアデザイン館 Sage Plaisir 21 ■■ ホームページ >>> http://www.sage-p.com/ メルマガ >>> http://www.mag2.com/m/0000083983.html ブログ >>> http://blog.livedoor.jp/sage_p/ ツイッター >>> http://twitter.com/Ts_Neko ダウンロード >>> http://www.sage-p.com/freesoft.htm サポート掲示板 >>> http://www.sage-p.com/kg_ban09/z6037C8.cgi 東日本大震災 >>> http://www.sage-p.com/saigai.html メール >>> ts-neko◇sage-p.com ←◇を@に変えてください 緊急メールは件名に「うどんメール」を付けてください。 このメルマガの登録・解除 - http://www.mag2.com/m/0000083983.htm