質問への回答文字列を読み取り、それを比較するCでは、複数の人がstrcmp()
、次のようなことを言っています
また、今後、多くの問題を回避するために、strncmp()の使用に慣れるよう強くお勧めします。
または( 文字列の比較が失敗するのはなぜですか? )
Strcmpではなくstrncmpを使用していることを確認してください。 strcmpは非常に危険です。
彼らは何の問題を暗示しているのですか?
scanf()
with string specifiers および gets()
は強く非推奨 である理由は、それらがほぼ必然的にバッファオーバーフローの脆弱性につながるためです。しかし、strcmp()
でバッファをオーバーフローさせることはできませんよね?
「バッファオーバーフロー、またはバッファオーバーランは、プログラムがバッファにデータを書き込んでいる間に、バッファの境界をオーバーランし、隣接するメモリを上書きする異常です。」
(- Wikipedia:バッファオーバーフロー )。
Strcmp()関数がバッファーに書き込むことはないため、strcmp()関数はバッファーオーバーフローを引き起こすことはできません。
人々がstrcmp()
の使用を思いとどまらせ、代わりにstrncmp()
を推奨する理由は何ですか?
strncmp
はバッファのオーバーランを防ぐことができますが、その主な目的はsafetyではありません。むしろ、それはaの最初のN文字だけを比較したい場合のために存在します(正しく NULで終わる可能性がある)文字列。
man page から:
strcmp()
関数は、2つの文字列_s1
_と_s2
_を比較します。 _s1
_がそれぞれ見つかった場合、0より小さい、等しい、またはより大きい整数が返され、_s2
_より小さい、一致する、またはより大きい.
strncmp()
関数は似ていますが、_s1
_と_s2
_の最初の(最大で)n
バイトのみを比較します。
この場合、strncmp
を単純なmemcmp
に置き換えることはできません。これは、文字列の1つがn
よりも短い場合は、NULストップ時の動作を利用する必要があるためです。
strcmp
によってバッファオーバーランが発生する場合は、次の2つのいずれかが当てはまります。
memcmp
を使用する必要があります。バッファの終わりを過ぎたreadingはbuffer overrunと見なされることに注意してください。 無害に見えるかもしれませんが終わりを過ぎてwritingと同じくらい危険です。
読み取り、書き込み、実行...それは問題ではありません。意図しないアドレスへのメモリ参照は、未定義の動作です。最も明らかなシナリオでは、プロセスのアドレス空間にマップされていないページにアクセスしようとすると、ページ違反が発生し、その後SIGSEGVが発生します。最悪の場合、\ 0バイトに遭遇することもありますが、他のバッファーに遭遇してプログラムの動作が不安定になることがあります。
文字列は、定義により「最初のヌル文字で終了し、最初のヌル文字を含む連続した文字のシーケンス」です。
strncmp()
がstrcmp()
より安全である唯一のケースは、2つの文字配列を文字列として比較する場合、両方の配列が少なくともn
であることが確実です。バイト長(strncmp()
に渡される3番目の引数)、そしてnot両方の配列に文字列が含まれている(つまり、_'\0'
_ null文字ターミネータが含まれている)ことは確かです。
ほとんどの場合、コード(それが正しければ)は、nullで終わる文字列を含むはずの配列に実際にnullで終わる文字列が含まれることを保証します。
strncmp()
に追加されたn
は、安全でないコードを安全にする魔法の杖ではありません。 NULLポインター、初期化されていないポインター、初期化されていない配列、n
の不正な値、または不正なデータの受け渡しから保護しません。どちらの機能でも、足元で自分を撃つことができます。
そして、あなたがあなたの配列でstrcmp
またはstrncmp
を呼び出すことを試みている場合、thoughtはnullで終了する文字列を含みましたが実際には含まれていません、そしてあなたのコードはすでにバグがあります。 strncmp()
を使用すると、そのバグの直接の症状を回避するのに役立つ場合がありますが、修正はされません。
strcmp
は、2つの文字列を比較して、違いが検出されるか、\0
がその1つで見つかるまで比較します。
一方、strncmp
は、比較する文字数を制限する方法を提供するため、文字列が\0
で終わっていない場合、サイズ制限に達した後、関数はチェックを続行しません。 。
この2つのメモリ領域で2つの文字列を比較するとどうなるか想像してみてください。
0x40, 0x41, 0x42,...
0x40, 0x41, 0x42,...
そして、最初の2つの文字だけに関心があります。どういうわけか\0
が文字列の末尾から削除されており、3番目のバイトが2つの領域で偶然一致しています。 strncmp
パラメータが2の場合、num
はこの3番目のバイトの比較を回避します。
[〜#〜] edit [〜#〜]以下のコメントが示すように、この状況は、言語の誤った使用または非常に具体的な使用に由来します。