I'm assuming there's a history to it, but why does the stack grow downward?
It seems to me like buffer overflows would be a lot harder to exploit if the stack grew upward...
Software Engineering Stack Exchange is a question and answer site for professionals, academics, and students working within the systems development life cycle. It only takes a minute to sign up.
Sign up to join this communityI'm assuming there's a history to it, but why does the stack grow downward?
It seems to me like buffer overflows would be a lot harder to exploit if the stack grew upward...
I believe it comes from the very early days of computing, when memory was very limited, and it was not wise to pre-allocate a large chunk of memory for exclusive use by the stack. So, by allocating heap memory from address zero upwards, and stack memory from the end of the memory downwards, you could have both the heap and the stack share the same area of memory.
If you needed a bit more heap, you could be careful with your stack usage; if you needed more stack, you could try to free some heap memory. The result was, of course, mostly, spectacular crashes, as the stack would occasionally overwrite the heap and vice versa.
Back in those days there were no interwebz, so there was no issue of buffer overrun exploitations. (Or at least to the extent that the interwebz existed, it was all within high security facilities of the united states department of defense, so the possibility of malicious data did not need to be given much thought.)
After that, with most architectures it was all a matter of maintaining compatibility with previous versions of the same architecture. That's why upside-down stacks are still with us today.
program memory is traditionally set up as
code
constants
heap (growing up)
...
stack (growing down)
heap and stack can be exchanged
but buffer overflows can still be exploited if the stack went the other way
taking the classic strcpy
as an example
foo(char* in){
char[100] buff;
strcpy(buff,in);
}
with stack memory as
ret foo
arg in
buff array
ret strcpy
buf pointer
in
this would mean that when the copying is done the return address for strcpy
is after the buffer (instead of foo
's return address) and can be overwritten by whatever is in in
Some hardware has the heap starting at high memory, growing down, while the stack starts at low memory growing up.
HP's PA-RISC hardware, among others, does this: http://www.embeddedrelated.com/usenet/embedded/show/68749-1.php
The venerable Multics Operating System ran on hardware that had (one of possibly many) stacks growing up: see http://www.acsac.org/2002/papers/classic-multics.pdf, end of section 2.3.2:
Third, stacks on the Multics processors grew in the positive direction, rather than the negative direction. This meant that if you actually accomplished a buffer overflow, you would be overwriting unused stack frames, rather than your own return pointer, making exploitation much more difficult.
That's a rather interesting statement. Did buffer overflows become such a huge problem only because of the "customary" procedure-call-stack-frame arrangement? Also, how much of Multics' reputation as Totally Invulnerable was just a fluke of hardware design?