CERT C++: EXP37-C
Call functions with the correct number and type of arguments
説明
ルール定義
正しい個数かつ正しい型の引数を指定して関数を呼び出します。1
Polyspace 実装
ルール チェッカーは以下の問題をチェックします。
ファイル アクセス モードまたはステータスが不適切です。
関数ポインターの信頼性の低いキャスト。
標準関数が不適切な引数で呼び出されました。
関数宣言の不一致
互換性のない引数
例
ファイル アクセス モードまたはステータスが不適切ですは、fopen
または open
グループの関数を、無効または互換性のないファイル アクセス モードで、ファイル作成フラグで、あるいはファイル ステータス フラグを引数として使用した場合に発生します。たとえば、関数 open
の場合、有効な例は次のとおりです。
有効なアクセス モードには、
O_RDONLY
、O_WRONLY
およびO_RDWR
が含まれる。有効なファイル作成フラグには、
O_CREAT
、O_EXCL
、O_NOCTTY
およびO_TRUNC
が含まれる。有効なファイル ステータス フラグには、
O_APPEND
、O_ASYNC
、O_CLOEXEC
、O_DIRECT
、O_DIRECTORY
、O_LARGEFILE
、O_NOATIME
、O_NOFOLLOW
、O_NONBLOCK
、O_NDELAY
、O_SHLOCK
、O_EXLOCK
、O_FSYNC
、O_SYNC
などが含まれる。
欠陥は次のような状態で発生します。
状態 | リスク | 修正方法 |
---|---|---|
関数 ANSI® C 標準によると、
|
実装によっては、アクセス モードの次のような拡張が許可されている。
ただし、アクセス モードの文字列は、有効なシーケンスのいずれかで始まらなければならない。 | fopen に有効なアクセス モードを渡す。 |
ステータス フラグ O_APPEND が、O_WRONLY または O_RDWR のいずれかと組み合わされずに関数 open に渡される。 |
関数 | O_APPEND|O_WRONLY または O_APPEND|O_RDWR をアクセス モードとして渡す。 |
ステータス フラグ O_APPEND および O_TRUNC がともに関数 open に渡される。 |
関数 | 意図することに応じて、2 つのモードのいずれかを渡す。 |
ステータス フラグ O_ASYNC が関数 open に渡される。 | 特定の実装では、モード O_ASYNC によって信号駆動の I/O 操作が有効にされない。 | 代わりに、fcntl(pathname, F_SETFL, O_ASYNC); を使用する。 |
修正方法は欠陥の根本原因によって異なります。多くの場合、結果の詳細には欠陥につながる一連のイベントが表示されます。そのシーケンス内のどのイベントについても修正を実装できます。結果の詳細にイベント履歴が表示されない場合は、ソース コード内で右クリック オプションを使用して逆のトレースを行い、これまでの関連するイベントを確認できます。Polyspace デスクトップ ユーザー インターフェイスでの Bug Finder の結果の解釈も参照してください。
以下の修正例を参照してください。
問題を修正しない場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。
Polyspace ユーザー インターフェイスでのバグ修正または正当化による結果への対処 (Polyspace ユーザー インターフェイスで結果をレビューする場合)。
Polyspace Access でのバグ修正または正当化による結果への対処 (Polyspace Access) (Web ブラウザーで結果をレビューする場合)。
コードへの注釈付けと既知の結果または許容可能な結果の非表示 (IDE で結果をレビューする場合)
fopen
での無効なアクセス モード#include <stdio.h>
void func(void) {
FILE *file = fopen("data.txt", "rw"); //Noncompliant
if(file!=NULL) {
fputs("new data",file);
fclose(file);
}
}
この例では、アクセス モード rw
は無効です。r
はファイルを読み取り用に開くことを示し、w
は書き込み用に新規ファイルを作成することを示しますが、この 2 つのアクセス モードには互換性がないためです。
r
か w
のいずれか一方をアクセス モードとして使用1 つの修正方法として、意図することに応じたアクセス モードを使用します。
#include <stdio.h>
void func(void) {
FILE *file = fopen("data.txt", "w");
if(file!=NULL) {
fputs("new data",file);
fclose(file);
}
}
"関数ポインターの信頼性の低いキャスト" は、関数ポインターが引数または戻り値の型が異なる別の関数ポインターにキャストされる場合に発生します。
関数ポインターを引数または戻り値の型が異なる別の関数ポインターにキャストし、後者の関数ポインターを使用して関数を呼び出した場合、動作は未定義になります。
引数または戻り値の型が一致しない 2 つの関数ポインター間のキャストは避けます。
以下の修正例を参照してください。
問題を修正しない場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。
Polyspace ユーザー インターフェイスでのバグ修正または正当化による結果への対処 (Polyspace ユーザー インターフェイスで結果をレビューする場合)。
Polyspace Access でのバグ修正または正当化による結果への対処 (Polyspace Access) (Web ブラウザーで結果をレビューする場合)。
コードへの注釈付けと既知の結果または許容可能な結果の非表示 (IDE で結果をレビューする場合)
int f(char c) {
return c;
}
int g(int i) {
return i;
}
typedef int (*fptr_t)(char);
typedef int (*gptr_t)(int);
void call() {
gptr_t ptr = (gptr_t) f;//Noncompliant
int i = ptr(511); // Undefined behavior
}
この例では、関数 f
へのポインターが gptr_t
(関数 g
の型) にキャストされます。この関数ポインターを使用して、整数値で f
を呼び出す場合、コードの動作は未定義になります。Polyspace® は、関数ポインターの信頼性の低いキャストにフラグを設定します。
未定義の動作を回避するには、関数 f
が異なる引数型にキャストされないようにコードをリファクタリングします。次に例を示します。
int f(int c) { //Fix: declare f with int argument
return c;
}
int g(int i) {
return i;
}
typedef int (*fptr_t)(char);
typedef int (*gptr_t)(int);
void call() {
gptr_t ptr = (gptr_t) f;//Compliant
int i = ptr(511);
}
標準関数が不適切な引数で呼び出されましたは、特定の標準関数の引数が、その関数における使用の要件を満たさない場合に発生します。
たとえば、こうした関数の引数は次のような形で無効になることがあります。
関数の種類 | 状態 | リスク | 修正方法 |
---|---|---|---|
strlen や strcpy のような文字列操作関数 | ポインター引数が NULL 終端文字列を指さない。 | 関数の動作が未定義になる。 | NULL 終端文字列を文字列操作関数に渡す。 |
fputc や fread のような、stdio.h 内のファイル処理関数 | FILE* ポインター引数が値 NULL をもつことがある。 | 関数の動作が未定義になる。 | FILE* ポインターを関数の引数として使用する前に、NULL についてテストする。 |
lseek や read のような、unistd.h 内のファイル処理関数 | ファイル記述子の引数が -1 になることがある。 | 関数の動作が未定義になる。 関数 | 関数 戻り値が -1 であれば、 |
ファイル記述子の引数が、閉じられたファイル記述子を表している。 | 関数の動作が未定義になる。 | ファイル記述子は、その使用が完全に終了してから閉じる。あるいは、ファイル記述子を関数の引数として使用する前に再度開く。 | |
mkdtemp や mkstemps のようなディレクトリ名生成関数 | 文字列テンプレートの最後の 6 文字が XXXXXX でない。 | 関数により、最後の 6 文字が、ファイル名を一意にする文字列で置き換えられる。最後の 6 文字が XXXXXX でない場合、関数は十分な一意性をもつディレクトリ名を生成できない。 | 文字列を関数の引数として使用する前に、その文字列の最後の 6 文字が XXXXXX であるかどうかをテストする。 |
getenv や setenv のような、環境変数に関連した関数 | 文字列引数が "" である。 | 動作が処理系定義になる。 | 文字列引数を getenv や setenv の引数として使用する前に、"" についてテストする。 |
文字列引数が等号 = で終了している。たとえば、"C" ではなく "C=" になっている。 | 動作が処理系定義になる。 | 文字列引数を = で終わりにしない。 | |
strtok や strstr のような文字列処理関数 |
| 実装によっては、こうしたエッジ ケースが扱われない。 | 文字列を関数の引数として使用する前に、"" についてテストする。 |
修正方法は欠陥の根本原因によって異なります。多くの場合、結果の詳細には欠陥につながる一連のイベントが表示されます。そのシーケンス内のどのイベントについても修正を実装できます。結果の詳細にイベント履歴が表示されない場合は、ソース コード内で右クリック オプションを使用して逆のトレースを行い、これまでの関連するイベントを確認できます。Polyspace デスクトップ ユーザー インターフェイスでの Bug Finder の結果の解釈も参照してください。
以下の修正例を参照してください。
問題を修正しない場合は、改めてレビューされないように結果またはコードにコメントを追加します。詳細は、以下を参照してください。
Polyspace ユーザー インターフェイスでのバグ修正または正当化による結果への対処 (Polyspace ユーザー インターフェイスで結果をレビューする場合)。
Polyspace Access でのバグ修正または正当化による結果への対処 (Polyspace Access) (Web ブラウザーで結果をレビューする場合)。
コードへの注釈付けと既知の結果または許容可能な結果の非表示 (IDE で結果をレビューする場合)
strnlen
の引数として渡される NULL
ポインター#include <string.h>
#include <stdlib.h>
enum {
SIZE10 = 10,
SIZE20 = 20
};
int func() {
char* s = NULL;
return strnlen(s, SIZE20); //Noncompliant
}
この例では、NULL
ポインターが strnlen
の引数として、NULL
終端文字列の代わりに渡されています。
コードの解析を実行する前に、GNU コンパイラを指定します。コンパイラ (-compiler)
を参照してください。
NULL
終端文字列を渡すNULL
終端文字列を、strnlen
の最初の引数として渡します。
#include <string.h>
#include <stdlib.h>
enum {
SIZE10 = 10,
SIZE20 = 20
};
int func() {
char* s = "";
return strnlen(s, SIZE20);
}
メモ
C++ コードでは、このチェッカーは extern "C"
として指定された関数に適用されます。
関数宣言の不一致は、関数 extern "C"
のプロトタイプがその定義と一致しない場合に発生します。関数定義の引数と関数プロトタイプの引数の型が一致するかどうかは環境によって異なります。Polyspace は、2 つの型のサイズと符号属性が使用されている環境で同じ場合に、それらの型に互換性があると見なします。たとえば、-target
を i386 として指定すると、Polyspace は、long
と int
を互換性のある型と見なします。
C++ で、関数が extern "C"
として指定されておらず、プロトタイプがどの関数定義とも一致しない場合、コンパイラは、プロトタイプを関数の未定義オーバーロードのプロトタイプとして扱います。Polyspace はそのような未定義の関数への呼び出しにフラグを設定しません。
既定の Polyspace as You Code 解析では、チェッカーはこの問題にフラグを設定しません。Polyspace as You Code 解析で非アクティブにされるチェッカー (Polyspace Access)を参照してください。
関数宣言の不一致は、未定義の動作を引き起こす可能性があります。関数宣言が extern "C"
で指定された場合、関数の定義と宣言の不一致はコンパイル中には警告のみを生成しますが、コンパイルされるコードは予想外の動作をする可能性があります。
同じファイル内で後で関数を定義する場合でも、関数を呼び出す前に、その完全なプロトタイプを指定します。
関数プロトタイプ宣言と関数定義における数値引数間の不一致を回避します。
関数プロトタイプ宣言と関数定義の引数の型間の不一致を回避します。
|
|
|
この例では、関数の foo
、bar
、および fubar
がファイル file1.c
で定義されています。これらのプロトタイプは prototype.h
で宣言されています。これらの関数は、ファイル file2.c
内で呼び出されます。
関数
foo
はint
型の引数で定義されていますが、プロトタイプは引数なしで宣言されています。この不一致のため、Polyspace は関数呼び出しにフラグを設定します。関数
bar
はint
型の引数で定義されていますが、プロトタイプはlong
型の引数で宣言されています。この 2 つの型はx86_64
環境では互換性がありません。-target
をx86_64
として指定すると、Polyspace は関数呼び出しにフラグを設定します。呼び出しシグネチャ、プロトタイプ、および定義が一致しているため、可変個引数関数
fubar
の呼び出しは準拠しています。
この欠陥の修正は、呼び出される関数の完全で正確なプロトタイプを宣言することです。この場合、関数定義とプロトタイプ宣言の不一致を解決することにより、報告された問題を修正します。更新されたプロトタイプに一致するように関数呼び出しを更新します。
|
|
|
"互換性のない引数" は、プロトタイプとの互換性がない引数を使用して外部関数が呼び出される場合に発生します。型の互換性は、使用しているハードウェアとソフトウェアの組み合わせに応じて異なる可能性があります。たとえば、次のコードを考えます。
extern long foo(int);
long bar(long i) {
return foo(i); //Noncompliant: calls foo(int) with a long
}
int
が想定されている場合に、外部関数 foo
が long
を使用して呼び出されます。int
のサイズが long
のサイズよりも小さい環境では、この関数呼び出しはプロトタイプとの互換性がないため、欠陥となります。C++ では、この欠陥はコンパイル エラーを引き起こす可能性があります。
パラメーターとの互換性がない引数を使用した外部関数の呼び出しは、未定義の動作です。ご使用の環境によっては、コードがコンパイルされるものの、予期しない方法で動作する可能性があります。
外部関数を呼び出すときには、プロトタイプで定義されているパラメーターの型と比較して同等またはそれより小さいサイズの引数型を使用します。ご使用の環境でさまざまな整数型のサイズを確認し、引数とパラメーターの型の互換性を判断します。
extern long foo1(int);
extern long foo2(long);
void bar(){
int varI;
long varL;
foo1(varL);//Noncompliant
foo2(varI);//Compliant
}
この例では、外部関数 foo1
が long
引数を使用して呼び出されますが、プロトタイプではパラメーターが int
として指定されています。x86
アーキテクチャでは、long
のサイズは int
のサイズを超えています。foo1(varL)
呼び出しは、未定義の動作を引き起こす可能性があります。Polyspace はこの呼び出しにフラグを設定します。foo2(varI)
呼び出しでは int
引数が使用されますが、パラメーターは long
として指定されています。int
のサイズは long
のサイズよりも大きくないため、このタイプの不一致はこのルールに準拠しています。
Polyspace でこの例を実行するには、以下のオプションを使用します。
-target x86_64
ターゲット プロセッサ タイプ (-target)
を参照してください。
この問題を修正するには、foo1
の引数を明示的にキャストします。これにより、引数の型とパラメーターの型が一致します。
extern long foo1(int);
extern long foo2(long);
void bar(){
int varI;
long varL;
foo1((int)varL);//Compliant
foo2(varI);//Compliant
}
チェック情報
グループ: 02.式 (EXP) |
バージョン履歴
R2019a で導入汎整数拡張の後に、プロトタイプとの互換性がない引数を使用して外部関数が呼び出される場合、チェッカーが起動されるようになりました。次に例を示します。
extern long foo(int);
long bar(long i) {
return foo(i); //Noncompliant: calls foo(int) with a long
}
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.
MATLAB Command
You clicked a link that corresponds to this MATLAB command:
Run the command by entering it in the MATLAB Command Window. Web browsers do not support MATLAB commands.
Web サイトの選択
Web サイトを選択すると、翻訳されたコンテンツにアクセスし、地域のイベントやサービスを確認できます。現在の位置情報に基づき、次のサイトの選択を推奨します:
また、以下のリストから Web サイトを選択することもできます。
最適なサイトパフォーマンスの取得方法
中国のサイト (中国語または英語) を選択することで、最適なサイトパフォーマンスが得られます。その他の国の MathWorks のサイトは、お客様の地域からのアクセスが最適化されていません。
南北アメリカ
- América Latina (Español)
- Canada (English)
- United States (English)
ヨーロッパ
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)