我正在this question阅读C中的%n
格式说明符。但是当我在不同的C ++编译器上尝试以下程序时,它给了我不同的输出。
为什么呢?是什么原因?是否存在未定义或实现定义的行为?
#include<stdio.h>
int main()
{
int c = -1;
printf("geeks for %ngeeks ", &c);
printf("%d", c);
getchar();
return 0;
}
输出:
geeks for geeks 10
geeks for geeks 10
geeks -1
Debug assertion failed ("'n' format specifier disabled",0)
答案 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
问题无关。