could someone please teach me a common example whereby (!) you destroy the stack in a C program? I use GCC, in Ubuntu. Thanks.
-
What do you mean destroy the stack? – Buhake Sindi Oct 06 '10 at 19:04
-
What CPU architecture are you using? Ubuntu has several architecture ports IIRC. – Billy ONeal Oct 06 '10 at 19:09
4 Answers
It depends on what you mean by "destroy the stack", but this is a common error that will generally cause corruption of vital stack-resident data:
void dumb()
{
char small[2];
strcpy(small, "too long to fit"); // Writes past the end of "small", overwriting vital information
}
This is a common source of security holes. It can potentially be used to hijack the instruction pointer, enabling malicious code to execute. See buffer overflow.
Another mistake that might be described as "destroying the stack" is the case of infinite recursion (scroll down on that page):
int add(int n)
{
return n + add(n + 1);
}
Which, as it lacks an exit condition, will push so many frames onto the stack that it eventually gets "full". (Unless the compiler can apply tail-call optimization; see below)
Both of these examples compile without as much as a warning using GCC 4.4.3.
Note: As Billy ONeal pointed out below, the behavior of these examples is specific to x86, not C as a language, and may vary from one compiler to another. That is not to say that they don't demonstrate how you can break the stack in a particular (and extremely common) implementation of C.

- 1
- 1

- 9,299
- 2
- 28
- 35
-
1Note: All of this is specific to x86. Nothing here is specified by the C standard. (C doesn't know about SIGSEGV/EXCEPTION_ACCESS_VIOLATION, nor does it know of any sort of virtual memory model) – Billy ONeal Oct 06 '10 at 19:09
-
Yep, just realized it myself. I'll update my post accordingly. Thanks for pointing that out. – Martin Törnwall Oct 06 '10 at 19:11
-
1@Martin: +1 for edit. One other thing of note: If the compiler tailcall optimizes the `add` function, it might simply loop forever rather than crashing, even on x86. – Billy ONeal Oct 06 '10 at 19:17
-
@Billy ONeal: yes -- confirmed! No crash when compiling my example with -O3. Interesting. +1 – Martin Törnwall Oct 06 '10 at 19:22
-
@Billy ONeal: it can't simply tailcall optimize `add`, although it could replace it with a loop; introduce an accumulator parameter; and/or spot that the function cannot possibly return, and replace it with something that doesn't do any addition at all. And while you say that the results are specific to x86, you might just as well say they're specific to ARM, specific to MIPS, specific to PowerPC, and so on. A stack features in quite a few C ABIs, and where there's a stack, these programs will tend to break it... – Steve Jessop Oct 06 '10 at 19:24
-
@Steve: The fact that these programs are undefined behavior that usually results in stack corruption I'm not really challenging here. I'm more challenging the statement "generally causing a segfault upon return" -- because "segfault" is an artifact of the x86 memory model. – Billy ONeal Oct 06 '10 at 19:25
-
@Steve Jessop: after reading the disassembly, I can conclude that add basically gets optimized to jmp $ – Martin Törnwall Oct 06 '10 at 19:27
-
@Billy: I agree with you on "segfault" being an x86 artifact. I've edited the first paragraph slightly to be less specific to that architecture. – Martin Törnwall Oct 06 '10 at 19:35
-
If I wrote a C compiler, it would compile your add function to `1: jmp 1`. – R.. GitHub STOP HELPING ICE Oct 06 '10 at 22:01
Here are a few more examples where the stack can get trashed.
char* foo()
{
char str[256];
return str;
}
void bar()
{
char* str = foo();
strcpy(str, "Holy sweet Moses! I blew my stack!!");
}
Or,
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
}

- 8,779
- 4
- 29
- 57
-
1Okay, the first example works. But the second example has nothing to do with the stack. Just because it's a stack allocated pointer doesn't mean it has anything to do with the stack. – Billy ONeal Oct 07 '10 at 02:19
You can't, at least, not according to the C standard. You might be able to use inline assembler features of GCC to mess with the stack pointer though.
EDIT: I suppose calling exit
, abort
, or (terminate is in C++ only) would result in destruction of the stack :Pterminate

- 104,103
- 58
- 317
- 552
-
I really wish someone would have given a comment with respect to why they downvoted this answer.... – Billy ONeal Oct 07 '10 at 02:18
-
I don't know why they downvoted your answer, but it sure isn't helpful to me. I don't think you understood the question. – Dervin Thunk Oct 07 '10 at 16:46
I'm not sure exactly what you mean, but whenever you exit a function the "stack" for that function is destroyed. For example:
void foo(void) {
// a, b and c are "allocated" on the stack here
int a, b, c;
} // a, b and c are destroyed here
In reality the stack is never destroyed in the way you might be thinking. There is a pointer to the top of the stack and functions reference positions relative the current top of stack. When a function exits the TOS pointer is decremented by a certain amount, but no actual destruction takes place. So you could theoretically still access the values from the function after it exits, although that would be a bad idea.
You might want to take a look at these:

- 39,711
- 30
- 131
- 179
-
"TOS" pointer? I'm not aware of an architecture with such a thing. At least on x86, the register you're looking for is `ESP`. This is the problem with answering with one particular architecture's behavior when talking about the C language as specified in the standard. – Billy ONeal Oct 06 '10 at 19:14
-
1@Billy ONeal: TOS == Top of Stack, probably ESP on x86 as you point out. – Robert S. Barnes Oct 06 '10 at 19:21