ISO/IEC TS 17961 [inverrno]
errno の不適切な設定および使用
説明
ルール定義
errno の不適切な設定および使用。1
Polyspace 実装
このチェッカーは以下の問題をチェックします。
errno の不適切な使用。
errno の未チェック。
errno がリセットされていません。
例
errno の不適切な使用は、errno をチェックしてもエラーがないことが保証されない状況で、errno でエラー状態をチェックしている場合に発生します。場合によっては、errno をチェックすることによって誤検知につながる可能性があります。
たとえば、次の関数呼び出し後に errno をチェックします。
fopen: ISO® 規格に従う場合、この関数はエラーでerrnoを設定しない可能性があります。atof: ISO 規格に従う場合、この関数はerrnoを設定しません。signal: この関数がSIG_ERRエラー インジケーターを返す場合のみ、errnoの値がエラーを示します。
ISO C 標準では、これらの関数は必ずしもエラーで errno を設定しません。関数が errno を設定するかどうかは、実装によって異なります。
エラーを検出するため errno のみをチェックする場合、このチェックの妥当性も実装によって異なります。
場合によっては、関数が特定のエラー インジケーターを返す場合のみ、errno の値がエラーを示します。関数の戻り値をチェックする前に errno をチェックする場合、誤検出が発生する可能性があります。
エラーの検出方法の詳細は、その特定の関数のドキュメンテーションを参照してください。
通常、そのような関数はエラーを示すために帯域外エラー インジケーターを返します。次に例を示します。
fopenは、エラーが発生すると NULL ポインターを返します。signalは、SIG_ERRエラー インジケーターを返し、errnoに正の値を設定します。この関数の戻り値をチェックした後のみerrnoをチェックします。
fopen 呼び出し後の errno の不適切なチェック#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define fatal_error() abort()
const char *temp_filename = "/tmp/demo.txt";
FILE *func()
{
FILE *fileptr;
errno = 0;
fileptr = fopen(temp_filename, "w+b");
if (errno != 0) {
if (fileptr != NULL) {
(void)fclose(fileptr);
}
/* Handle error */
fatal_error();
}
return fileptr;
}この例では、errno は fopen の呼び出し後にチェックされる最初の変数です。エラーが発生すると fopen が errno を非ゼロの値に変更すると想定しています。エラーで errno を設定しない fopen の実装を使ってこのコードを実行すると、エラー状態を見落とすことになります。この場合、fopen は検出をエスケープする NULL ポインターを返す可能性があります。
fopen 呼び出し後に戻り値をチェック1 つの修正方法として、fopen の戻り値が NULL ポインターかどうかのみをチェックします。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#define fatal_error() abort()
const char *temp_filename = "/tmp/demo.txt";
FILE *func()
{
FILE *fileptr;
fileptr = fopen(temp_filename, "w+b");
if (fileptr == NULL) {
fatal_error();
}
return fileptr;
}errno の未チェックは、エラー状態を示すために errno を設定する関数を呼び出しても、その呼び出し後に errno をチェックしていない場合に発生します。このような関数の場合、エラーが発生したかどうかを判断するための唯一信頼できる方法は errno をチェックすることです。
エラーで errno を設定する関数には次のものがあります。
fgetwc、strtolおよびwcstol。関数の包括的な一覧については、errno に関するドキュメンテーションを参照してください。
encrypt、setkeyなどの POSIX®errno設定関数。
エラーなしで関数呼び出しが完了したかどうかを確認するには、errno のエラー値をチェックします。
このような errno を設定する関数の戻り値はエラーを示しません。戻り値は、以下のいずれかになります。
voidエラーが発生しても、戻り値は正常に行われた呼び出しと同じ値になる可能性があります。このような戻り値をインバンド エラー インジケーターと呼びます。
エラーが発生したかどうかは、errno をチェックすることでのみ判断できます。
たとえば、strtol は文字列を long 型整数に変換して、その整数を返します。変換結果がオーバーフローする場合、この関数は LONG_MAX を返し、errno に ERANGE を設定します。ただし、この関数は正常に変換が行われても LONG_MAX を返すことがあります。errno をチェックすることでのみ、エラーと正常な変換を区別することができます。
関数を呼び出す前に、errno にゼロを設定します。
関数呼び出しの後、errno をゼロと比較して、エラーが発生したかどうかを確認します。あるいは、errno を既知のエラー インジケーター値と比較します。たとえば、strtol は errno に ERANGE を設定してエラーを示します。
Polyspace® の結果のエラー メッセージには、比較できるエラー インジケーター値が示されます。
strtol 呼び出し後の errno 未チェック#include<stdio.h>
#include<stdlib.h>
#include<errno.h>
int main(int argc, char *argv[]) {
char *str, *endptr;
int base;
str = argv[1];
base = 10;
long val = strtol(str, &endptr, base);
printf("Return value of strtol() = %ld\n", val);
}
errno をチェックしないで strtol の戻り値を使用しています。
errno をチェックstrtol を呼び出す前に、errno にゼロを設定します。strtol 呼び出し後、戻り値については LONG_MIN または LONG_MAX をチェックし、errno については ERANGE をチェックします。
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<limits.h>
int main(int argc, char *argv[]) {
char *str, *endptr;
int base;
str = argv[1];
base = 10;
errno = 0;
long val = strtol(str, &endptr, base);
if((val == LONG_MIN || val == LONG_MAX) && errno == ERANGE) {
printf("strtol error");
exit(EXIT_FAILURE);
}
printf("Return value of strtol() = %ld\n", val);
}
errno がリセットされていませんは、エラー状態を示すために errno を設定する関数を呼び出す前に errno をリセットしていない場合に発生します。ただし、関数呼び出し後には、errno でエラー状態をチェックしています。
errno を設定する関数は、errno を、エラー状態を示す非ゼロの値に設定します。
errno を設定する関数を呼び出す前に errno をゼロに設定していなかった場合、errno を設定する関数を以前に呼び出したときに設定された非ゼロの値が、errno に残っている可能性があります。この場合、errno を使用してエラーを確認すると、最新の呼び出しで発生したエラーであると誤って判断する可能性があります。
errno はプログラム起動時に 0 に設定されますが、エラーの発生後に自動的にリセットされることはありません。必要に応じて、errno を明示的に 0 に設定しなければなりません。
エラー状態を示すために errno を設定する関数を呼び出す前に、errno を明示的にゼロにリセットします。
strtod を呼び出す前に errno をリセットしていない#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <float.h>
#define fatal_error() abort()
double func(const char *s1, const char *s2)
{
double f1;
f1 = strtod (s1, NULL);
if (0 == errno) {
double f2 = strtod (s2, NULL);
if (0 == errno) {
long double result = (long double)f1 + f2;
if ((result <= (long double)DBL_MAX) && (result >= (long double)-DBL_MAX))
{
return (double)result;
}
}
}
fatal_error();
return 0.0;
}この例では、strtod 呼び出しの前に errno をゼロにリセットしていません。この errno がゼロかどうかをチェックすると、誤検知につながる可能性があります。
errno をリセット1 つの修正方法として、strtod を呼び出す前に errno をゼロにリセットします。
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <float.h>
#define fatal_error() abort()
double func(const char *s1, const char *s2)
{
double f1;
errno = 0;
f1 = strtod (s1, NULL);
if (0 == errno) {
double f2 = strtod (s2, NULL);
if (0 == errno) {
long double result = (long double)f1 + f2;
if ((result <= (long double)DBL_MAX) && (result >= (long double)-DBL_MAX))
{
return (double)result;
}
}
}
fatal_error();
return 0.0;
}チェック情報
| 決定可能性:決定不可能 |
バージョン履歴
R2019a で導入R2024a 以降、先に errno をゼロに設定せずに、errno に値を設定する関数を呼び出し、呼び出し後にエラー状態を調べるために errno をテストした場合、関数の呼び出しに対してルール違反が表示されるようになります。以前は、関数呼び出しではなく、その後の errno の検査に対してルール違反が表示されていました。
また、errno に値を設定する関数の、チェッカーが対応する範囲が拡大しました。
1 Extracts from the standard "ISO/IEC TS 17961 Technical Specification - 2013-11-15" are reproduced with the agreement of AFNOR. Only the original and complete text of the standard, as published by AFNOR Editions - accessible via the website www.boutique.afnor.org - has normative value.
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)