基本上适用于整个程序。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 认为它需要引用堆栈外的三个东西,而不是它拥有的两个。