【雑談】 getsは本当に危険か?

フォーラム(掲示板)ルール
フォーラム(掲示板)ルールはこちら  ※コードを貼り付ける場合は [code][/code] で囲って下さい。詳しくはこちら
たかぎ

【雑談】 getsは本当に危険か?

#1

投稿記事 by たかぎ » 15年前

Cプログラミングの初学者がgetsを使うという状況に限った場合、具体的にどんな危険性があると思いますか?
環境にもよるでしょうから、こういった環境ではこんな危険性があるということを教えてください。

へろりくしょん

Re:【雑談】 getsは本当に危険か?

#2

投稿記事 by へろりくしょん » 15年前

やっぱり、素直にバッファオーバーランじゃないでしょうか。

たかぎ

Re:【雑談】 getsは本当に危険か?

#3

投稿記事 by たかぎ » 15年前

> やっぱり、素直にバッファオーバーランじゃないでしょうか。

それはそうなのですが、では、(初学者が書いたプログラムが)バッファオーバーランしたとき、具体的にどんな危険がありますか?
バッファオーバーランなら単なる配列の操作でも起きます。初学者は間違って当然ですから。
もしバッファオーバーランが決してあってはならないほど危険なものであれば、getsだけでなく配列も禁止すべきですよね。
というより、よほどコンピュータに精通していて、しかも注意深い人でなければ、Cプログラミングを学習すること自体が困難になると思います。
けれども、実際はそうではありませんね。

初学者が作ったプログラムが正しく動かないということは、あたりまえに起きることなので、それ自体は危険でも何でもないはずです。
getsを使って不具合が発生したとき、人が死ぬとか、火災が起こるとか、そこまでいかなくても世間にさまざまな迷惑をかけるとか、せめて自分のPCが破壊されるとかであれば、確かに「危険」なのですが、そうでなければ、学習の時点ではバッファオーバーランしてもよいのでは? と思うわけです。

へろりくしょん

Re:【雑談】 getsは本当に危険か?

#4

投稿記事 by へろりくしょん » 15年前

>そうでなければ、学習の時点ではバッファオーバーランしてもよいのでは? と思うわけです。

なるほど。 それはそうですね。
しかしそれを言ってしまえば、今時のOSならば、コアダンプを吐くとかエラー吐いて落ちますから、gets()関数に限らず、何をしても危険という危険は無いような気がするのですが。
OSの無い環境まで考慮するならば、そこはそれ、鼻から悪魔ですからやっぱり何とも言えないかと。

そこであえて危険と言うならば、初学者がある程度の知識・技術を獲得してもなお、最初の頃に習得した物をそのまま使い続ける、ということでは無いでしょうか。

ループカウンタとして多用される変数iですが、どうせあちこちで使うからと、グローバルスコープで使い続けていた人を知っています。

楽な方向に流されがちなのが人間ですから、こういうのはやっぱり最初にきっちり癖をつけておかないとダメな気がします。


誤解を招きそうだったので、一部書き換えてます。 画像

palladium

Re:【雑談】 getsは本当に危険か?

#5

投稿記事 by palladium » 15年前

>バッファオーバーランしたとき、具体的にどんな危険がありますか?

Windows 98 の仮想アドレス内のカーネルパーティションは
0xC0000000 ~ 0xFFFFFFFFらしいです
この部分にはシステムのコードが配置されるようです
スレッドスケジューリング、
メモリ管理、ファイルシステムサポート、
ネットワークサポート、デバイスドライバは
この領域にロードされるようです。

Windows 2000ではこの領域(3GB拡張してないとき)は
システムによって保護されているのでアクセスしようとすると
アクセス違反でアプリは強制終了となるようです。

Windows 98 の場合はシステムによってこの領域が保護されていないので
アプリはこの領域を読み書きできるようです。
「ブルー画面」の可能性もあるかもしれませんね。

たかぎ

Re:【雑談】 getsは本当に危険か?

#6

投稿記事 by たかぎ » 15年前

> しかしそれを言ってしまえば、今時のOSならば、コアダンプを吐くとかエラー吐いて落ちますから、gets()関数に限らず、何をしても危険という危険は無いような気がするのですが。

ネットワークがらみは必ずしもそうとはいえませんけどね。

> そこであえて危険と言うならば、初学者がある程度の知識・技術を獲得してもなお、最初の頃に習得した物をそのまま使い続ける、ということでは無いでしょうか。

