%n 格式说明程序在不同的编译器上给出不同的输出。为什么?
%n format specifier program giving different outputs on different compilers. Why?
我在 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
微软 Visual Studio 2010:
Debug assertion failed ("'n' format specifier disabled",0)
如问题中所述,Code Blocks
确实正确,而 Orwell Dev C++
不正确。 Visual Studio 另一方面是不合格的。
cppreferences C documentation for printf says 说:
returns the number of characters written so far by this call to the function.
我在标准草案中没有看到任何使它成为可选的内容,C++ 指的是关于 printf
的 C 标准。 MSDN documents this 并说:
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.
为什么 %n 格式本质上是不安全的?
我假设他们认为它是不安全的,因为 Format String Vulnerability 文档中概述的安全问题是一种可能的利用方法。它基于由用户输入控制的格式字符串。该论文给出了以下示例:
char user_input[100];
scanf("%s", user_input);
printf(user_input);
Retired Ninja 链接到 Bugtraq post,它演示了此类错误最终导致 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.
Visual Studio方法的问题在于它破坏了可移植性。其他方法包括使用像 Wformat-security used by gcc 这样的标志,它与 -WError
结合使用可能会导致错误,但您可以在构建过程中选择它。
代码块输出正确。
Orwell Dev C++ 输出不正确。默认情况下,该实现不符合要求(阅读文档以查看是否有办法使其正常运行),或者它有错误。
默认情况下,Microsoft 的实施是不合规的。它禁用标准 %n
格式说明符以防止某些可能的安全问题(尽管您问题的代码中没有此类问题)。显然有办法重新启用它;参见 。
我在您的程序中看到的唯一潜在问题是它不会在输出末尾打印换行符,但这与 %n
问题无关。
我在 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
微软 Visual Studio 2010:
Debug assertion failed ("'n' format specifier disabled",0)
如问题中所述,Code Blocks
确实正确,而 Orwell Dev C++
不正确。 Visual Studio 另一方面是不合格的。
cppreferences C documentation for printf says 说:
returns the number of characters written so far by this call to the function.
我在标准草案中没有看到任何使它成为可选的内容,C++ 指的是关于 printf
的 C 标准。 MSDN documents this 并说:
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.
为什么 %n 格式本质上是不安全的?
我假设他们认为它是不安全的,因为 Format String Vulnerability 文档中概述的安全问题是一种可能的利用方法。它基于由用户输入控制的格式字符串。该论文给出了以下示例:
char user_input[100];
scanf("%s", user_input);
printf(user_input);
Retired Ninja 链接到 Bugtraq post,它演示了此类错误最终导致 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.
Visual Studio方法的问题在于它破坏了可移植性。其他方法包括使用像 Wformat-security used by gcc 这样的标志,它与 -WError
结合使用可能会导致错误,但您可以在构建过程中选择它。
代码块输出正确。
Orwell Dev C++ 输出不正确。默认情况下,该实现不符合要求(阅读文档以查看是否有办法使其正常运行),或者它有错误。
默认情况下,Microsoft 的实施是不合规的。它禁用标准 %n
格式说明符以防止某些可能的安全问题(尽管您问题的代码中没有此类问题)。显然有办法重新启用它;参见
我在您的程序中看到的唯一潜在问题是它不会在输出末尾打印换行符,但这与 %n
问题无关。