should program call stack grow upward or downwards?

W

Walter Roberson

David R Brooks said:
Moving to mini & micros, they all grow the stack downward:

*all* ?? That's a pretty big territory to cover!
I assume
because most of the early ones (8086 being the exception) booted code
from zero, so there was usually ROM at low addresses. So grow the stack
toward it.
However, there's a case to be made for growing it upward, namely that
buffer overflows cannot mess with the saved register image or other
important areas: an overflow will only trash that function's own data,
then walk into unallocated space. Might make things a lot more robust.

The buffer being overflowed could be one whose address came from
the calling routine.
 
T

Terje Mathisen

David said:
However, there's a case to be made for growing it upward, namely that
buffer overflows cannot mess with the saved register image or other
important areas: an overflow will only trash that function's own data,
then walk into unallocated space. Might make things a lot more robust.

Sorry, that's wrong.
(I've made the same mistake myself, so don't feel too bad! :)

The problem with a buffer overflow in an upward-growing stack is that if
the buffer is allocated on the stack (a prerequisite for all bugs of
this type), and your function calls a library function to copy
something, without a boundary check, then the overflow will overwrite
the library function's stack area!

I.e. when returning from gets() or strcpy(), you pop an overwritten
return address, and end up either with a crash, or in the case of an
exploit, you return to a carefully-planned piece of trampoline code
somewhere in memory. :-(

This is identical to what happens in a downward growing stack, except
that the buffer you overflow is inside your parent's stack frame instead
of your own.

Terje
 
A

Andrew Reilly

Moving to mini & micros, they all grow the stack downward: I assume
because most of the early ones (8086 being the exception) booted code
from zero, so there was usually ROM at low addresses. So grow the stack
toward it.
However, there's a case to be made for growing it upward, namely that
buffer overflows cannot mess with the saved register image or other
important areas: an overflow will only trash that function's own data,
then walk into unallocated space. Might make things a lot more robust.

I'm pretty sure that the PA-RISC stack grew upwards, in the standard
convention. As Terje pointed out, that probably didn't make it
significantly "safer".

Most modern processors don't have special stack pointers, so direction
comes down to convention, or comfort for the API specifiers. On the bare
metal, I've coded both directions on several processors. Made no great
difference. If anything, I'd say that post-increment address update is
probably a little bit more common than pre-decrement, so pushing things
onto upward-growing stacks is a bit easier than pushing downwards, at the
expense of popping. Many modern processors don't have any update
addressing modes, so that probably doesn't matter at all.

Cheers,
 
D

Dave Vandervies

[I wrote:]
I'm not so sure this meets the definition of a "stack".

Push: Allocate new frame
Link new frame back to current frame
(We need to be able to find it back)
Populate new frame and set it as current

Pop: Follow current frame's link back to previous frame and set it
as current
Deallocate old frame

Walks like a stack, quacks like a stack...

In any
case, such an implementation has no sensible definition of "growth
direction" for a stack.

Which was precisely my point.


dave
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,263
Messages
2,571,062
Members
48,769
Latest member
Clifft

Latest Threads

Top