FIO36-C. fgets() が改行文字を読み取ると仮定しない
fgets() 関数は通常、改行で終わる行を入力ストリームから読み込むために使用される。fgets() 関数は、サイズ引数をとり、最大で size-1 文字をストリームからコピー先バッファにコピーする。プログラマがコピー先文字列の最後の文字に必ず改行が入っていると思い込むと、切り捨てエラーが発生する可能性がある。
違反コード
以下のコード例では、入力行から末尾の改行(\n)を削除しようとしている。
char buf[BUFSIZ + 1]; if (fgets(buf, sizeof(buf), fp)) { if (*buf) { /* FIO37-Cを参照 */ buf[strlen(buf) - 1] = '\0'; } } else { /* エラー処理 */ }
しかし、buf の最後の文字が改行でない場合、このコードは有効な文字を上書きしてしまう。
適合コード
以下の解決法では、strchr() を使用して文字列中の改行文字(それが存在する場合)を置き換えている。fgetws() が使用されている場合は、同様に wcschr() を使用する。
char buf[BUFSIZ + 1]; char *p; if (fgets(buf, sizeof(buf), fp)) { p = strchr(buf, '\n'); if (p) { *p = '\0'; } } else { /* エラー処理 */ }
他の解決法としてすぐ思いつくのは、バッファに1文字分のスペースを残しておいて、改行コードがコピーされていなかったら null 終端文字の前に改行を追加するという方法である。しかし、このアプローチは危険である。実際には意図されていなかった入力を暗黙的に受けつけてしまい、予測できない結果となる恐れがあるからである。
リスク評価
改行文字が読み取られると想定すると、データが切り捨てられる可能性がある。
ルール | 深刻度 | 可能性 | 修正コスト | 優先度 | レベル |
---|---|---|---|---|---|
FIO36-C | 中 | 高 | 中 | P12 | L1 |
参考情報
- [Lai 06]
- [Seacord 05] Chapter 2, "Strings"
- [ISO/IEC 9899:1999] Section 7.19.7.2, "The fgets Function"
翻訳元
これは以下のページを翻訳したものです。
FIO36-C. Do not assume a newline character is read when using fgets()