- 스레드 한 개당 하나의 스택(1m) 생성
- 높은 주소에서 낮은 주소 방향으로 사용
void foo(int a, int b)
{
int c = 0;
foo(1, 2); // 재귀 호출
}
int main()
{
int n1 = 10;
int n2 = 20;
foo(1, 2);
}
<< Stack >>
|--------|
| n1 | <- 지역변수
| n2 |
| 2 | <- 함수에 전달한 인자 마지막 인자부터 push
| 1 |
| c | <- c지역변수
| 2 |
| 1 |
...(무한 반복)
Stack의 동작 방식
<< 기본 1Mb 할당 >>
|------------------|
| Commit PAGE |
| Commit PAGE |
| Commit PAGE | <- PAGE_GUARD
| |
| |
| 1M |
PAGE_GUARD에 도달할 경우 OS서 Commit PAGE를 더해서 메모리를 더 Commit
|------------------|
| Commit PAGE |
| Commit PAGE |
| Commit PAGE |
| |
| ... |
| |
| Commit PAGE |
| Commit PAGE |
| |
마지막 페이지는 Commit이 없이 접근 시 EXCEPTION_STACK_OVERFLOW예외를 OS에서 던진다.
#include <stdio.h>
#include <Windows.h>
int main()
{
char* p = (char*)VirtualAlloc(0, 1024 * 1024, MEM_RESERVE, PAGE_READWRITE);
VirtualAlloc(p, 4096, MEM_COMMIT, PAGE_READWRITE);
VirtualAlloc(p + 4096, 4096, MEM_COMMIT, PAGE_READWRITE | PAGE_GUARD);
p[0] = 'A';
p[4095] = 'B';
__try
{
p[4096] = 'C';
}
__except(1)
{
// PAGE_GUARD에 접근시 예외가 나온다
printf("%x\n", GetExceptionCode()); // 8000001(EXCEPTION_GUARD_PAGE)
}
// 다시 접근시 정상사용가능
p[4096] = 'C';
}
#include <stdio.h>
#include <Windows.h>
DWORD Filter(int cnt, int code);
// 1M : 256개의 PAGE
#define LAST_GUARD_PAGE 253
#define PAGE_SIZE 4096
int guard_page = 1;
char* stack_addr = 0;
int main()
{
// 1M를 예약
stack_addr = (char*)VirtualAlloc(0, 1024 * 1024, MEM_RESEVE, PAGE_READWRITE);
VirtualAlloc(stack_addr, PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE);
VirtualAlloc(stack_addr + guard_page * PAGE_SIZE, PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE | PAGE_GUARD);
int i = 0;
__try
{
for(int i = 0; i < 1024*1024; i++)
{
stack_addr[i] = 'A';
}
}
__except(Filter(i, GetExceptionCode()))
{
printf("STACK OVERFLOW %x\n", GetExceptionCode());
}
}
DWORD Filter(int cnt, int code)
{
if(code == EXCEPTION_GUARD_PAGE)
{
if(guard_page < LAST_GUARD_PAGE)
{
++guard_page;
VirtualAlloc(stack_addr + guard_page * PAGE_SIZE, PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE | PAGE_GUARD);
printf("%d : GUARD MOVE NEXT %d PAGE\n", cnt, guard_page);
return -1;
}
else if(guard_page == LAST_GUARD_PAGE)
{
++guard_page;
VirtualAlloc(stack_addr + guard_page * PAGE_SIZE, PAGE_SIZE, MEM_COMMIT, PAGE_READWRITE);
printf("%d : LAST PAGE\n", cnt);
return -1;
}
}
return 1;
}