25

I'm using fopen in C to write the output to a text file. The function declaration is (where ARRAY_SIZE has been defined earlier):

void create_out_file(char file_name[],long double *z1){  
  FILE *out;  
  int i;  

  if((out = fopen(file_name, "w+")) == NULL){  
    fprintf(stderr, "***> Open error on output file %s", file_name);  
    exit(-1);  
  }  

  for(i = 0; i < ARRAY_SIZE; i++)  
    fprintf(out, "%.16Le\n", z1[i]);  
  fclose(out);  
}  

My questions:

  1. On compilation with MVS2008 I get the warning: warning C4996: 'fopen': This function or variable may be unsafe. Consider using fopen_s instead. I haven't see much information on fopen_s so that I can change my code. Any suggestions?

  2. Can one instruct fprintf to write numbers at a desired numerical precision to a file? If I'm using long double then I assume that my answers are good till 15 digits after the decimal point. Am I right?

Jean-François Corbett
  • 37,420
  • 30
  • 139
  • 188
yCalleecharan
  • 4,656
  • 11
  • 56
  • 86
  • 17
    There is nothing remotely unsafe about fopen(), but a few people at MS seem to have lost their collective marbles over functions that take null-terminated strings as parameters. –  Apr 04 '10 at 17:04
  • 5
    I believe this is all a plot by Microsoft to lock people into Windows-only programming. – lost_in_the_source Feb 16 '16 at 17:08

6 Answers6

23

fopen_s is a variant of fopen which contains parameter validation and hands back an error code instead of a pointer in case something goes wrong during the open process. It's more secure than the base variant because it accounts for more edge conditions. The compiler is warning you to use it because fopen represents a potential exploitation vector in your application.

You can specify digits of precision to the printf family of functions by using the specifier %.xg, where x is the digits of precision you want in the output. A long double varies in precision from platform to platform, but you can generally bet on it being at least 16 digits of decimal precision.

Edit: While I'm not entirely on board with the others who are suggesting that fopen_s is a complete waste of time, it does represent a pretty low chance of exploitation and it isn't widely supported. Some of the other functions warned about under C4996 are much more serious vulnerabilities, however, and using _CRT_SECURE_NO_WARNINGS is the equivalent of turning off the alarm for both "you left your bedroom door unlocked" and "you left a nuclear bomb in the kitchen".

As long as you aren't restricted to using "pure C" for your project (e.g. for a school assignment or an embedded microcontroller), you would do well to exploit the fact that almost all modern C compilers are also C++ compilers and use the C++ iostream variants of all of these I/O functions in order to get both improved security and compatibility at the same time.

Dan Story
  • 9,985
  • 1
  • 23
  • 27
  • Thanks. I have fprintf(out, "%.16Le\n", z1[i]) in my code and yes I get the 16 precision digits after the d.p. – yCalleecharan Apr 04 '10 at 17:13
  • Thanks again. I'm using C as this it's what I know better. I'm writing a code for research purposes which has to give accurate result. I had to non-dimensionalize my equations forming the C code so as to have a nice range of values that would prevent either too large values nor too low values to creep into the simulation and hence in the solution. I don't know much about C++ and I don't know if I can just save my file to cpp and use C++ iostream safely without other parts of my code giving me compilation errors. For now, I shall restrict myself to C till I know how to make the switch to C++. – yCalleecharan Apr 04 '10 at 17:37
  • "...using _CRT_SECURE_NO_WARNINGS is the equivalent of turning off the alarm for both "you left your bedroom door unlocked" and "you left a nuclear bomb in the kitchen". Well said! – Eric M Feb 06 '20 at 23:50
12

I ran into a similar problem working with Visual Studio 2012 but where my problem expanded was I'm building a program that I want to use the bells and whistles of Visual Studio for testing and eventually be able to compile and run the same application on my Linux server (I'm making a bot)

so this is what I came up with after some Google-ing and thought I'd post it in case it may help anyone else.

FILE *fp_config;
const char *configfile ;
configfile = "bot.conf";
#ifdef WIN32
    errno_t err;
    if( (err  = fopen_s( &fp_config, configfile, "r" )) !=0 ) {
#else
    if ((fp_config = fopen(configfile, "r")) == NULL) {
#endif
        fprintf(stderr, "Cannot open config file %s!\n", configfile);
    }

this will appease Visual Studio and it will not complain and it will also allow the same code to compile on gcc or any other standards compliant c/c++ compiler

BrierMay
  • 391
  • 1
  • 4
  • 15
9
  1. fopen_s and all the other _s functions are MS-specific "secure" variants of standard functions. If your code doesn't need to be cross-platform, you can just switch and make the compiler happy. Otherwise, just add the _CRT_SECURE_NO_WARNINGS pre-processor directive into your project settings and it'll stop warning you about it.

  2. Yeah, long double is easily good for 15 digits of precision; actually, even regular doubles are good enough for that much (but no more).

tzaman
  • 46,925
  • 11
  • 90
  • 115
  • Thanks. On my 32-bit machine, both double and long double gives me 16 digits of precision and the 16th digit is the one not accurate. – yCalleecharan Apr 04 '10 at 17:14
  • Yeah, `long double` size is platform-dependent; sadly, MSVC++ makes it the same as `double`, so no use really. A 64-bit double has 53-bit precision in the mantissa, which is about 15.95 decimal digits (log10(53)). – tzaman Apr 04 '10 at 19:50
  • `fopen_s` and the other `_s` variants introduced to provide greater safety are defined in the ISO C11 standard. The Visual Studio folk may have jumped the gun, but compilers that permit selection of C11 (and C17) should provide those. – orcmid Jul 27 '23 at 18:22
5

Moving from fopen to fopen_s disabled the ability to open file in notepad (read only) while file is opened and being writen. Swithing back to fopen and I can read wile my program writes the file.

eduard
  • 309
  • 3
  • 9
  • 3
    From the [reference](http://en.cppreference.com/w/c/io/fopen): When using fopen_s or freopen_s, file access permissions for any file created with "w" or "a" prevents other users from accessing it. File access mode flag "u" can optionally be prepended to any specifier that begins with "w" or "a", to enable the default fopen permissions. (C11) – Brady Dean May 28 '17 at 22:09
4

Other posters have pointed out that fopen is not really very unsafe. If you don't want this warning, but you do want the other ones that warn of real vulnerabilities, don't #define _CRT_SECURE_NO_WARNINGS.

Instead, the next time you get the fopen warning, click on the line that says "see declaration of 'fopen'". This will take you to the line in stdio.h which is injecting the warning. Delete the text _CRT_INSECURE_DEPRECATE(fopen_s) from that line, and you will no longer get the security warning when you use fopen, but it will remain for strcpy, strdup and those other possibly dangerous ones.

AShelly
  • 34,686
  • 15
  • 91
  • 152
  • 1
    actually on windows the "standard" implementation of open does have some vulnerabilities due to the 14, 125, 16 year old brats that have nothing better to do with their time than find ways to hack programs and mess up other peoples computers, so they came up with a different way to pass the file descriptor making it harder for the teenagers – BrierMay Aug 11 '13 at 23:41
0

Just define _CRT_SECURE_NO_WARNINGS before you include any file to get rid of this warnings, and stop believe to what MS says about fopen

Artyom
  • 31,019
  • 21
  • 127
  • 215