DCL12-C. 抽象データ型は opaque な型を使って実装する
抽象データ型はオブジェクト指向言語であるC++やJavaに限られたものではなく、C言語でも、作成し使用されるべきものである。抽象データ型が最も効果を発揮するのは、プライベート(opaque)データ型や情報の隠ぺいを実現するときである。
違反コード
以下のコード例は CERT が開発した managed string library に基づく。[Burch 2006]この例では、managed string 型およびこの型に対して演算を行う関数が、以下に示す string_m.h
ヘッダファイルで定義されている。
struct string_mx { size_t size; size_t maxsize; unsigned char strtype; char *cstr; }; typedef struct string_mx string_mx; /* 関数宣言 */ extern errno_t strcpy_m(string_mx *s1, const string_mx *s2); extern errno_t strcat_m(string_mx *s1, const string_mx *s2); /* etc. */
string_mx
型の実装は、string_m.h
をインクルード後であれば、そのデータ型のユーザに完全に見えてしまう。そうすると、プログラマが構造体のフィールドを直接操作するということはおおいにありそうだ。その結果、ソフトウェアエンジニアリングの原則であるデータの隠ぺいやデータのカプセル化に違反することになり、間違った、移植性のないコードを開発する可能性が高まる。
適合コード
以下の適合コードは、string_mx
型をプライベート型として実装しなおしており、managed string library の利用者からデータ型の実装が見えないように隠している。これを実現するために、プライベートデータ型のディベロッパは 2 つのヘッダファイルを作成している。ひとつは外部の string_m.h
ヘッダファイルであり、これはデータ型のユーザがインクルードする。もうひとつの内部のヘッダファイルは、managed string 抽象データ型を実装するファイルの中だけでインクルードされている。
外部の string_m.h
ヘッダファイルの中では、string_mx
型は struct string_mx
のインスタンスになるものとして定義されており、これは不完全型として宣言されている。
struct string_mx; typedef struct string_mx string_mx; /* 関数宣言 */ extern errno_t strcpy_m(string_mx *s1, const string_mx *s2); extern errno_t strcat_m(string_mx *s1, const string_mx *s2); /* etc. */
内部のヘッダファイルでは、struct string_mx
は完全に定義されているが、この抽象化データはユーザには見えない。
struct string_mx { size_t size; size_t maxsize; unsigned char strtype; char *cstr; };
この抽象データ型を実装するモジュールは、外部定義と内部定義の両方をインクルードする。一方、この抽象データ型を使うユーザは、外部定義である string_m.h
のみをインクルードする。こうすることで、 string_mx
データ型をプライベートのままにすることができる。
リスク評価
opaque な抽象データ型を使用することは、セキュアプログラミングに必須ではないが、特に継続するコードのメンテナンスの過程でコードに入り込む欠陥や脆弱性の数を大幅に減らすことにつながるだろう。
レコメンデーション |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
DCL12-C |
低 |
低 |
高 |
P1 |
L3 |
自動検出(最新の情報はこちら)
ツール |
バージョン |
チェッカー |
説明 |
---|---|---|---|
LDRA tool suite |
V. 8.5.4 |
352 S |
実装済み |
参考資料
[Burch 2006] |
翻訳元
これは以下のページを翻訳したものです。
DCL12-C. Implement abstract data types using opaque types (revision 51)