24

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?

Deduplicator
  • 41,806
  • 6
  • 61
  • 104
ZijingWu
  • 3,070
  • 3
  • 21
  • 38
  • The documentation site you linked to has [this link](http://msdn.microsoft.com/zh-cn/library/8ef0s5kh(v=vs.90).aspx) on the very first page. –  Oct 16 '13 at 05:52
  • @H2CO3, I have checked this page, but it doesn't mension fopen and fopen_s – ZijingWu Oct 16 '13 at 06:56

2 Answers2

27

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

paxdiablo
  • 772,407
  • 210
  • 1,477
  • 1,841
  • When you say "fall to pieces" are you means fopen will crash, but fopen_s will return error? – ZijingWu Oct 16 '13 at 06:59
  • 1
    @ZijingWu, yes, that's the most likely case. An implementation of `fopen` _could_ catch a NULL filename or mode, and return an error, but most will simply go off into la-la land as they attempt to dereference bad memory. Have updated the answer with more detail. – paxdiablo Oct 16 '13 at 08:56
  • But why did Microsoft decide to take that much trouble of inventing a new function and deprecating the old one if they could have reached the same effect by adding the check for a NULL pointer to fopen, without any harm and much less trouble for everybody? If it's undefined by the standard, what keeps them from defining it for their implementation? – Sebastian Oct 27 '17 at 18:46
  • 2
    Note that the standard C library specifies in [C11 §7.1.4 Use of library functions](https://port70.net/~nsz/c/c11/n1570.html#7.1.4): _Each of the following statements applies unless explicitly stated otherwise in the detailed descriptions that follow: If an argument to a function has an invalid value (such as …, or a pointer outside the address space of the program, or a null pointer, or a pointer to non-modifiable storage when the corresponding parameter is not const-qualified) or …, the behavior is undefined._ Thus, passing a null pointer to `fopen()` invokes undefined behaviour. – Jonathan Leffler Jun 19 '18 at 14:13
  • Note that the default behavior of the Microsoft C Run-Time Library's *Invalid Parameter Handler* will crash the program too, this time on purpose. – Medinoc Oct 25 '20 at 11:19
1

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.

Medinoc
  • 6,298
  • 16
  • 36