(Win32 : WindowsProgramming-25) Stack Memory

Posted by : at

Category : win32   WindowsProgramming


  • 스레드 한 개당 하나의 스택(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;
}

About Taehyung Kim

안녕하세요? 8년차 현업 C++ 개발자 김태형이라고 합니다. 😁 C/C++을 사랑하며 다양한 사람과의 협업을 즐깁니다. ☕ 꾸준한 자기개발을 미덕이라 생각하며 노력중이며, 제가 얻은 지식을 홈페이지에 정리 중입니다. 좀 더 상세한 제 이력서 혹은 Private 프로젝트 접근 권한을 원하신다면 메일주세요. 😎

Star
Useful Links