Search code examples
c++runtime-errorprintf

Different run-time checking of printf() for %s?


I know that, to use printf() correctly, we need to further pass in same number of values according to what are defined in the const char* format, i.e. %s/%f/%d....

int printf( const char* format, ... );

I just noticed that, although not recommended, it will run without any run-time errors if we don't pass in any values, like the following (of course, we will get un-expected results):

printf("%a"); // ok
printf("%c"); // ok
printf("%d"); // ok
printf("%e"); // ok
printf("%f"); // ok
printf("%g"); // ok
printf("%i"); // ok
printf("%o"); // ok
printf("%p"); // ok
printf("%u"); // ok
printf("%x"); // ok

If this will holds for all formats, I will feel no surprised by thinking that printf() doesn't do any run-time checking. Weird thing is that, it will give run-time error for %s (also seems the only one).

printf("%s"); // run-time error: Access violation reading location

Even more interesting thing is that, it seems that it only run-time checks for the first or consecutive of %s. Check out the following examples:

printf("%s%s", "xxx"); // run-time error: Access violation reading location
printf("%s%d%s", "xxx"); // ok

So, my question is that:

  • Does printf() run-time check differently for %s compared with other formats? And why?
  • Why does printf() only run-time check for the first or consecutive of %s?

ps: I tested it under VS2010, OS: Win7x64.


Solution

  • In this case the C++ standard fall back on the C99 draft standard which says this is undefined behavior in section 7.19.6.1 The fprintf function which covers printf with respect format specifiers, says:

    [...]If there are insufficient arguments for the format, the behavior is undefined.

    So as the standard says in the definition for undefined behavior:

    Possible undefined behavior ranges from ignoring the situation completely with unpredictable results, to behaving during translation or program execution in a documented manner characteristic of the environment (with or without the issuance of a diagnostic message), to terminating a translation or execution (with the issuance of a diagnostic message).

    anything can happen.

    Since printf is a variadic function it has to rely on the caller to correctly represent the data passed in. So run time checking is not possible. Although several compilers do provide compile time checking, for example gcc even provides this checking as an attribute format (archetype, string-index, first-to-check) which can be used with your own functions.