web-dev-qa-db-ja.com

fopen_sはどのようにしてfopenよりも安全ですか?

Windowsプラットフォームのレガシーコードに取り組んでいます。 VS2013でコードをコンパイルすると、次の警告が表示されます。

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

また、sprintfに対して同様の警告を表示します。バッファオーバーフローのため、sprintf_sはsprintfよりも安全であると理解しています。

しかし、どうすれば fopen_sfopenよりも安全であり、fopenはバッファを受け入れないため、バッファオーバーフローの可能性はありません。 fopenが安全ではなく、fopen_sが安全であるケースを誰かが提供できますか?

22
ZijingWu

この場合、sは「安全」を表すのではなく、「セキュリティ強化」を表します。 fopen_sの場合、ファイルを開こうとする前に、パラメーターの有効性がチェックされます。

fopenを使用すると、ファイル名にNULLポインターを渡すことができ、すべてがバラバラになる可能性があります。 fopen_sにはその問題はありません (a)

fopen_sのようなこれらの境界チェックインターフェイスは、ISO標準のオプションの一部であり、付録K(C11のように)で詳しく説明されていることに注意してください。とにかく)。実装はそれらを提供するために必要ではなく、正直なところ、fopenや他の多くのいわゆる安全でない関数は完全に安全ですあなたがコーダーとして何をしているのか知っているなら。

fopen_sはNULLポインターをトラップしますが、無効なポインターはトラップしないため、安全ではなくセキュリティが強化されていることに注意してください。無効であるがNULL以外のポインターを渡すと、損傷が発生する可能性があります。

宛先バッファサイズを指定するように強制する他の「安全な」関数も、正しいサイズを渡した場合にのみ安全です。大きすぎるものを渡すと、すべての賭けが無効になります。


(a)C11 K.3.5.2.1 The fopen_s functionから:

errno_t fopen_s (
    FILE * restrict * restrict streamptr,
    const char * restrict      filename,
    const char * restrict      mode);

ランタイム-制約

Streamptr、filename、またはmodeのいずれもnullポインターであってはなりません。

実行時制約違反がある場合、fopen_sはファイルを開こうとしません。さらに、streamptrがnullポインターでない場合、fopen_sは* streamptrをnullポインターに設定します。

これをC11 7.20.5.3 The fopen functionと比較してください。これは、ファイル名とモードの両方が文字列を指している必要があることを示していますが、NULLポインターを指定した場合に何が起こるかを指定していません(ほとんどの実装は、NULLポインターの逆参照でクラッシュする可能性があります)。

25
paxdiablo