代码之家  ›  专栏  ›  技术社区  ›  Destructor

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

  •  18
  • Destructor  · 技术社区  · 10 年前

    我在读关于 %n C中的格式说明符 this question 。但当我在不同的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++:(正确输出)

    极客对极客10
    

    Orwell开发C++:

    geeks -1
    

    Microsoft Visual Studio 2010:

    Debug assertion failed ("'n' format specifier disabled",0) 
    
    2 回复  |  直到 7 年前
        1
  •  10
  •   Shafik Yaghmour    10 年前

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

    cpp参考 C documentation for printf says 说:

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

    我在标准草案中没有看到任何东西使其成为可选的,C++指的是关于 printf . 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 它演示了这样一个bug在 proftpd 1.2.0pre6 :

    • ftp到主机
    • 登录(匿名或无)

    (这应该全部在一行,没有空格)

    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%653300u%n

    (用带ascii值的字符替换X 连续0xdc、0x4f、0x07、0x08)

    很多其他讨厌的事情都可以很容易地用这个解决。自从 proftpd将用户输入数据传递给snprintf,参数攻击是 容易的

    Visual Studio方法的问题在于它破坏了可移植性。其他方法包括使用标志,如 Wformat-security used by gcc 它与 -WError 可以使其成为错误,但您可以将其作为构建过程的一部分。

        2
  •  4
  •   Community CDub    7 年前

    代码块输出正确。

    Orwell Dev C++输出不正确。该实现在默认情况下不是不一致的(请阅读文档以查看是否有方法使其正确运行),或者它存在错误。

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

    我看到的程序的唯一潜在问题是它在输出末尾没有打印换行符,但这与 %n个 问题