Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

%n format specifier program giving different outputs on different compilers. Why?

Tags:

c++

c

printf

I was reading about %n format specifier in C at this question. But when I tried the following program on different C++ compilers, it gave me different outputs.

Why? What is the reason? Is there undefined or implementation defined behavior occurring?

#include<stdio.h>

int main()
{
  int c = -1;
  printf("geeks for %ngeeks ", &c);
  printf("%d", c);
  getchar();
  return 0;
}

Output:

Code blocks 13.12: (correct output)

geeks for geeks 10

Borland/CodeGear/Embarcadero C++: (correct output)

geeks for geeks 10

Orwell Dev C++:

geeks -1

Microsoft Visual Studio 2010:

Debug assertion failed ("'n' format specifier disabled",0) 
like image 492
Destructor Avatar asked Mar 23 '15 19:03

Destructor


People also ask

What is a format specifier in C++?

The format specifier is used during input and output. It is a way to tell the compiler what type of data is in a variable during taking input using scanf () or printing using printf ().

Why does the same program produce different output with different compilers?

Edit: I see the question comments have the source, and others have also commented on Eclipse and Putty not being C compilers. Generally speaking, the same program producing different output with different compilers is a sign that you’ve run into undefined behavior — typically this means that you’ve done something wrong.

What is a%format specifier in C?

Format specifiers in C. Format specifier is used during input and output. It is a way to tell the compiler what type of data is in a variable during taking input using scanf() or printing using printf(). Some examples are %c, %d, %f, etc.

What is the general syntax of a format specifier?

The general syntax of a format specifier is % [flags] [width] [.precision] [argsize] typechar The format () method of Formatter class accepts a wide variety of format specifiers. When an uppercase specifier is used, then letters are shown in uppercase.


Video Answer


2 Answers

As noted in the question Code Blocks is indeed correct while Orwell Dev C++ is incorrect. Visual Studio on the other hand is non-conforming.

cppreferences C documentation for printf says says:

returns the number of characters written so far by this call to the function.

I don't see anything in the draft standard that makes this optional, C++ refers to the C standard with respect to printf. MSDN documents this and says:

Because the %n format is inherently insecure, it is disabled by default. If %n is encountered in a format string, the invalid parameter handler is invoked, as described in Parameter Validation. To enable %n support, see _set_printf_count_output.

Why is the %n format is inherently insecure?

I am assuming that they consider it unsafe because of security issues such as those outlined in Format String Vulnerability documents one possible way to exploit this. It is predicated on the format string being controlled by user input. The paper gives the following example:

char user_input[100];
scanf("%s", user_input); 
printf(user_input); 

Retired Ninja linked to Bugtraq post which demonstrates an real example of such a bug ending up in an exploit in proftpd 1.2.0pre6:

  • ftp to host
  • login (anonymous or no)

(this should be all on one line, no spaces)

ftp> ls aaaXXXX%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u%u %u%u%u%u%u%u%u%u%u%653300u%n

(replace the X's with the characters with ascii values 0xdc,0x4f,0x07,0x08 consecutively)

Lots of other nasties can easily be easily done with this. Since proftpd will pass on user input data to snprintf, argument attacks are easy.

The problem with Visual Studios approach is that it breaks portability. Other approaches include using flags like Wformat-security used by gcc which combined with -WError can make it an error but you can choose this as part of your build process.

like image 147
Shafik Yaghmour Avatar answered Sep 18 '22 18:09

Shafik Yaghmour


The Code Blocks output is correct.

The Orwell Dev C++ output is incorrect. Either that implementation is not non-conforming by default (read the documentation to see if there's a way to make it behave correctly), or it has a bug.

Microsoft's implementation is non-conforming by default. It disables the standard %n format specifier to prevent some possible security problems (though there are no such problems in the code in your question). Apparently there are ways to re-enable it; see Shafik Yaghmour's answer.

The only potential problem I see with your program is that it doesn't print a newline at the end of its output, but that's not relevant to the %n issue.

like image 26
Keith Thompson Avatar answered Sep 21 '22 18:09

Keith Thompson