1

我的问题是关于缺少参数的 printf 之后的行为:

printf("%s blah blah %d", int); // integer was given as argument (and not int written)

我已经知道,如果格式的参数不足,则行为未定义。

问题是它是否为 printf 结果或整个程序未定义?

  • 当 %s 尝试从未经授权的内存地址读取时,可能会发生崩溃。(发生在我身上)
  • printf 完成后 [long] 会发生崩溃吗?(打印一些垃圾字符串和一个整数)

编辑:

为了澄清,我不是在询问编译错误或警告,也不是在执行此行时程序崩溃。问题是这一行是否可以在该行已经执行后使程序随机崩溃。

4

2 回答 2

1

对于整个程序,它是未定义的。

事实上,在程序存在之前它是未定义的:编译器本身在存在文本时所做的事情是未定义的printf("%s blah blah %d", int);

于 2012-09-30T09:43:45.800 回答
0

基本上适用于整个程序。Printf 开始从堆栈中取出参数,在这种情况下,它会占用int太多的值。这通常类似于退货地址。因此,当 printf 返回时,它会返回堆栈中的下一个随机数。通常的结果——如果你幸运的话——是分段错误。

因为它将参数压入堆栈,所以它会弹出它们,所以它会尝试获取第int一个。

如果你走运,它会找到一段可寻址的代码。这导致您的第二种情况,其中地址成为该随机字符散列的地址。现在它将尝试打印一个字符串,直到找到一个随机的 NUL 字符。

更新

正如 Joachim 所指出的,其细节由调用约定决定,所以让我们做一个明确的例子。当调用 printf 函数时,返回地址要么被先推送,要么最后被推送。我们假设它首先被推送(在通常的架构上更常见),所以这个调用将需要 PUSH 返回地址、格式字符串的 PUSH 地址、一个 int 值——比如说 42。这给了我们这个堆栈:

RTN ADDR
ADDR OF STRING
42

并使堆栈指针 SP 指向堆栈上的下一个位置。

现在 printf 开始解释字符串。它查找int参数的地址,并确定它是 SP-1。所以字符串参数的地址必须是 SP-2 ... 但这是格式字符串的地址,因为没有字符串参数。然后它在寻找格式字符串的地址时,它想找到SP-3,但那是返回地址,一个可执行代码的地址。在大多数机器上,这应该会导致分段错误。

如果您查看调用约定的其他选项,您会发现它们中的每一个都在看一些错误的东西,因为无论如何,printf 认为它需要引用堆栈外的三个东西,而不是它拥有的两个。

于 2012-09-30T09:46:47.957 回答