2009-06-01 6 views
5

が、私はこのようなものをやろう:なぜMSVC++は "std :: strcat"を "安全でない"とみなしていますか? (C++)

char* prefix = "Sector_Data\\sector"; 
char* s_num = "0"; 
std::strcat(prefix, s_num); 
std::strcat(prefix, "\\"); 

などなど、私は警告を取得し

warning C4996: 'strcat': This function or variable may be unsafe. Consider using strcat_s instead. 

なぜstrcatのが危険とみなされ、そして方法がありますstrcat_sを使わずにこの警告を取り除くには?唯一の方法は警告を取り除くために場合

はまた、それが動作しないか、strcat_sを使用することです(構文ワイズ:どうやら、それは2つの引数を取りません)。

+13

あなたの例がひどく間違っていることを知っておくべきです。文字列定数(char * s = "hello";など)は書き込み可能ではありません。あなたが運が良ければ、クラッシュするでしょう、あなたが不運な場合は、アプリケーションがいくつかの微妙な方法で正しく実行されません。 適切な方法は、次のようなものです。 接頭辞[SIZE] = "Sector_Data \\ sector"; SIZEはプレフィックスを保持するのに十分な大きさで、追加する予定のものは何でも構いません。 –

+3

書かれているように、あなたの例にはバッファオーバーフローが含まれています。可能なバッファオーバーフローだけではなく、特定のバッファオーバーフロー。 –

答えて

26

バッファのプレフィックスは、バッファオーバーランの原因となるよりも少ないスペースでコピーできます。 したがって、ハッカーは特別に細工された文字列を渡すことができ、リターンアドレスやその他の重要なメモリを上書きし、プログラムのコンテキストでコードの実行を開始します。

strcat_sあなたは、文字列をコピーする先のバッファの長さに渡すことを強制することでこれを解決。バッファがオーバーランしていないことを確認するために、必要に応じて文字列を切り捨てます。

google strcat_sを使用する方法を正確に確認してください。

+1

strcat_sは、CRTのセキュリティ強化の一部としてリリースされた関数のライブラリの1つです。http://msdn.microsoft.com/en-us/library/8ef0s5kh(VS.80).aspx – Sean

+3

真実は、これは、あなたが書いたコードをWindows以外の場所でもコンパイルできないようにするために、マイクロソフトに代わって恐れているだけのことです。'strcat_s'は独自の' strncat'(これは40年ぐらいの間)です。さらに、 'strcat'は最初は安全ではなく、' strlen'によって与えられた長さの 'strcat_s'も安全です。安全でないものは、盲目的に任意の(そして任意の長さの)ユーザー入力を受け入れていますが、非標準関数を使用してもその問題は解決されません。別の関数( 'strlen')でのみクラッシュします。 – Damon

+1

@DeadMG: 'strcat_s 'を使うということは、合計サイズから最初の長さを引く必要はないということですが、それ以外はまったく同じです。しかし、一般的に私の主張は、「安全な」機能を使用しても何も安全ではないということです。あなたは、あなたのプログラムの文字列リテラルのようないくつかのデータを信じることができるか、それを信頼できないことを知っています(ユーザが入力したデータ)。そうでない場合、いずれの「安全な」機能が使用されていても、すべてが失われます。同じことがstrncatにも当てはまります... – Damon

3

それはあなたのケースでは、宛先の文字列(接頭辞)がその境界を越えて書き込まれるかどうかをチェックする手段がないので。 strcatは本質的に、ソース文字列を宛先にバイト単位でコピーするループ処理を行います。ヌル端末と呼ばれる値「0」( '\ 0'で表記)を見ると停止します。 Cには境界チェックが組み込まれておらず、dest strはメモリ内の単なる場所であるため、strcatは元のstrまたはdestを吹き飛ばしてもad-infinidiumを続けます。 strにはヌル端末がありません。

上記の解決策は、ご使用のWindows環境に応じて異なります。あなたは、プラットフォームに依存しない何かをしたい場合は、strncatと口論する必要があります。

strncat(char* dest, const char* src, size_t count) 

