web-dev-qa-db-ja.com

Visual Studioで「安全でない」警告/エラーを取り除く方法(strcpy、sprintf、strdup)

Strcpy、sprintfなどが安全でないというコンパイラの警告を取り除こうとしています。安全でない理由はわかりますが、C++スタイルでコードを修正する良い方法は考えられません。

次にコードの抜粋を示します。

extList->names[i]=(char *)malloc(length*sizeof(char));
strcpy(extList->names[i],extName);                     // unsafe
// strncpy(extList->names[i],extName,length);          // also unsafe

ここにメッセージがあります:

C4996: 'strcpy':この関数または変数は安全でない可能性があります。代わりにstrcpy_sの使用を検討してください。非推奨を無効にするには、_CRT_SECURE_NO_WARNINGSを使用します。詳細については、オンラインヘルプを参照してください。

コピーするものの長さを知らなければ、C++でデータをコピーする安全な方法は考えられません。 strlen()があることは知っていますが、データがnullで終了していると(おそらく誤って)想定しているため、これも安全ではありません。

また:

// used to concatenate:
sprintf(extStr,"%s%s",platExtStr,glExtStr);

C4996: 'sprintf':この関数または変数は安全でない可能性があります。代わりにsprintf_sの使用を検討してください。非推奨を無効にするには、_CRT_SECURE_NO_WARNINGSを使用します。詳細については、オンラインヘルプを参照してください。

Std :: stringを使用して連結するのは簡単ですが、データを何らかの方法でextStrに取り込む必要があります(strcpy、lolは使用しません)。 string :: c_str()関数は変更不可能なデータへのポインターを返すため、extStrをそれに等しく設定することはできません。 (そして、c_str()ポインターが後で呼び出される削除が必要かどうかさえわかりませんか?「新しい」を使用してスペースを割り当てますか?)

これについて何かアドバイスはありますか?これは私のものではない10,000行のファイルの一部です...そのため、C++の方法で物事を書き直すことには熱心ではありません。

21
Andre

それらを無効にするためのプラグマは実際には必要ありません。

Win32/msvcの場合、ProjectProperties-> Configuration Properties-> C/C++-> Preprocessor-> Preprocessor Definitionsで、次のマクロを追加します。

_CRT_SECURE_NO_DEPRECATE  
_CRT_NONSTDC_NO_DEPRECATE

または、コマンドラインパラメーター(-D_CRT_SECURE_NO_DEPRECATE)でこれを渡すことができます。おそらく、特定の* .cppファイルの先頭でこれらを定義できます。また、おそらくもっと多くあります(crtdefs.hを参照してください-たくさんあるようです...)。これらの種類の警告は通常、どのマクロを無効にできるかを通知します-コンパイラの出力を読み取るだけです。

35
SigTerm

この質問に対する別の回答を次に示します。

#ifdef _MSC_VER
#pragma warning(Push)
#pragma warning(disable : 4996)
#endif

        strcpy(destination, source);

#ifdef _MSC_VER
#pragma warning(pop)
#endif
7
PapaAtHome

警告のみを取り除くことがあなたの目的である場合...単にこれを定義する_CRT_SECURE_NO_WARNINGSそして、それはすべての廃止警告を抑制します。しかし、これは安全でないCRT関数の根本的な問題を修正しません。

Visual Studioバージョン> = 2005を使用していて、これらの警告を適切な方法で修正したい場合...最も簡単な方法は#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES 1および#define _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT 1プロジェクト内。

コードをさらに変更しなくても、ほとんどの警告が自動的に修正されることがわかります。このウィンドウを定義することにより、安全でないCRT関数のほとんどに対して、安全なオーバーロードされた関数が自動的に呼び出されます。静的配列のバッファサイズは自動的に計算されます。

動的に割り当てられたバッファはこの方法では修正されませんが、手動で修正する必要があります。詳細は このリンク を参照してください。

以下はプログラムでサンプルを修正する方法です

