多くの危険に満ちている"C言語",安全に使うためにはコーディング・ガイドラインが不可欠
世の中は「モデリングだ!」,「UMLだ!」とにぎやかで,「コードはもう自動生成の時代だ!」という話もあります.しかし,大多数の現場では,現在も人がコードを書いてがんばっています.そして人がやる以上,必ずミスを作り込みます.特にあのC言語ときたら! 開発者の一人であるKen Thompson先生が「もともとエイプリル・フールの冗談で作ったら,広まっちゃって困った」とおっしゃったという噂注1は,本当なのでしょうか?
1989年から1990年にかけてANSIやISOで規格化され,いくぶんかはましになったとはいえ,C言語はいまだに多くの危険に満ちている,ということに反論する人はいないでしょう注2.
注2:それは,裏を返せば柔軟でなんでも書けてしまうという,プログラマにとって楽しい側面でもあるわけだが.... |
図1は,経済産業省による組み込みソフトウェアの不具合発生工程に関する2006年の調査結果です.グラフ左下の,「ソフトウェア実装・単体テスト」に関わる不具合が,全体の3割近くを占めています.
図2は同様の調査で,2010年の報告内容です.やはり実装以降の工程で,実装にかかわる不具合が大きな割合を占めていることが分かります.これら実装に起因する不具合が,すべてC言語の危険性によるものとは言えませんが,無視できない割合で原因になっているであろうことは,実際に使用されているみなさんにとっては想像に難くないでしょう.なんとか,C言語の持つ危険性を避け,不具合を誘発しないようにする施策が必要です.
●自動車などの高信頼が要求される装置の開発に学ぼう
自動車に代表される高信頼が求められるシステムへも,マイコンの導入は進んでいます.このような装置では,不具合が人の生死に直結する場合があります.さまざまな不具合防止策が考えられ,その中でC言語による実装については,MISRA(Motor Industry Software Reliability Association)注3という団体が,特に車載ソフトウェアの移植性や信頼性,安全性を確保することを目的に,危険な記述をしないためのルール集を作りました.1998年のことです.これをMISRA-C(ミスラ・シー)といいます.
注3:MISRAは英国に本部のある,非営利の団体.インファント島ではない(それはモスラ). |
その後2004年に,自動車に限らず高信頼を必要とする装置に向けて「クリティカルなシステムでC言語を使うためのガイドライン」として,第2版を発行しています注4.
注4:MISRA-C 2004は,C90をベースにしている.発行からすでに8年が経過し,また市場のコンパイラの多くがC99準拠になっていることもあり,現在改版が進められている. |
MISRA-C 2004には141個のルールが定めてあります.ルールが好きな人などあまりいないと思いますが,141個の数に閉口される方も多いでしょう.しかし,もともと実際の開発事例をもとに検討してできたものなので,読んでみると突飛なものはありません.だいたい,「誰でもやってしまうミス」は同じなのです.
141個のルールは,121個の「必須」項目と,20個の「推奨」項目でできています.なにが違うかというと,ルールを逸脱するときの手続きが違います.必須項目は,逸脱するときに組織的な逸脱のルールに従わなければなりません.推奨項目はそこまでは求めず,プログラマの裁量にまかされていて,「まぁ,なるべくなら従っておいたほうがいいよ」ということになっています.実際の運用では,両方の区別なしに,組織できちんと検討して,別途,ルールを作って運用しないと混乱のもとになります.
例えばこんな例があります.MISRA-Cのルール6.3では,
基本型の代わりに,サイズと符号属性(signedness)を示す typedef を使用しなければならない.
と規定しています.推奨ルールではあるのですが,これを守るには,組織で別の型名を定義して統一する必要があります.推奨だからと個人の裁量にまかせてしまうと,レビューもできない見た目がバラバラのコードができてしまうことになるからです.
このような記述ルールを運用する上でなによりも大切なのは,ただやみくもにルールを遵守するのではなく,「なぜそのルールを守らないといけないのか」といった,背景を理解しておくことです.これを行えば,暗記しなくても自然にルールが身に付きますし,技術力の向上にもつながります.MISRA-Cは,単に「暗記するべきルール集」ではなく,「先人たちの知恵の結晶」と思って読むのがよいでしょう.
●「逸脱ルール」は組織で決める
話は前後しますが,「逸脱」という言葉が出てきました.「え? 守らなくてもいい場合があるの!?」と思ったあなたは正解です.はい,守らない方がいいときは守らなくてよいのです.ただし! ここが大切ですが,守らない方がいいかどうかを,コーディングしているあなたが勝手に判断してはいけません.その判断が正しいかどうか,誰も保証できないからです.必ず,組織で決めた「逸脱ルール」に従って,レビューなどを行う必要があります.もちろん,そのときはエビデンスを残すことも忘れずに行いましょう.組織での検討では,「逸脱」として削除するばかりでなく,ルールを拡張することも積極的に行うとよいです.例えばルール16.8には,
戻り値の型が非 void の関数の場合,すべての出口で,式を持つ明示的な return 文を記述しなければならない.
と書いてあります.void 型関数では,別に return を書かなくても間違いではないですが,ここはルールを拡張して,
void 型の関数では,式のない return 文を記述して,出口を明示する.
と,してみてはどうでしょう.こうすると,文面通りに処理の終了を明示できますし,作りかけで忘れていた,などというトラブルを回避することもできます.
今や高信頼が不要な組み込みシステム開発は存在しません.「MISRA-Cって,車載向けの話でしょう?」と言わず,C言語でコーディングしている人は,ぜひ一度は熟読しておくことをお薦めします.
たち・のぶゆき
組み込みソフトウェア・エンジニア