C言語における`gets`関数は、標準入力から1行分の
文字列を取得するための関数です。しかし、この関数には重大なセキュリティ上の問題があり、現在では使用が推奨されていません。`gets`関数は、入力バッファのサイズを超えたデータを読み込んでしまう可能性があり、バッファオーバーランを引き起こす危険性があります。この
脆弱性のため、2011年に改訂されたC11規格以降の標準Cライブラリからは廃止されました。
`gets`関数の形式
C99規格までは、`
`ヘッダーファイルで`gets`関数は以下のように定義されていました。
c
char gets(char s);
この関数は、標準入力から改行文字(`
`)が現れるまでのデータを読み込み、引数として渡された`s`に格納します。読み込んだ改行文字は終端記号(`\0`)に置き換えられます。正常に読み込みが完了した場合は`s`を返し、エラーが発生した場合は`NULL`を返します。
`scanf`関数と異なり、`gets`関数は改行文字を読み込んだ後に終端記号に置き換えるため、入力ストリームに改行文字が残りません。この点は`scanf`と異なるため、`scanf`と組み合わせて使用する際には注意が必要です。例えば、`scanf`の直後に`gets`を呼び出すと、入力ストリームに残った改行文字を`gets`が読み込んでしまい、意図しない動作を引き起こすことがあります。
セキュリティ上の問題
`gets`関数の最大の問題点は、入力バッファのサイズを超えた入力を受け付けてしまうことです。例えば、以下のようなコードがあったとします。
c
char a[10];
gets(a);
このコードでは、`a`は10バイトの領域を確保しています。`gets`関数は、入力されたデータが`a`のサイズ(終端記号を除いた9バイト)を超える場合でも読み込みを続行します。これにより、`a`が確保されたメモリ領域を超えてデータが書き込まれ、バッファオーバーランが発生します。このバッファオーバーランは、プログラムのクラッシュやセキュリティ上の脆弱性につながる可能性があります。
`gets`関数には、入力される文字列の長さを制限する機能がないため、バッファオーバーランを防ぐことができません。そのため、実用的なプログラミングでは絶対に`gets`関数を使用すべきではありません。C11規格で廃止されたのも、このセキュリティ上の問題が主な理由です。また、POSIX.1-2008でも廃止予定とされています。GCCなどのコンパイラでは、`gets`関数を使用すると警告が表示されます。
C++においても、`std::gets`関数はC++11規格で廃止予定となり、C++14規格で削除されました。
`gets`関数の代替策
`gets`関数の代わりに、以下の関数を使用することが推奨されます。
`fgets`関数: `fgets`関数は、指定されたバッファサイズまで、または改行文字が現れるまでのデータを読み込みます。`gets`関数と異なり、バッファオーバーランを防ぐことができます。ただし、`fgets`関数は改行文字をバッファに含めて読み込むため、`gets`関数と単純に置き換えることはできません。
`gets_s`関数: C11で追加された`gets_s`関数は、バッファサイズを指定できるため、バッファオーバーランを防ぐことができます。しかし、`gets_s`関数はC11において実装が必須ではないため、使用できる環境が限られる場合があります。
`getline`関数: POSIX 2008で追加された`getline`関数は、指定されたストリームから1行分のデータを読み込み、動的にメモリを確保して格納します。`getline`関数は、バッファサイズを気にする必要がなく、安全に文字列を読み込むことができます。ただし、`getline`関数を使用するには`_GNU_SOURCE`をdefineする必要があります。
また、`getchar`関数を使用して、同様の機能を持つ関数を自作することも可能です。
C++においては、`std::getline`関数が標準ライブラリに用意されており、文字列クラス`std::string`のオブジェクトとして安全に1行分の入力を取得できます。したがって、C++では`gets`関数を使用する必要は全くありません。
`gets`関数の使用は、セキュリティ上のリスクを伴うため、これらの代替関数を積極的に利用しましょう。
関連項目
標準Cライブラリ
`fgets`
`puts`
`scanf`
脚注
特になし
外部リンク
gets(3) – JM Project Linux Library Functions マニュアル