gets()について不平を言う場合、SCANF(「%s」、…)で同じことをしてみませんか?
-
24-10-2019 - |
質問
から man gets
:
gets()を使用しないでください。データを事前にデータを知ることなく()取得する()読み取られることが不可能であるため、gets()がバッファの端を過ぎてキャラクターを保存し続けるため、使用することは非常に危険です。コンピューターのセキュリティを破るために使用されています。代わりにfgets()を使用します。
私が見るほとんどどこでも scanf
同じ問題を抱えるはずの方法で使用されている(バッファオーバーフロー/バッファオーバーラン): scanf("%s",string)
. 。この場合、この問題は存在しますか?なぜそれについての参照がないのか scanf
男ページ? GCCがこれをコンパイルするときに警告しない理由 -Wall
?
PS:文字列の最大長をフォーマット文字列で指定する方法があることを知っています scanf
:
char str[10];
scanf("%9s",str);
編集:前のコードが正しいかどうかを判断するように求めていません。私の質問は次のとおりです scanf("%s",string)
常に間違っているのですが、なぜ警告がなく、Manページには何もないのですか?
解決
答えは、単に誰もGCCにコードを書いて、その警告を作成していないということです。
あなたが指摘するように、の特定のケースに対する警告 "%s"
(フィールド幅がない)が非常に適切です。
ただし、これはの場合のみであることに留意してください scanf()
, vscanf()
, fscanf()
と vfscanf()
. 。このフォーマット仕様は、完全に安全です sscanf()
と vsscanf()
, 、したがって、その場合は警告を発行しないでください。これは、既存の「scanfスタイルの形式」分析コードに単純に追加できないことを意味します。それを「FSCANFスタイル形式のストリング」および「SSCANFスタイルの形式」オプションに分割する必要があります。
GCCの最新バージョン用のパッチを作成すると、受け入れられる可能性が高くなります(もちろん、GlibCヘッダーファイルにもパッチを送信する必要があります)。
他のヒント
使用 gets()
決して安全ではありません。 scanf()
あなたがあなたの質問で言ったように、安全に使用することができます。ただし、安全に使用しているかどうかを判断することは、コンパイラがワークアウトするのがより難しい問題です(たとえば、電話をかけている場合 scanf()
バッファーを渡し、文字が引数としてカウントされる関数では、それは伝えることができません)。その場合、あなたが何をしているのかを知っていると仮定する必要があります。
コンパイラがのフォーマット文字列を見ると scanf
, 、文字列が見えます!これは、フォーマット文字列が実行時に入力されないと仮定しています。 GCCのような一部のコンパイラには、コンパイル時間に入力した場合、フォーマット文字列を分析するための追加の機能があります。この追加機能は包括的ではありません。状況によっては、Cのような言語には実行時間のオーバーヘッドが必要であるため、たとえば、この場合に追加の隠されたコードを挿入せずに安全でない使用法を検出できます。
char* str;
size_t size;
scanf("%z", &size);
str = malloc(size);
scanf("%9s"); // how can the compiler determine if this is a safe call?!
もちろん、安全なコードを書く方法があります scanf
読み取る文字の数を指定し、文字列を保持するのに十分なメモリがあることを指定した場合。の場合 gets
, 、読む文字の数を指定する方法はありません。
SCANFのManページがバッファオーバーランの確率に言及していない理由はわかりませんが、Vanilla Scanfは安全なオプションではありません。かなり古いリンク - http://blogs.msdn.com/b/rsamona/archive/2005/10/24/4844449.aspx これをケースとして示しています。また、これを確認してください(GCCではありませんが、それにもかかわらず) - http://blogs.msdn.com/b/parthas/archive/2006/12/06/application-crash-on-replacing-sscanf-with-sscanf-s.aspx
SCANFは、データの読み取り量に基づいてヒープ上のスペースを割り当てるだけです。バッファを割り当てず、null文字が読み取られるまで読み取られないため、バッファーを上書きするリスクはありません。代わりに、ヌル文字が見つかるまで独自のバッファーに読み取り、おそらく読み取りの最後にある別の正しいサイズにバッファをコピーします。