これは、インテリジェントに使用される別のオプションです。 countを使用して、コピーする最大文字数を指定することができます。これを行うには、destにどれくらいのスペースがあるかを調べなければなりません(strlen(dest)をどのくらい割り当てたか)、それをcountとして渡してください。

+1

strncatでも安全ではありません。 MSDNより: strncatはstrDestの十分なスペースをチェックしません。バッファオーバーランの潜在的な原因となります。 countは、付加される文字の数を制限することに留意してください。 strDestのサイズに制限はありません。以下の例を参照してください。詳細については、「バッファオーバーランの回避」を参照してください。 –

+0

宛先バッファに十分な領域があるかどうかは、言語の範囲外であり、OS /コンパイラによって追加の機能が必要です。 –

+2

MSDNはstrncat()について意味を持ちません。それはプログラマーにサイズを入力させ、2つのサイズを1つのサイズと同じように間違えさせることができます。 strncpy()のようなstrncat()の問題は、限られた長さのstrcat()(またはstrcpy())と同じことをしないということです。 –

4

C/C++の文字列操作関数の1つで、バッファオーバーランエラーが発生する可能性があります。

問題は、関数がバッファのサイズがわからないことです。 MSDNのドキュメントから:

最初の引数、strDestination、 は 現在strDestinationとstrSource組み合わせ とクロージング「\ 0」を保持するのに十分な大きさでなければなりません。 、バッファオーバーランが発生する可能性があります。

strcat_sには、バッファのサイズを示す追加の引数があります。これにより、連結を行う前にサイズを検証することができ、オーバーランを防ぐことができます。あなたは、C++を使用している場合は、なぜ全体の混乱を避け、std::stringを使用しないでhttp://msdn.microsoft.com/en-us/library/d45bbxx4.aspx

+0

+1実際の文書へのリンクを提供しています。 – Eclipse

+0

'strcat_s'の引数がコンパイラによって正しいかどうか、あるいは' strcat_s'の動作がエラーに依存しているかどうかがチェックされていれば...残念ながらどちらもそうではありません。 – Deduplicator

28

を参照してください。エラーのない同じ例は、次のようになります。

std::string prefix = "Sector_Data\\sector"; 
prefix += "0"; 
prefix += "\\" 

バッファサイズとそのすべてのことを心配する必要はありません。 const char *のAPIをお持ちの場合は、.c_str()のメンバーだけを使用できます。追加することにより、あなたはこれらの警告を取り除くことができます

some_c_api(prefix.c_str()); 
+4

根本的な問題に対する良い答えを見てうれしいです。私ができるなら、私は一回以上upvoteしたいと思います。 –

4

_CRT_SECURE_NO_WARNINGS 

し、プロジェクトのプリプロセッサ定義に

_SCL_SECURE_NO_WARNINGS 

+0

はい、上記のフラグを使用して警告メッセージを表示しないようにすると、移植性のあるコードを記述したい場合に最適です。 strcat_sを使用すると、移植可能でないコードになる可能性があります。これは、Microsoftコンパイラ固有のものです。 –

0

strcatには2つの問題があります。まず、あなたはほとんどの機能と同じである仕事をして、関数の外ですべてのあなたの検証を行う必要があります:

あなたはちょうどそれが収まることを確認するために、両方の文字列の長さ全体を歩いする必要が
if(pDest+strlen(pDest)+strlen(pScr) < destSize) 

、コピーをするために全長をもう一度歩く前に。このため、多くのプログラマーは、テストに合ってスキップすると単純に仮定します。さらに悪いことに、コードが最初に書かれたときに適合するように保証されているかもしれませんが、誰かが別のstrcatを追加したり、プログラムのどこか他の場所でバッファサイズや定数を変更すると、問題が発生することがあります。

もう1つの問題は、pSrcとpDstが重複している場合です。あなたのコンパイラに依存して、strcatはpSrcの0の文字を一度にチェックする単純なループかもしれません。 pDstが0を上書きすると、プログラムがクラッシュするまで実行されるループに入ります。

4

警告をオフにするには、これを行うことができます。

#pragma warning(disable:4996) 

btw strcat_s()を使用することを強くお勧めします。

関連する問題