これは私も考えました。確かに一理あります。
最初のころに atoi を習得すると、いくら問題があっても strtol ではなく atoi を使い続けますからね。
あと、最初からインテリセンスありきで学習したプログラマは、インテリセンスが使えない環境だと手も足も出なくなるのも、根は同じだと思います。

> 楽な方向に流されがちなのが人間ですから、こういうのはやっぱり最初にきっちり癖をつけておかないとダメな気がします。

細かい話は抜きにして、とりあえず動くものを作って楽しさを味わうのがよいのか、最初から厳密な理解を積み重ねるのがよいのか、さじ加減が難しいところです。

たかぎ

Re:【雑談】 getsは本当に危険か?

#7

投稿記事 by たかぎ » 15年前

> Windows 98 の場合はシステムによってこの領域が保護されていないので
> アプリはこの領域を読み書きできるようです。
> 「ブルー画面」の可能性もあるかもしれませんね。

もう古い話は忘れましたが、多くは再起動で済みますね。
MS-DOSのころは普通に暴走していましたので、頻繁にリセットボタンを押しながらプログラミングを習得したものです。
再起動しても復帰できないようなら痛いですが、そうでなければ大した問題でもない気がします。

palladium

Re:【雑談】 getsは本当に危険か?

#8

投稿記事 by palladium » 15年前

>もう古い話は忘れましたが

古いネタですみませんでした。

たかぎ

Re:【雑談】 getsは本当に危険か?

#9

投稿記事 by たかぎ » 15年前

> 古いネタですみませんでした。

かまわないですよ。
Windows 98なんかを持ち出さなくても、μITRONの環境とかなら普通にOSの領域に書き込みできますから。
ただ、普通はクラッシュしても再起動で済んでしまいます。

palladium

Re:【雑談】 getsは本当に危険か?

#10

投稿記事 by palladium » 15年前

>かまわないですよ。
ありがとうございます。


以前、剣道を習ってましたが真剣ではなく竹刀で稽古してました。(あたりまえだろw)
しかし、C言語の場合ある意味最初から真剣かもしれませんね。

>最初にきっちり癖をつけておかないとダメな気がします。
これはやっぱり大切なことのように思います。

めるぽん

Re:【雑談】 getsは本当に危険か?

#11

投稿記事 by めるぽん » 15年前

>バッファオーバーランなら単なる配列の操作でも起きます
gets と配列で違うのは、バッファオーバーランしたときに、悪意のあるユーザからの入力で任意の値を入れられることでしょうか。
配列でも任意の値を入れられることはあるかもしれませんが、乗っ取る側からすればそれを解析するより gets を探す方が楽そうです。

たかぎ

Re:【雑談】 getsは本当に危険か?

#12

投稿記事 by たかぎ » 15年前

> gets と配列で違うのは、バッファオーバーランしたときに、悪意のあるユーザからの入力で任意の値を入れられることでしょうか。

初学者が勉強で作ったプログラムを狙って、悪意のあるユーザが入力するという状況がよくわからないのですが...

めるぽん

Re:【雑談】 getsは本当に危険か?

#13

投稿記事 by めるぽん » 15年前

そのプログラムを狙う悪意のあるユーザがどこにもいないのであれば、初学者だろうと何だろうとセキュリティのことは気にしなくていいのではないでしょうか。まあその人の学習的には良くないんでしょうけど。
可能性を考えるだけなら、会社にプログラムをやったことがない人がプログラマとして配属されていきなり適当に仕事を割り振られて必死で作ったときに gets が入っていて、それはパッケージとしてユーザに売られるものだったとか、学生が初めて作ったプログラムをこれは便利だ思って Vector とかに登録したとか・・・実際あるのかどうかは知りませんが、もしあるなら攻撃の踏み台に使われる可能性はあると思うのですけれども。

たかぎ

Re:【雑談】 getsは本当に危険か?

#14

投稿記事 by たかぎ » 15年前

> 会社にプログラムをやったことがない人がプログラマとして配属されていきなり適当に仕事を割り振られて必死で作ったときに gets が入っていて、それはパッケージとしてユーザに売られるものだったとか、

少なくともこれは別の問題な気がします。
安全云々以前に、素人が作ったものを客に提供するというのは倫理的にあり得ない話です。
実際やってしまう悪徳業者がいそうなのが、怖いところですが...

> 学生が初めて作ったプログラムをこれは便利だ思って Vector とかに登録したとか

