web-dev-qa-db-ja.com

strcmpの何が問題になっていますか?

質問への回答文字列を読み取り、それを比較するCでは、複数の人がstrcmp()、次のようなことを言っています

また、今後、多くの問題を回避するために、strncmp()の使用に慣れるよう強くお勧めします。

または( 文字列の比較が失敗するのはなぜですか?

Strcmpではなくstrncmpを使用していることを確認してください。 strcmpは非常に危険です。

彼らは何の問題を暗示しているのですか?

scanf() with string specifiers および gets()は強く非推奨 である理由は、それらがほぼ必然的にバッファオーバーフローの脆弱性につながるためです。しかし、strcmp()でバッファをオーバーフローさせることはできませんよね?

「バッファオーバーフロー、またはバッファオーバーランは、プログラムがバッファにデータを書き込んでいる間に、バッファの境界をオーバーランし、隣接するメモリを上書きする異常です。」

(- Wikipedia:バッファオーバーフロー )。

Strcmp()関数がバッファーに書き込むことはないため、strcmp()関数はバッファーオーバーフローを引き起こすことはできません。

人々がstrcmp()の使用を思いとどまらせ、代わりにstrncmp()を推奨する理由は何ですか?

13
David Cary

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つのいずれかが当てはまります。

  1. データはNULで終了する必要はなく、代わりにmemcmpを使用する必要があります。
  2. データはNULで終了することが期待されていますが、NULで終了していないために、バッファーにデータを入力するときにすでに混乱しています。

バッファの終わりを過ぎたreadingbuffer overrunと見なされることに注意してください。 無害に見えるかもしれませんが終わりを過ぎてwritingと同じくらい危険です。

読み取り、書き込み、実行...それは問題ではありません。意図しないアドレスへのメモリ参照は、未定義の動作です。最も明らかなシナリオでは、プロセスのアドレス空間にマップされていないページにアクセスしようとすると、ページ違反が発生し、その後SIGSEGVが発生します。最悪の場合、\ 0バイトに遭遇することもありますが、他のバッファーに遭遇してプログラムの動作が不安定になることがあります。

17

文字列は、定義により「最初のヌル文字で終了し、最初のヌル文字を含む連続した文字のシーケンス」です。

strncmp()strcmp()より安全である唯一のケースは、2つの文字配列を文字列として比較する場合、両方の配列が少なくともnであることが確実です。バイト長(strncmp()に渡される3番目の引数)、そしてnot両方の配列に文字列が含まれている(つまり、_'\0'_ null文字ターミネータが含まれている)ことは確かです。

ほとんどの場合、コード(それが正しければ)は、nullで終わる文字列を含むはずの配列に実際にnullで終わる文字列が含まれることを保証します。

strncmp()に追加されたnは、安全でないコードを安全にする魔法の杖ではありません。 NULLポインター、初期化されていないポインター、初期化されていない配列、nの不正な値、または不正なデータの受け渡しから保護しません。どちらの機能でも、足元で自分を撃つことができます。

そして、あなたがあなたの配列でstrcmpまたはstrncmpを呼び出すことを試みている場合、thoughtはnullで終了する文字列を含みましたが実際には含まれていません、そしてあなたのコードはすでにバグがあります。 strncmp()を使用すると、そのバグの直接の症状を回避するのに役立つ場合がありますが、修正はされません。

6
Keith Thompson

strcmpは、2つの文字列を比較して、違いが検出されるか、\0がその1つで見つかるまで比較します。

一方、strncmpは、比較する文字数を制限する方法を提供するため、文字列が\0で終わっていない場合、サイズ制限に達した後、関数はチェックを続行しません。 。

この2つのメモリ領域で2つの文字列を比較するとどうなるか想像してみてください。

0x40, 0x41, 0x42,...0x40, 0x41, 0x42,...

そして、最初の2つの文字だけに関心があります。どういうわけか\0が文字列の末尾から削除されており、3番目のバイトが2つの領域で偶然一致しています。 strncmpパラメータが2の場合、numはこの3番目のバイトの比較を回避します。

[〜#〜] edit [〜#〜]以下のコメントが示すように、この状況は、言語の誤った使用または非常に具体的な使用に由来します。