2016-11-04 3 views
1
scanf_s("%s", a, 10); 

このコードは、プログラムをバッファオーバーフローの悪用から守ります。scanfの幅指定とscanf_sの相違点

しかし scanf_sせずに、私たちは書くことができます。

scanf("%9s", a); 

私はこのコードは、バッファオーバーフローをブロックすると思います。これは本当ですか?

したがって、基本的に2つの方法の違いは何ですか?

また、scanfの幅指定がバッファオーバーフローをブロックしている場合、元のscanfを「安全でない」と呼びますか?

答えて

3

scanf_s()は、C99標準(または以前のもの)では記述されていません。

C99(またはそれ以前)をターゲットとするコンパイラを使用する場合は、scanf()を使用します。 C11 Standardの場合、buffer overflowsに対してセキュリティを強化するためにscanf_s()はscanf()よりもはるかに難しいです。

したがって、基本的に2つの方法の違いは何ですか?

scanf_s()は、より安全なバージョンのscanf()です。宛先を指定する引数の後に、宛先のサイズを指定する必要があります。プログラムは、コピーする前にバッファが指定されたサイズであることをチェックして、上書きがなく、悪意のあるコードが実行されていないことを確認します。引数はscanf_s()の場合に渡される必要があります。

また、scanfの幅指定がバッファオーバーフローをブロックしている場合、元のscanfを「安全でない」と呼びますか?

scanfで使用できるフォーマット指定子は、入力の最大サイズを制限し、バッファオーバーフローを防ぐ明示的なフィールド幅の設定をサポートしています。しかし、フィールド幅がembedded into format stringでなければならないので、scanf()の機能は使いにくいです(printfで実行できるように、可変引数を渡す方法はありません)。 scanfは実際にはそれほどうまく設計されていません。しかし、scanfが文字列バッファオーバーフローの安全性に関して何とか絶望的に壊れているという主張は完全に虚偽であり、通常は怠惰なプログラマによって作られています。

scanf()の実際の問題は、あまりオーバーフローしているにもかかわらず、まったく異なる性質を持っています。 scanf関数を使用して数値の小数表現を算術型の値に変換すると、算術オーバーフローから保護されません。オーバーフローが発生した場合、scanfは未定義の動作を生成します。このため、C標準ライブラリで変換を実行する唯一の正しい方法は、strtoファミリの関数です。

したがって、上記を要約すると、scanfの問題は、文字列バッファで適切かつ安全に使用することが難しいということです。また、算術入力には安全に使用することはできません。後者は本当の問題です。前者は不便です。それはprintfで行うことができるように

scanf_sは(scanf()フィールドの幅がembedded into format stringなければならない)、可変長引数を介してフィールド幅を通過させることによって、文字列の場合にバッファオーバーフローの問題を解決します。また、フィールド幅はscanf_sでは必須ですが、scanfではオプションです。

+0

ありがとうございます。しかしもう1つの疑問は、算術オーバーフローからscanf_sは安全ですか? scanf_sはこの問題をどのように解決しましたか? – Gear

+1

私は自分の答えを編集しました。 – abhiarora

+0

C標準の関数 'scanf_s()'は数値入力の算術オーバーフロー(アンダーフロー)に対する保護を提供していないことに注意してください。少なくとも 'scanf C11規格のK.3.5.3.2。 –