%n格式说明符程序在不同的编译器上给出不同的输出。为什么?

时间:2015-03-23 19:36:33

标签: c++ c printf

我正在this question阅读C中的%n格式说明符。但是当我在不同的C ++编译器上尝试以下程序时,它给了我不同的输出。

为什么呢?是什么原因?是否存在未定义或实现定义的行为?

#include<stdio.h>

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

输出:

代码块13.12 :(正确输出)

geeks for geeks 10

Borland / CodeGear / Embarcadero C ++ :(正确输出)

geeks for geeks 10

Orwell Dev C ++:

geeks -1

Microsoft Visual Studio 2010:

Debug assertion failed ("'n' format specifier disabled",0) 

2 个答案:

答案 0 :(得分:10)

正如问题Code Blocks中所述确实正确,而Orwell Dev C++不正确。另一方面,Visual Studio不符合要求。

cppreferences C documentation for printf says说:

  

返回此函数调用到目前为止写入的字符数。

我没有在标准草案中看到任何使这个可选的内容,C ++引用了与printf相关的C标准。 MSDN documents this并说:

  

由于%n格式本质上不安全,因此默认情况下禁用。如果在格式字符串中遇到%n,则调用无效参数处理程序,如参数验证中所述。要启用%n支持,请参阅_set_printf_count_output。

为什么%n格式本身就不安全?

我假设他们认为它不安全,因为Format String Vulnerability文件中概述的安全问题是一种可能的方法来利用它。它取决于由用户输入控制的格式字符串。本文给出了以下例子:

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

已退役的忍者与Bugtraq post相关联,展示了此类错误的真实示例,最终出现在proftpd 1.2.0pre6的漏洞利用中:

  
      
  • ftp to host
  •   
  • 登录(匿名或否)
  •   
     

(这应该是一行,没有空格)

     

FTP&GT;是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%U%653300u%N

     

(用带有ascii值的字符替换X&#39;   连续0xdc,0x4f,0x07,0x08)

     

很容易就可以很容易地完成很多其他的恶作剧。以来   proftpd会将用户输入数据传递给snprintf,参数攻击都是   容易。

Visual Studios方法的问题在于它破坏了可移植性。其他方法包括使用Wformat-security used by gcc之类的标记与-WError结合使用可能会导致错误,但您可以选择此作为构建过程的一部分。

答案 1 :(得分:4)

代码块输出正确。

Orwell Dev C ++输出不正确。默认情况下,该实现不是不符合要求(阅读文档以查看是否有办法使其正常运行),或者它有错误。

默认情况下,Microsoft的实现不符合要求。它禁用标准%n格式说明符以防止一些可能的安全问题(尽管您的问题中的代码中没有此类问题)。显然有办法重新启用它;见Shafik Yaghmour's answer

我在程序中看到的唯一潜在问题是它在输出结束时不会打印换行符,但这与%n问题无关。