10

次のコードはエラーを引き起こし、アプリケーションを強制終了します。バッファーの長さはわずか 10 バイトで、テキストの長さは 22 バイトであるため (バッファー オーバーフロー)、これは理にかなっています。

char buffer[10];    
int length = sprintf_s( buffer, 10, "1234567890.1234567890." ); 

アプリケーションをクラッシュさせずに報告できるように、このエラーをキャッチするにはどうすればよいですか?

編集:

以下のコメントを読んだ後、_snprintf_s を使用しました。-1 値を返す場合、バッファは更新されていません。

length = _snprintf_s( buffer, 10, 9, "123456789" );
printf( "1) Length=%d\n", length ); // Length == 9

length = _snprintf_s( buffer, 10, 9, "1234567890.1234567890." );
printf( "2) Length=%d\n", length ); // Length == -1

length = _snprintf_s( buffer, 10, 10, "1234567890.1234567890." );
printf( "3) Length=%d\n", length ); // Crash, it needs room for the NULL char 
4

6 に答える 6

17

それは設計によるものです。sprintf_sおよびファミリの他の関数の要点は、*_sバッファ オーバーラン エラーをキャッチし、それらを前提条件違反として扱うことです。これは、実際には回復可能であることを意図していないことを意味します。sprintf_sこれは、エラーのみをキャッチするように設計されています。文字列が宛先バッファーに対して大きすぎる可能性があることがわかっている場合は、呼び出してはいけません。その場合は、strlen最初に使用して、トリミングが必要かどうかを確認して決定します。

于 2009-10-01T19:49:19.343 に答える
8

の代わりに、( Windows では別名)sprintf_sを使用できます。snprintf_snprintf

#ifdef WIN32
#define snprintf _snprintf
#endif

char buffer[10];    
int length = snprintf( buffer, 10, "1234567890.1234567890." );
// unix snprintf returns length output would actually require;
// windows _snprintf returns actual output length if output fits, else negative
if (length >= sizeof(buffer) || length<0) 
{
    /* error handling */
}
于 2009-10-01T20:06:55.890 に答える
6

これは VC++ で動作し、snprintf を使用するよりもさらに安全です (そして _snprintf よりも確実に安全です):

void TestString(const char* pEvil)
{
  char buffer[100];
  _snprintf_s(buffer, _TRUNCATE, "Some data: %s\n", pEvil);
}

_TRUNCATE フラグは、文字列を切り捨てる必要があることを示します。この形式では、バッファーのサイズは実際には渡されません。これが (逆説的に!) とても安全な理由です。コンパイラはテンプレート マジックを使用してバッファ サイズを推測します。つまり、バッファ サイズを誤って指定することはできません (驚くほど一般的なエラーです)。この手法を適用して、他の安全な文字列ラッパーを作成することもできます。これについては、私のブログ投稿 ( https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/ ) で説明されています。

于 2014-11-22T00:41:25.100 に答える