41

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...

6

3 Answers 3

27

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.

2
  • 12
    Go back further in history and there was no heap, even today, many 8 and 16 bit micro controllers do not have a heap. The stack grew down so the program could be installed in a low memory address, and the stack was the remaining memory. Stack initialization could be performed before program load, simplifying programs.
    – mattnz
    Feb 29, 2012 at 23:54
  • 1
    Most small microcontrollers have a heap, just not a heap that grows. It hard to justify to use dynamic memory allocation on the heap when you have small amount of RAM ( < 1Kbytes )to work with. Usually the only memory section's size that changes is the stack.
    – tehnyit
    Mar 1, 2012 at 9:32
9

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

6

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?

1
  • Well, not having executable stack(s) probably helped Multics just as much as intelligent stack direction, and of course with many programs written in PL/1, string overflows were also not really a problem. Nov 3, 2015 at 21:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.