How can fopen_s be more safe than fopen?

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).


Back when VS2005 came out I thought it was simply Microsoft going too far with their "let's make proprietary functions instead of giving people snprintf()", since both would (by default) raise a win32 exception if passed a NULL pointer (though fopen would raise STATUS_ACCESS_VIOLATION whereas fopen_s would raise STATUS_INVALID_PARAMETER). Which means both would result in the program crashing immediately unless Win32-specific code is added to handle the exception.

However, a peek in the CRT source code did reveal one small difference: The sharing flags used by fopen are fully permissive, whereas those used by fopen_s forbid other processes from opening the file for writing. In that way, fopen_s is more secure since it means the file won't change under your process's feet.