Hi, could someone please teach me a common example whereby (!) you destroy the stack in a C program? I use GCC, in Ubuntu. Thanks.
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
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:
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 recursion is optimized out; 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.
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
}