INT06-C. 文字列トークンを整数に変換するには strtol() 系の関数を使う
文字列トークンを整数に変換するには strtol
系関数を使うこと。これらの関数は他の方法よりも堅牢なエラー処理を提供する。
strtol()
、strtoll()
、strtoul()
および strtoull()
関数は、null 終端バイト文字列の最初の部分を、long int
、long long int
、unsigned long int
および unsigned long long int
へそれぞれ変換する。
signed int
、signed short
、singed char
など、より小さな符号付き型に変換するには、strtol()
関数を使い、結果の値をその型の範囲に照らし合わせてテストすること。
unsigned int
、unsigned short
、unsigned char
などより小さな符号無し型に変換するには、strtoul()
関数を使い、結果の値をその型の範囲に照らし合わせてテストすること。
これらの範囲テストは、より小さな型がたまたま同じサイズと表現を持つような特定のコンパイラではなにもしない。
違反コード (atoi()
)
以下のコード例は、静的配列 buff
に格納されている文字列トークンを、atoi()
関数を使用して符号付き整数値に変換している。
int si;
if (argc > 1) {
si = atoi(argv[1]);
}
atoi()
、atol()
および atoll()
関数は、文字列トークンをそれぞれ int
、long int
、long long int
表現に変換する。エラーが発生する場合を除き、以下と同じ結果になる。
atoi: (int)strtol(nptr, (char **)NULL, 10)
atol: strtol(nptr, (char **)NULL, 10)
atoll: strtoll(nptr, (char **)NULL, 10)
残念ながら atoi()
系の関数は無効な値に対してエラーを報告するメカニズムを持っていない。特に atoi()
、atol()
、atoll()
の各関数は以下の特徴を持つ。
- エラー時に
errno
をセットする必要がない - 結果の値が表現できない場合、その動作は未定義とする
- 文字列が整数を表現できない場合には 0 を返すが、これは正しくフォーマットされている 0 を表す文字列と区別がつかない
違反コード(sscanf()
)
以下のコード例では、sscanf()
関数を使って文字列トークンを整数に変換している。sscanf()
関数には atoi()
と同じ制限がある。
int matches;
int si;
if (argc > 1) {
matches = sscanf(argv[1], "%d", &si);
if (matches != 1) {
/* エラー処理 */
}
}
sscanf()
関数は、一致と代入が成功した入力要素の個数を返す。返される値は渡された変換の個数よりも少ないこともあり、最初に一致の失敗があった場合には 0 になることもある。しかし、sscanf()
は、strtol()
が報告するオーバーフローなどのような他のエラーについては報告しない。
適合コード (strtol()
)
strtol()
、strtoll()
、strtoul()
および strtoull()
関数は、null終端バイト文字列をそれぞれ long int
、long long int
、unsigned long int
および unsigned long long int
表現にそれぞれ変換する。
この適合コードでは、strtol()
を使って文字列トークンを整数に変換しており、結果の値が int
の範囲にあることを保証している。
int main(int argc, char *argv[]) {
if (argc < 2)
return EXIT_SUCCESS;
const char* const str = argv[1];
char *end;
int si;
errno = 0;
const long sl = strtol(str, &end, 10);
if (end == str) {
fprintf(stderr, "%s: not a decimal number\n", str);
}
else if ('\0' != *end) {
fprintf(stderr, "%s: extra characters at end of input: %s\n", str, end);
}
else if ((LONG_MIN == sl || LONG_MAX == sl) && ERANGE == errno) {
fprintf(stderr, "%s out of range of type long\n", str);
}
else if (sl > INT_MAX) {
fprintf(stderr, "%ld greater than INT_MAX\n", sl);
}
else if (sl < INT_MIN) {
fprintf(stderr, "%ld less thatn INT_MIN\n", sl);
}
else {
si = (int)sl;
/* si を使った処理 */
return EXIT_SUCCESS;
}
return EXIT_FAILURE;
}
リスク評価
このレコメンデーションの違反がセキュリティ上の脆弱性につながることはまれだが、データの欠損や誤解釈には容易につながるおそれがある。
レコメンデーション |
深刻度 |
可能性 |
修正コスト |
優先度 |
レベル |
---|---|---|---|---|---|
INT06-C |
中 |
中 |
中 |
P8 |
L2 |
自動検出(最新の情報はこちら)
ツール |
バージョン |
チェッカー |
説明 |
---|---|---|---|
|
|
以下に挙げる関数呼び出しを警告することで、このレコメンデーションの違反を検出できる。
|
|
5.0 |
|
CERT C Rule Packを使ってこのレコメンデーションの違反を検出できる |
|
LDRA tool suite |
V. 8.5.4 |
44 S |
実装済み |
PRQA QA-C | 8.1 | Warncall -wc atoi, -wc atol | 部分的に実装済み |
関連するガイドライン
CERT C++ Secure Coding Standard | INT06-CPP. Use strtol() or a related function to convert a string token to an integer |
MITRE CWE | CWE-676, Use of potentially dangerous function CWE-20, Insufficient input validation |
参考資料
[Klein 2002] |
翻訳元
これは以下のページを翻訳したものです。
INT06-C. Use strtol() or a related function to convert a string token to an integer (revision 86)