これもおそらくgetsだけの問題ではないでしょうね。

MNS

Re:【雑談】 getsは本当に危険か?

#15

投稿記事 by MNS » 15年前

初学者の方がgetsを使うという状況において、
それにバッファオーバーフローという危険が伴なうということを教えられたとして、
コード上で行える具体的な対策が、getsを使わないことくらいしかないことが、
少々問題というか、危険な気がします。

配列の場合ももちろんバッファオーバーフローの危険は伴いますが、
コード上でいくつかの対策を行うことができるので、
仮にバッファオーバーフローの原理を理解していなくても、
ある程度は、その危険を回避することが出来ますし、
対策となるコードに具体性があるので、初学者の方にとっても、
バッファオーバーフローの原理をすんなりと理解できそうな気はします。

しかし、getsの場合は特に対策のしようがない気がするので、
(要素数をなるだけ大きくする、くらいでしょうか)
何となく使って、何となく動いてしまう状況も起こりえますし、
少なからず、配列に対する理解を深めてから使うほうがよいでしょうね。

たかぎ

Re:【雑談】 getsは本当に危険か?

#16

投稿記事 by たかぎ » 15年前

> 少なからず、配列に対する理解を深めてから使うほうがよいでしょうね。

これは、配列の理解が深まるまでは、getcharやgetcで1文字ずつ入力すべし、という意味でしょうか?
あと、

> バッファオーバーフローという危険

についてですが、具体的にどんな実害を想定していますか?

MNS

Re:【雑談】 getsは本当に危険か?

#17

投稿記事 by MNS » 15年前

>これは、配列の理解が深まるまでは、getcharやgetcで1文字ずつ入力すべし、という意味でしょうか?
というよりは、
バッファオーバーフローの原理が理解できない内にgetsを使うのは問題であり、
初学者の方で、配列に対する一定の理解がないのにも関わらず、
バッファオーバーフローの原理が理解できる、という方はそういないと思います。
裏を返せば、バッファオーバーフローの危険性が無い入力関数があれば、
それは使ってもよいと思います。(あるかどうかは分かりませんが)

>具体的にどんな実害を想定していますか?
最近のOSなら、保護されていないところを書き換えようとしても、
なんだかんだで大丈夫なんですかね?

それならば、実害といってはあれですが、
理由が分からないが、意図した通りにプログラムが動かない、エラーが出る。
しかし、原因がバッファオーバーフローであるということが分からない、
もしくは、バッファオーバーフローというのが原因なのは分かったが、
それが何故起きているのかが分からない。
結果として、プログラミングの学習に支障がでる、
といった状況に陥りかねないということでしょうかね。

たかぎ

Re:【雑談】 getsは本当に危険か?

#18

投稿記事 by たかぎ » 15年前

> 裏を返せば、バッファオーバーフローの危険性が無い入力関数があれば、
> それは使ってもよいと思います。(あるかどうかは分かりませんが)

単にバッファオーバーランを回避するだけならできますが、それで何もかもが丸く収まるわけではありませんね。
だとすると、やはり配列を理解するまでは、getchar 等で1文字ずつ入力する以外に、文字列を読み込む方法がないように思います。

> 最近のOSなら、保護されていないところを書き換えようとしても、
> なんだかんだで大丈夫なんですかね?

最悪、再起動で済む場合がほとんどでしょう。
これは最近のOSに限りません。
もっとも、プログラマブルI/Oポートを直接触れるようなプラットフォームの場合、外部回路では入力なのに無理矢理出力に設定すれば、電源とGNDを短絡させてハードウェアを破壊することはできると思います。

> 理由が分からないが、意図した通りにプログラムが動かない、エラーが出る。
> しかし、原因がバッファオーバーフローであるということが分からない、
> もしくは、バッファオーバーフローというのが原因なのは分かったが、
> それが何故起きているのかが分からない。
> 結果として、プログラミングの学習に支障がでる、

それならなおのこと、バッファオーバーランを体験して、どんな現象が起きるのかを実感し、原因究明と対策を行う経験を積んだ方が学習が進みませんか?
避けていてもいつかは直面する問題なので、初期のうちの、まだプログラムが単純で、原因究明が容易なうちに体験させるのは悪くないと思いませんか?

MNS

Re:【雑談】 getsは本当に危険か?

#19

投稿記事 by MNS » 15年前

なるほど。
バッファオーバーフローは、それほど危険な現象ではないんですね。
それならば、確かに、身を以て体験したほうが良い経験になりそうです。

