【问题标题】:Why this function causes non-stop printing?为什么此功能会导致不停打印?
【发布时间】:2012-10-04 05:35:43
【问题描述】:

你好,我的一个朋友向我展示了这段代码来说明数组/堆栈边界检查。

#include <stdio.h>

void foo() {
    unsigned long long a[1];
    a[3] -= 5;
    printf("Print me!\n");    
}

int main(){ 
    foo();
    return 0;    
}

当我运行这段代码时,它一直在打印“打印我!\n”,它就是不会停止。我已经用 MingW 64 位编译了代码。这里发生了什么事?我想请人解释一下,为什么它一直在打印文本。

【问题讨论】:

  • 不,它不会导致不停打印!
  • 未定义的行为意味着 - 行为是未定义的。任何事情都有可能发生。
  • 它改变了栈上的返回地址。值 5 很重要,因为这是 CALL 机器代码指令的长度。所以当函数返回时,它会跳回函数调用。像这样的黑客通常不会很好地复制。
  • @Raj 也许它取决于编译器......我已经用 MingW 64bit 编译了它。
  • @Amas,未定义的行为几乎肯定取决于编译器。事实上,它甚至可能取决于每次编译甚至每次运行生成的二进制文件。

标签: c printing infinite


【解决方案1】:

看起来可能是stack buffer overflow

您正在引用堆栈数组a 中的未定义索引。这可能会覆盖堆栈上的返回地址。

当函数returns 到main 函数时,它很可能再次执行foo,因为返回地址可能被设置为函数被- 5 操作调用之前的值。

【讨论】:

  • 正确的原理,但实际上它返回到main但地址更改为foo()调用之前的地址,所以它再次执行。确实是未定义的行为。
  • 谢谢。我的意思是foo 的“打印函数”——因为这是唤起printf 的函数。我已经澄清了答案。
【解决方案2】:

您正在 foo() 中更改堆栈帧之外的值。

具体来说,您是从返回地址中减去 5(如果这是正常的 x86-32 调用约定)

如果 main 中的 foo() 调用被编译成类似

call ebp-126(调用短偏移)指令长5个字节。

因此,返回将转到调用,而不是调用之后。调用将再次执行。

不过,这与代码的可移植性和未定义性差不多,因为它取决于调用约定和编译器发出的特定指令。

【讨论】:

    【解决方案3】:

    您通过命令a[3] -= 5; 损坏了线程堆栈,因为更改 var 超出了数组范围。这种行为是完全不可预测的,并且在其他系统上可能会有所不同。我想你只是修改堆栈上的返回地址来调用 printf

    如果您想了解 - 使用反汇编程序。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-04-02
      • 1970-01-01
      • 2021-01-03
      • 2021-04-27
      • 2013-03-01
      • 1970-01-01
      相关资源
      最近更新 更多