strcpy_s(extList->names[i], length, extName); 
6
V M Rakesh

あなたはどれだけコピーするか知っています-あなたはそれにスペースを割り当てました!

確かに、割り当てられたスペースよりも多くを喜んでコピーしませんか?

コピーするアイテムの数を制限することにより、バッファオーバーランを明示的に回避する方法を使用したいと思います。私がCプログラマだった頃に

dest = malloc(len);         // note: where did we get len?
if ( dest is null )  panic!  // note: malloc can fail
strncpy(dest, src, len);
dest[len-1] =0;

これは少し面倒で、strncpy()を使用していることが指摘されています。このメソッドは、本来文字列ではなく固定幅フィールド用に設計されたものです。しかしそれはach

Strdup()やstrlcpy()のようなメソッドがあります。

私のおすすめ:

1)。ターゲットは警告を抑制することではなく、コードを堅牢にすることです。

2)。文字列をコピーするときは、次のことを確認する必要があります。

  • 不正な入力(たとえば、終了していない文字列や過度に長い文字列)から身を守ります。
  • Mallocの失敗から身を守ってください。
  • ヌルが表示されるまで、コピーするよりもカウントされた文字数のコピーを強く推奨します
  • 文字列を作成すると主張する場合は、それをnullで終了するようにしてください。

環境でstrlcpy()が使用可能な場合は、それを使用できます。そうでない場合は、独自の小さなユーティリティ関数を作成してみませんか?次に、ローカライズした関数だけに警告がある場合は、問題があります。

5
djna

最初の例では、すでに長さがわかっています。 _length+1_バイトを割り当てていないので、lengthはnullターミネータを含むと想定します。その場合は、単に_std::copy_文字列:std::copy(extName, extName + length, expList->names[i]);

ソース文字列がnullで終了していると想定する2番目の例では、宛先文字列の長さを計算して_std::copy_を再度使用して手動で連結するか、または_std::string_と_std::copy_を使用して_c_str_を宛先に追加します(ここでも、十分なスペースを割り当てたと仮定します)。

c_str()は、外部削除を必要とするメモリを割り当てません。

最後に、sizeof(char)は常に1であるため、mallocでは冗長ですが、その文字のビット数は8ではない場合があります(_CHAR_BIT_を参照)。

4
Mark B

すべての関数呼び出しを置き換える必要があると思います 可能なら 独自の実装を呼び出す。ここでの良い例は、strcpyを置き換え、その内部でコンパイラ固有のバージョンのstrcpyを呼び出す関数です。実装は、特にプラットフォーム/コンパイラーを追加または変更する場合、選択したコンパイラーに合わせて簡単に変更できます。

例:


char* StringCopy(char* Destination, const char* Source, size_t DestinationSize)
{
#ifdef _MSC_VER
  return strcpy_s(Destination, Source, DestinationSize);
#else
  if(!(strlen(Source) >= DestinationSize))
     return strcpy(Destination, Source);
  else
     return 0x0;
#endif
}
2
Simon

移植性が問題にならない場合は、 'strcpy_s' を使用できます。

2
oefe

このコードをWindowsプラットフォーム用にのみコンパイルする場合は、これらの関数の保護されたバージョンを使用することをお勧めします。ただし、このコードが複数のプラットフォーム(linux、Aixなど)でコンパイルされる場合は、_CRT_SECURE_NO_WARNINGSを使用してWindowsプロジェクト構成ファイル(.vcxprojなど)の警告を無効にするか、次のようなコードスニペットを使用できます。これは、.cppファイルでこれらの関数が呼び出された場所にあります。

#if _OS_ == _OS__WINDOWS
//secure function call
#else
//already written code
#endif
0

メッセージで提案されているように、_CRT_SECURE_NO_WARNINGSを使用してこの警告を無効にします。

projectProperties-> Configuration Properties-> C/C++-> Preprocessor-> Preprocessor Definitionsで、次のマクロを追加します。

_CRT_SECURE_NO_WARNINGS

0
cheng