Stack can be classified into “Full Stack” and “Empty Stack” by addressing mode.
Full Stack : The stack pointer points to the last item in the stack.
Empty Stack : The stack pointer points to the next free space on the stack.
I prefer Empty Stack because… how can I say… It is more computer-like-expression…. :-)
Usually, in computer science, indexing starts like (i=start) and ends like (i<end)… That is, [a, b) range concept is normal…
In Empty Stack, we can say "Stack is empty" by checking (SP == Framebase). And this is more suitable for above concept…
Ascending Stack : The stack grows upwards, starting from a low address and progressing to a higher address.
Descending Stack : The stack grows downwards, starting with a high address and progressing to a lower one.
Fundamentally, these two are same. But, I prefer descending stack, because when stack is broken, mostly post-stack-section(higher memory address) tends to be broken. So,
– [case1 : current stack has enough free space]
Descending stack is better to detect stack-corruption than ascending stack.
char a; // ---(*1)
memcpy(a, data, len); // len > 10 ---(*2)
If stack space after (*1) is not used, then even if stack is corrupted, it is very difficult to detect in ascending stack.
(because, no one uses corrupted area.) So, debugging is more difficult.
– [case2 : current stack is almost pull]
In descending stack, usually, corrupting stack of specific thread(Thread A) affects it’s own behavior firstly. So, it is easier to debug – same with [case1].
In ascending stack, corrupting stack may affects to other thread’s stack – thread whose stack is just next (higher address) of Thread A – firstly with high possibility (especially, if several stacks are adjacent in memory space). This usually leads to debugging-nightmare