メインコンテンツ

CERT C: Rec.DCL12-C

抽象データ型は不透明な型を使用して実装する

説明

ルール定義

抽象データ型は不透明な型を使用して実装します。1

Polyspace 実装

ルール チェッカーは、"構造体または共用体オブジェクトへのポインターがデリファレンスされないファイル内で、このオブジェクトの実装が可視" をチェックします。

すべて展開する

問題

この問題は、構造体または共用体へのポインターが翻訳単位内でデリファレンスされないが、オブジェクトの実装が非表示でない場合に発生します。

ファイル内か、ファイルにインクルードされているヘッダー ファイル内で構造体または共用体が定義されていて、そのファイル内でこの構造体または共用体へのポインターが宣言されているが、そのポインターがデリファレンスされることがない場合、チェッカーはコーディング ルール違反にフラグを設定します。構造体または共用体の定義は、このファイルに対して可視であってはなりません。

構造体定義に関するこのルールの違反が表示された場合、同じファイル内か、そのファイルにインクルードされているヘッダー ファイル内でその構造体へのポインターを定義したかどうかを特定します。次に、ファイル内のどこかでポインターをデリファレンスしているかどうかをチェックします。ポインターをデリファレンスしていない場合、構造体定義はこのファイルから隠し、ヘッダー ファイルに含めなければなりません。

file.h:構造体実装が含まれています。

#ifndef TYPE_GUARD
#define TYPE_GUARD

typedef struct  {                                               
  int a;                                                    
} myStruct; 

#endif

file.c:file.h をインクルードしますが、構造体をデリファレンスしません。

#include "file.h"

myStruct* getObj(void);
void useObj(myStruct*);

void func() {
  myStruct *sPtr = getObj();
  useObj(sPtr);
}

この例では、myStruct 型へのポインターがデリファレンスされません。このポインターは単純に関数 getObj から取得され、関数 useObj に渡されます。

myStruct の実装は、file.cfile.h から構成された翻訳単位内で可視化されています。

1 つの修正方法として、ヘッダー ファイル file.h 内で不透明なデータ型を定義します。不透明なデータ型 ptrMyStruct は、構造体の内容を明らかにすることなく myStruct 構造体を指します。構造体 myStruct 自体は別の翻訳単位内で定義することができます。この場合、これはファイル file2.c で構成されます。構造体の定義を不透明な型の定義にリンクするために、共通のヘッダー ファイル file.hfile.c および file2.c の両方にインクルードしなければなりません。

file.h:構造体実装が含まれていません。

#ifndef TYPE_GUARD
#define TYPE_GUARD

typedef struct myStruct *ptrMyStruct; 

ptrMyStruct getObj(void);
void useObj(ptrMyStruct);

#endif

file.c:file.h をインクルードしますが、構造体をデリファレンスしません。

#include "file.h"

void func() {
  ptrMyStruct sPtr = getObj();
  useObj(sPtr);
}

file2.c:file.h をインクルードし、構造体をデリファレンスします。

#include "file.h"

struct myStruct {                                               
  int a;                                                    
};

void useObj(ptrMyStruct ptr) {
    (ptr->a)++;
}

リスク

構造体または共用体へのポインターがファイル内でデリファレンスされない場合、その構造体または共用体の実装の詳細をそのファイルの翻訳単位内で使用できるようにする必要はありません。構造体メンバーなどの実装の詳細を隠蔽し、意図されていない変更からそれらを保護することができます。

ポインターを介して参照できるがその内容にはアクセスできない不透明な型を定義します。

例 - 明らかにされたオブジェクト実装

file.h:構造体実装が含まれています。

#ifndef TYPE_GUARD
#define TYPE_GUARD

typedef struct  {  //Noncompliant                                             
  int a;                                                    
} myStruct; 

#endif

file.c:file.h をインクルードしますが、構造体をデリファレンスしません。

#include "file.h"

myStruct* getObj(void);
void useObj(myStruct*);

void func() {
  myStruct *sPtr = getObj();
  useObj(sPtr);
}

この例では、myStruct 型へのポインターがデリファレンスされません。このポインターは単純に関数 getObj から取得され、関数 useObj に渡されます。

myStruct の実装は、file.cfile.h から構成された翻訳単位内で可視化されています。

修正 — 不透明な型を定義

1 つの修正方法として、ヘッダー ファイル file.h 内で不透明なデータ型を定義します。不透明なデータ型 ptrMyStruct は、構造体の内容を明らかにすることなく myStruct 構造体を指します。構造体 myStruct 自体は別の翻訳単位内で定義することができます。この場合、これはファイル file2.c で構成されます。構造体の定義を不透明な型の定義にリンクするために、共通のヘッダー ファイル file.hfile.c および file2.c の両方にインクルードしなければなりません。

file.h:構造体実装が含まれていません。

#ifndef TYPE_GUARD
#define TYPE_GUARD

typedef struct myStruct *ptrMyStruct; 

ptrMyStruct getObj(void);
void useObj(ptrMyStruct);

#endif

file.c:file.h をインクルードしますが、構造体をデリファレンスしません。

#include "file.h"

void func() {
  ptrMyStruct sPtr = getObj();
  useObj(sPtr);
}

file2.c:file.h をインクルードし、構造体をデリファレンスします。

#include "file.h"

struct myStruct {                                               
  int a;                                                    
};

void useObj(ptrMyStruct ptr) {
    (ptr->a)++;
}

チェック情報

グループ: Rec.02.宣言と初期化 (DCL)

バージョン履歴

R2019a で導入


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.