The title could probably be called Stack Expansion or Stack Growth, depending upon how you like to name it. A thread stack is used to store information such as function parameters, function return addresses and local variables. It is allocated from virtual memory. A stack isn’t committed fully straight away, instead portions of virtual memory are committed when needed, and the rest of the virtual memory allocated to the stack is reserved. Stacks have certain limits, and this how stack overflows are caused. A stack begins to use virtual memory outside of the reserved region.
When a stack begins to grow or expand, then it will access the Guard Page. Once the Guard Page has been accessed, then the amount of committed memory to stack will grow. The diagram illustrates this point. Notice how the Reserved level of memory has reduced in size?
KeExpandKernelStackAndCalloutEx and KeExpandKernelStackAndCallout can be used to expand a stack. Check the WDK documentation or MSDN for more information.
Stacks typically follow the LIFO (Last In – First Out) queue algorithm. You may notice pop and push Assembly instructions being used too, push is used to insert data onto the stack, whereas, pop is used to remove data from the stack. For instance, a creation of local variable; this variable is added to the stack with a push instruction, and when the local variable is destroyed, then the pop instruction is used. Stacks do not decrease in size afterwards, once expanded they will remain that size or expand with growth.
Stack Overflows and Stack Underflows:
A stack overflow is when the stack pointer references memory outside of the reserved region, whereas, a stack underflow is when the stack pointer moves beyond the originating address of the stack.
6.1 Stack Limit Checking