gets
gets はC言語の標準Cライブラリにおける、標準入出力ヘッダー(<stdio.h>)で宣言されている標準入力から1行分の文字列を取り出す入力関数である。この関数はバッファオーバーランを防ぐことが出来ないという致命的な脆弱性を持っており、例えばGCCではコンパイルされるものの「the `gets' function is dangerous and should not be used. ('gets' 関数は危険なため使うべきではありません。)」と警告される。C言語の規格においても、将来的には廃止されることが予想される関数である。
目次 |
[編集] 形式
stdio.h で gets は以下のような形式で宣言されている。
char *gets(char *s)
gets は標準入力から改行('\n')が現れるまでデータを読み込み、引数で渡された s に格納する、このとき改行文字は終端記号('\0')に置き換える。戻り値にはエラーが発生した場合は NULL をそれ以外は s を返す。
scanfの %d や %s と異なり、改行文字は読み込んだ後で終端記号に書き換えるためストリームに改行文字は残らない。このため scanf のような改行文字の処理は必要とはしない。逆に scanf で呼ばれた直後に gets を呼ぶと入力ストリームの先頭に改行文字が残っているため gets は空の文字列を返してしまう。このため scanf と混在して使うべきではないとされている[1]。
[編集] セキュリティ
以下のようなコードがあった場合を考えてみる。
char a[10]; gets(a);
このとき、入力されたデータが a の長さから終端記号を除いた 9バイトより大きいものであるなら、このコードはバッファオーバーランが発生する。入力されるデータの長さを測ることはプログラム側では判別することは不可能なので、他の関数(scanf や fgets など)ではこのような場合には格納先に入力できる最大長を指定することでバッファオーバーランを回避する方法がとられる。しかし上記の宣言を見てもわかるように、gets には入力される文字列の長さを制限する機能が存在しない。これはつまり gets を用いてバッファオーバーランを防ぐ手段はないことを表している。このため gets は実用的なプログラミングでは絶対に使用してはならない関数とされている。gets の代替としては同様の機能を持つ fgets 関数を通常用いる。ただし fgets 関数は gets 関数と末尾の改行コードの扱いが異なる(gets は改行コードを終端記号に置き換えるが fgets は改行記号の後ろに終端記号を付与する)ため、単純に gets を fgets で置き換えてしまうとバグの原因になることがあり注意が必要である。