使用可能なコーディング標準

コーディング標準は多数存在しますが、広く使われているものは僅かです。MISRA C[2]は、自動車産業ソフトウェア信頼性協会(Motor Industry Software Reliability Association)が開発したCプログラミング言語用のソフトウェア開発標準です。その目的は、組込みシステム、具体的にはISO Cでプログラムされたシステムに関わるコードの安全性、移植性、信頼性を向上させることにあります。

MISRA C標準の初版「Guidelines for the use of the C language in vehicle-based software」(車載用ソフトウェアにおけるC言語使用のガイドライン)は1998年に作成され、正式にはMISRA C:1998として知られています。2004年と2012年に更新され、規則が追加されました。C++ 2003に基づくMISRA C++ 2008標準もあります。

MITREのCWE(Common Weakness Enumeration:共通脆弱性タイプ一覧)[3]にも、優れたコーディングのための標準的な規則がいくつか示されています。このリストは、開発者が誤ってコードに組込んでしまう欠陥を明らかにするために、mitre.orgが行った調査によって作成されたものです。ウェブ、アプリ、デスクトップ、組込みなどの別を問わず、意外にもあらゆるタイプのコード開発者が同じような誤りを犯す傾向にありました。

このようにして、開発者が避けるべき一般的な落とし穴のリストとしてCWEは生まれました。リストには、例えば、C++コード(もしくはCコード)における解放なしでのメモリの確保が挙げられています。また、プロトタイプ宣言なしで使われる関数も同様で、これは優れたコーディング手法という点で興味深い問題です。関数のプロトタイプ宣言をしなければコンパイル時に厳密なタイプチェックが行われませんが、C言語の規則によるとプロトタイプ宣言をしないとすべての引数が整数に拡張され、コードの効率が低下することもあります。この場合、MCUにFPUがなければ、キャスティングと浮動小数演算が呼び出される可能性があります。これが、常にプロトタイプ宣言が必要となる理由です。しかし、CWEの重要なポイントは、リスキーなコーディングや不適切なコーディングの性質を識別できることにあります。

SEI CERT CおよびC++[4]も、領域外書き込みに関する浮動小数のチェックや、定数オーバーライドがないことの確認など、ケーススタディから得られた一般的な脆弱性を定義しています。また、コードをより読みやすく、理解しやすくするためのスタイリング規約も定めています。

MISRA C 2012の実例

MISRA C 2012は、組込みアプリケーションにおけるコード品質を確保するために広く使われています。以下では、これらのコーディング標準がソースコードに与える影響について理解を深めるために、いくつかの規則と指針を見ていきます。

例えば、指針4.6はプリミティブデータ型の使用を禁じています。これは一見すると奇妙に思えるかもしれませんが、その理由を理解すれば納得がいくはずです。コンパイラが違えば、例えば整数のサイズや符号属性などの扱いも異なります。このためコードのレビューに細心の注意を要することもあります。レビュアーとしてコードを見た場合、これは、コード作成者がコンパイラのコード解釈方法を理解しているのかどうかを疑問に感じる要因にもなります。プリミティブ型を使わなければ、コンパイラやアーキテクチャが変わってもコードが影響を受けることはありません。

ほとんどの場合、開発者はuint16_tのような型を使用します。このような型はその幅や符号属性を変数型で明示的に示しているので、その変数が符号なしの16ビットであることはコンパイラに明確に伝わります。これらはstdint.hの一部です。

また、規則13も興味深い指針で、これはANDまたはOR演算子の右側に副作用を含めることはできないと定めています。図2に示すコード例はまったく正しいものに見えますが、実はそうではありません。

  • MISRA C 2012 - 規則13のコード例

    図2 – MISRA C 2012 - 規則13のコード例

問題は、式の左側が偽の場合のみ右側が実行されるという点です。その場合だけポインタpがポストインクリメントされます。問題となるのはコード記述時にこの動作を間違えやすいという点で、コードのレビュー、テスト、メンテナンスを行うすべての人は、コードの記述方法によって生じる予期せぬ影響を理解しておく必要があります。このコードセクションにあるコメントが助けになるのは明らかですが、実際にはその内容が適切に記述されていることは稀です。

また別の良い例が規則14で、ifステートメントまたはwhileステートメントは本体部分を中カッコで囲まなければならないとしています。図3のコード例にこの例を示します。

  • MISRA C 2012 - 規則14のコード例

    図3 – MISRA C 2012 - 規則14のコード例

z=1ステートメントがelseブロックの一部を構成するものかどうかは、判断が難しいところです。このような問題が生じるのは、直前のステートメントと同じレベルにインデントされているからです。もしそのように意図されているのであれば、このコードブロックが意図したように動作しないことは明らかなので、これはバグです。規則14はこの種のコーディングエラーを防ぎます。これは、コードの信頼性と移植性を向上させることによって将来にわたり有効な設計を保証するためにMISRA Cに定められた、200以上ある規則のごく一部です。