【发布时间】:2011-04-22 00:24:35
【问题描述】:
有人可以教我一个常见的例子吗(!)你在 C 程序中破坏堆栈?我在 Ubuntu 中使用 GCC。 谢谢。
【问题讨论】:
-
销毁堆栈是什么意思?
-
您使用的是什么 CPU 架构? Ubuntu 有几个架构端口 IIRC。
标签: c memory-management stack
有人可以教我一个常见的例子吗(!)你在 C 程序中破坏堆栈?我在 Ubuntu 中使用 GCC。 谢谢。
【问题讨论】:
标签: c memory-management stack
你不能,至少,不符合 C 标准。不过,您也许可以使用 GCC 的内联汇编器功能来处理堆栈指针。
编辑:我想调用 exit、abort 或 (终止仅在 C++ 中)会导致堆栈破坏:Pterminate
【讨论】:
我不确定您的确切意思,但是每当您退出一个函数时,该函数的“堆栈”就会被破坏。例如:
void foo(void) {
// a, b and c are "allocated" on the stack here
int a, b, c;
} // a, b and c are destroyed here
实际上,堆栈永远不会像您想象的那样被破坏。有一个指向栈顶的指针,函数引用相对于当前栈顶的位置。当一个函数退出时,TOS 指针会减少一定的量,但不会发生实际的销毁。所以理论上你仍然可以在函数退出后访问函数的值,尽管那是个坏主意。
你可能想看看这些:
【讨论】:
ESP。这是在谈论标准中规定的 C 语言时,用一种特定架构的行为来回答的问题。
这取决于您所说的“销毁堆栈”是什么意思,但这是一个常见错误,通常会导致重要的堆栈驻留数据损坏:
void dumb()
{
char small[2];
strcpy(small, "too long to fit"); // Writes past the end of "small", overwriting vital information
}
这是安全漏洞的常见来源。它可能被用来劫持指令指针,使恶意代码得以执行。见buffer overflow。
另一个可能被描述为“破坏堆栈”的错误是infinite recursion 的情况(在该页面上向下滚动):
int add(int n)
{
return n + add(n + 1);
}
由于缺少退出条件,它会将如此多的帧推入堆栈,最终会“满”。 (除非编译器可以申请tail-call optimization;见下文)
这两个示例都使用 GCC 4.4.3 编译而没有警告。
注意:正如 Billy ONeal 在下面指出的那样,这些示例的行为特定于 x86,而不是 C 作为一种语言,并且可能因编译器而异。这并不是说他们不演示了如何在 C 的特定(并且非常常见的)实现中打破堆栈。
【讨论】:
add 函数,它可能会永远循环而不是崩溃,即使在 x86 上也是如此。
add,尽管它可以用循环替换它;引入累加器参数;和/或发现该函数不可能返回,并将其替换为根本不做任何添加的东西。虽然您说结果特定于 x86,但您也可以说它们特定于 ARM、特定于 MIPS、特定于 PowerPC 等等。很多 C ABI 中都有堆栈功能,如果有堆栈,这些程序往往会破坏它......
这里还有一些堆栈可能会被丢弃的示例。
char* foo()
{
char str[256];
return str;
}
void bar()
{
char* str = foo();
strcpy(str, "Holy sweet Moses! I blew my stack!!");
}
或者,
void foo()
{
char* str; // uninitialized; has garbage value
strcpy(str, "Holy sweet Moses! I blew my stack!!");
// well, could be anything you are trashing
}
void foo()
{
int* ptr; // uninitialized; has garbage value
*ptr = "0xDEADBEEF";
// well, could be anything you are trashing
}
【讨论】: