2010-10-06 77 views
1

有人可以请教我一个常见的例子,借此(!)你在C程序中销毁堆栈?我在Ubuntu中使用GCC。 谢谢。在C程序中堆栈破坏的典型例子

+0

你是什么意思摧毁堆栈? – 2010-10-06 19:04:49

+0

您使用的是哪种CPU架构? Ubuntu有几个架构端口IIRC。 – 2010-10-06 19:09:58

回答

5

这取决于你所说的“破坏栈”是什么,但是这是一个常见的错误一般会导致重要堆栈数据的损坏:

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的警告那样编译。


注:作为比利奥尼尔下面指出的那样,这些实施例的行为是特定于86,而不是C作为一种语言,并且可以变化从一个编译器到另一个。这并不是说他们演示了如何突破堆在一个特定的(而且非常普遍的)实现C.

+1

注意:所有这些特定于x86。这里没有什么是由C标准规定的。 (C不知道SIGSEGV/EXCEPTION_ACCESS_VIOLATION,也不知道任何类型的虚拟内存模型) – 2010-10-06 19:09:06

+0

是的,只是意识到自己。我会相应地更新我的帖子。感谢您指出了这一点。 – 2010-10-06 19:11:21

+1

@Martin:编辑+1。另一件值得注意的事情是:如果编译器tailcall优化了'add'函数,它甚至可以在x86上永远循环而不会崩溃。 – 2010-10-06 19:17:47

0

你不能,至少不符合C标准。你也许可以使用GCC的内联汇编器功能来处理堆栈指针。

编辑:我想打电话exitabort,或terminate(终止在C++只)会导致栈破坏:P

+0

我真的希望有人会对他们为什么低估这个答案给予评论.... – 2010-10-07 02:18:36

+0

我不知道他们为什么低估了你的答案,但它肯定对我没有帮助。我认为你不了解这个问题。 – 2010-10-07 16:46:22

0

我不知道你的意思到底是什么,但每当你退出一个函数,该函数的“堆栈”被销毁。例如:

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指针减少一定量,但不会发生实际的破坏。所以理论上你仍然可以在函数退出后访问函数中的值,尽管这是一个坏主意。

你可能想看看这些:

How Does The Function Call Stack Work?

Calling Conventions in C and C++

+0

“TOS”指针?我不知道有这样的事情的架构。至少在x86上,您要寻找的寄存器是“ESP”。在讨论标准中指定的C语言时,这是回答某个特定架构行为时的问题。 – 2010-10-06 19:14:27

+1

@Billy ONeal:TOS ==堆栈顶部,可能是ESP上的ESP,正如你指出的那样。 – 2010-10-06 19:21:16

2

这里有几个例子,其中堆栈可以得到丢弃。

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 
} 
+1

好的,第一个例子工作。但第二个例子与堆栈无关。仅仅因为它是一个堆栈分配指针,并不意味着它与堆栈有任何关系。 – 2010-10-07 02:19:40