>原因究明と対策を行う経験を積んだ方が学習が進みませんか?
おっしゃるとおりなのですが、この対策というものが、
果たしてgetsにおいて行えるかどうか、というのが問題な気もします。

その体験は、あくまで配列の学習過程において体験するほうが、
効果的という気がしなくもありませんね。
まあ、文字列入力は初期段階で紹介したほうが良いのかも知れませんが…

たかぎ

Re:【雑談】 getsは本当に危険か?

#20

投稿記事 by たかぎ » 15年前

> バッファオーバーフローは、それほど危険な現象ではないんですね。

そこまでいうといいすぎな気がしますが、多く場合はそうだといえます。

> 果たしてgetsにおいて行えるかどうか、というのが問題な気もします。

私が思いつく範囲では、2種類の状況を除いて、gets を使い続けて対策する方法はありません。
ただ、最初から答えを示してしまうのではなく、とことん対策を考えさせて、「対策できない」という結論を導かせるのは意味があると思います。

2種類の状況というのは、ひとつはファイルからのリダイレクトによる入力の場合で、それであれば事前にファイルサイズを調べることで、必要なバッファサイズを知ることができますので対策可能です(ファイルの排他制御はもちろん必要です)。
もうひとつは、1行あたりの入力文字数の制限があるようなコンソールを使う場合です。
任意の入力に対して対策可能な状況は、この二つしかないと思います。もちろん、運用で問題を回避することはできますが...

getsの使用にこだわらない場合は次の3つの対策方法があります。

1. 1行分の文字列を格納できるようにバッファを拡張する。拡張できない場合はエラーにする。
2. 事前に割り付けたバッファに格納できなかった文字は、改行まで捨てる。
3. 事前に割り付けたバッファに格納しきれない場合はエラーとし、再入力を促す。

1.は realloc で動的にバッファを拡張しなければなりませんので、当然難易度が上がります。
2.は情報を失うことになるので、それに伴う問題が生じます。
3.は、コンソールの場合は最も妥当な選択ですが、リダイレクトの場合は破綻します。
こう考えると、なかなか一筋縄ではいかないのです。

> その体験は、あくまで配列の学習過程において体験するほうが、
> 効果的という気がしなくもありませんね。

分かりやすさでいえば、そうですね。

組木紙織

Re:【雑談】 getsは本当に危険か?

#21

投稿記事 by 組木紙織 » 15年前

gets()が危険というより、gets()を使うことによってバッファオーバーラン
が発生しやすくなり、その対策方法が少ないということが問題なんですね。
gets()の問題というより、gets()によって起こるバッファオーバーランの問題と解釈しなおして考えると、

実行時に起こる状況はほかの方々があげられているので、わたしは別の観点から。
デバッグ時にデバッグが難しくなる。ということをあげたいと思います。
またはRelease時とDebug時の動作が異なるときがあることです。

たかぎ

Re:【雑談】 getsは本当に危険か?

#22

投稿記事 by たかぎ » 15年前

> gets()が危険というより、gets()を使うことによってバッファオーバーラン
> が発生しやすくなり、その対策方法が少ないということが問題なんですね。

現実の問題として、初学者が勉強で使っている状況で、バッファオーバランが発生しやすいと思いますか?
例えば、1024バイト程度の配列を用意してgetsで読み込もうとしたとき、実際のその初学者がバッファオーバーランに遭遇することがあると思いますか?

> デバッグ時にデバッグが難しくなる。ということをあげたいと思います。

予期しない事態が起きますし、振る舞いを理解することも難しいでしょうね。

> またはRelease時とDebug時の動作が異なるときがあることです。

初学者がgetsを使っている状況で、Releaseビルドをする機会がどの程度あるでしょうか?
あるいは、これが問題になるのであれば、最初からGCCでも使っておけば問題を回避できるのではないですか?

たかぎ

Re:【雑談】 getsは本当に危険か?

#23

投稿記事 by たかぎ » 15年前

コメントをいただいている皆さんありがとうございます。
私から、いろいろな反論をさせていただいていますが、この機会に徹底的にこの問題を議論したいからです。
悪意はありませんのでご理解ください。
引き続き、いろいろな方のご意見をいただければ幸いです。

組木紙織

Re:【雑談】 getsは本当に危険か?

#24

投稿記事 by 組木紙織 » 15年前

