How can fopen_s be more safe than fopen?

ZijingWu picture ZijingWu · Oct 16, 2013 · Viewed 15.5k times · Source

I'm working on legacy code for Windows platform. When I compile the code in VS2013, it give following warning:

error C4996: 'fopen': This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details."

And it will also give samiliar warning for sprintf. I understand sprintf_s is more safe than sprintf because of buffer overflow.

But how can be fopen_s be more safe than fopen, there is no chance of buffer overflow because fopen doesn't accept an buffer. Can anyone provide an case fopen is unsafe, and fopen_s is safe?

Answer

paxdiablo picture paxdiablo · Oct 16, 2013

The s doesn't stand for "safe" in this case, it stands for "security enhanced". For fopen_s, the parameters are checked for validity before attempting to open the file.

With fopen, you can pass a NULL pointer for the filename and everything will most likely fall to pieces. fopen_s doesn't have that problem (a).

Keep in mind that these bounds checking interfaces like fopen_s are an optional part of the ISO standard, detailed in Annex K (as at C11, anyway). Implementations are not required to provide them and, to be honest, fopen, and many other so-called unsafe functions, are perfectly safe if you know what you're doing as a coder.

It's interesting to note that fopen_s will trap NULL pointers for you but not invalid pointers, hence why it's security enhanced rather than safe - you can still cause some damage if you pass an invalid but non-NULL pointer.

Other "safe" functions which force you to provide destination buffer sizes are also safe only as long as you pass the right size. Pass something too big and all bets are off.


(a) From 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);

Runtime-constraints

None of streamptr, filename, or mode shall be a null pointer.

If there is a runtime-constraint violation, fopen_s does not attempt to open a file. Furthermore, if streamptr is not a null pointer, fopen_s sets *streamptr to the null pointer.

Contrast that with C11 7.20.5.3 The fopen function which states that the filename and mode must both point to a string but don't specify what happens if you provide a NULL pointer (most implementations would likely crash with a null pointer dereference).