>現実の問題として、初学者が勉強で使っている状況で、バッファオーバランが発生しやすいと思いますか?
発生しやすいという意味では十分に大きいサイズにしておけば問題ないと思いますが、
私がはじめた時は意図的にバッファオーバーランを発生させて(当時はその用語を知りませんでしたが)
動作を見たことがあります。


>初学者がgetsを使っている状況で、Releaseビルドをする機会がどの程度あるでしょうか?
どの程度の初学者を考えているか分かりませんが、
コンパイラオプションを学ぶ機会があると思います。その時に。

たかぎ

Re:【雑談】 getsは本当に危険か?

#25

投稿記事 by たかぎ » 15年前

> 私がはじめた時は意図的にバッファオーバーランを発生させて(当時はその用語を知りませんでしたが)
> 動作を見たことがあります。

そういう試みは是非やるべきですね。
ただ、自分でわかっていてやったわけなので、デバッグが困難という状況にはならないと思います。

> どの程度の初学者を考えているか分かりませんが、
> コンパイラオプションを学ぶ機会があると思います。その時に。

普通にgetsを使う段階だと、Releaseビルドを行う機会はまずないと考えています。
というより、getsを普通に使うような段階だと、IDEを使うこと自体が邪魔ですね。
Debug/Releaseの切り替えは、コンパイラオプションというよりはIDEの機能ですので、なおさらReleaseビルドの機会は少ないと考えています。

へろりくしょん

Re:【雑談】 getsは本当に危険か?

#26

投稿記事 by へろりくしょん » 15年前

>普通にgetsを使う段階だと、Releaseビルドを行う機会はまずないと考えています。

この段階というのは、学習の進行度という意味でしょうか。 ちょっと言わんとするところが不明ですが、
gets() 関数は標準入力からの入力をとても簡単に行える便利な関数ですから、これで済むなら使い続ける人もいるのでは無いでしょうか。


>というより、getsを普通に使うような段階だと、IDEを使うこと自体が邪魔ですね。

これはどういう意味でしょう。 IDEはとても便利なツールだと思いますが。
私は使い捨てのような小さなプログラムの場合は、面倒なのでいちいちIDEを使うような事はしませんが、それ以外の場合はIDEを使います。 便利ですよね?

たかぎ

Re:【雑談】 getsは本当に危険か?

#27

投稿記事 by たかぎ » 15年前

> この段階というのは、学習の進行度という意味でしょうか。 

はい、そうです。
学習過程で、必要悪としてgetsを使うことが有益な状況では、頒布を前提とするReleaseビルドの必要はほとんどないのではないかと思います。
逆に、そんな状況で(Releaseビルドするだけならかまいませんが)頒布するのは、getsの是非以前の問題があります。

> gets() 関数は標準入力からの入力をとても簡単に行える便利な関数ですから、これで済むなら使い続ける人もいるのでは無いでしょうか。

私も使いますよ。
分かっていて使うぶんにはかまわないのです。
そうではなく、問題点が分からないまま使ってよいのは、つまり必要悪として認められるのは、学習のごく初期の段階だけではないでしょうか?

> これはどういう意味でしょう。 IDEはとても便利なツールだと思いますが。

IDEが便利なことは否定しませんし、実際にそうです。
ただ、とりあえず、Hello, World! を動かしたいだけの状況でIDEを持ち出すのは、本質とはまったく異なる部分で多大な労力を払う必要があるので、IDEはむしろ邪魔だと思うのです。
個人的には、それだけの労力を払ってもIDEを持ち出すメリットがあるのは、デバッガを使いたいか、Makefileが必要になるかしたときだと思います。
この二つは、おそらく似たようなタイミングで訪れます。この段階では、もう「初学者」とか「初心者」という呼称は卒業する時期ではないでしょうか?

naohiro19

Re:【雑談】 getsは本当に危険か?

#28

投稿記事 by naohiro19 » 15年前

>入力が 20 文字を超えると行バッファのオーバーランが発生し、ほとんどの場合はプログラムがクラッシュします。

だそうですね

たかぎ

Re:【雑談】 getsは本当に危険か?

#29

投稿記事 by たかぎ » 15年前

> >入力が 20 文字を超えると行バッファのオーバーランが発生し、ほとんどの場合はプログラムがクラッシュします。
> だそうですね

すみません、意味がわかりません。
投稿する場所を間違えていませんか?

閉鎖

“C言語何でも質問掲示板” へ戻る