가드 페이지 만들기

가드 페이지는 메모리 페이지 액세스를 위한 원샷 알람을 제공합니다. 이는 대규모 동적 데이터 구조의 증가를 모니터링해야 하는 애플리케이션에 유용할 수 있습니다. 예를 들어 가드 페이지를 사용하여 자동 스택 검사를 구현하는 운영 체제가 있습니다.

가드 페이지를 만들려면 페이지에 대한 PAGE_GUARD 페이지 보호 한정자를 설정합니다. 이 값은 VirtualAlloc, VirtualAllocEx, VirtualProtect 및 VirtualProtectEx 함수에서 다른 페이지 보호 한정자와 함께 지정할 수 있습니다. PAGE_GUARD 한정자는 PAGE_NOACCESS제외한 다른 페이지 보호 한정자와 함께 사용할 수 있습니다.

프로그램이 가드 페이지 내의 주소에 액세스하려고 하면 시스템에서 STATUS_GUARD_PAGE_VIOLATION(0x80000001 ) 예외가 발생합니다. 또한 시스템은 PAGE_GUARD 한정자를 지우고 메모리 페이지의 보호 페이지 상태 제거합니다. 시스템은 STATUS_GUARD_PAGE_VIOLATION 예외를 사용하여 메모리 페이지에 액세스하려는 다음 시도를 중지하지 않습니다.

시스템 서비스 중에 가드 페이지 예외가 발생하면 서비스가 실패하고 일반적으로 일부 오류 상태 표시기를 반환합니다. 또한 시스템은 관련 메모리 페이지의 보호 페이지 상태 제거하므로 STATUS_GUARD_PAGE_VIOLATION 예외로 인해 동일한 시스템 서비스의 다음 호출이 실패하지 않습니다(물론 누군가가 가드 페이지를 다시 설정하지 않는 한).

다음 짧은 프로그램은 가드 페이지 보호의 동작을 보여 줍니다.

/* A program to demonstrate the use of guard pages of memory. Allocate
   a page of memory as a guard page, then try to access the page. That
   will fail, but doing so releases the lock on the guard page, so the
   next access works correctly.

   The output will look like this. The actual address may vary.

   This computer has a page size of 4096.
   Committed 4096 bytes at address 0x00520000
   Cannot lock at 00520000, error = 0x80000001
   2nd Lock Achieved at 00520000

   This sample does not show how to use the guard page fault to
   "grow" a dynamic array, such as a stack. */

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <tchar.h>

int main()
{
  LPVOID lpvAddr;               // address of the test memory
  DWORD dwPageSize;             // amount of memory to allocate.
  BOOL bLocked;                 // address of the guarded memory
  SYSTEM_INFO sSysInfo;         // useful information about the system

  GetSystemInfo(&sSysInfo);     // initialize the structure

  _tprintf(TEXT("This computer has page size %d.\n"), sSysInfo.dwPageSize);

  dwPageSize = sSysInfo.dwPageSize;

  // Try to allocate the memory.

  lpvAddr = VirtualAlloc(NULL, dwPageSize,
                         MEM_RESERVE | MEM_COMMIT,
                         PAGE_READONLY | PAGE_GUARD);

  if(lpvAddr == NULL) {
    _tprintf(TEXT("VirtualAlloc failed. Error: %ld\n"),
             GetLastError());
    return 1;

  } else {
    _ftprintf(stderr, TEXT("Committed %lu bytes at address 0x%lp\n"),
              dwPageSize, lpvAddr);
  }

  // Try to lock the committed memory. This fails the first time 
  // because of the guard page.

  bLocked = VirtualLock(lpvAddr, dwPageSize);
  if (!bLocked) {
    _ftprintf(stderr, TEXT("Cannot lock at %lp, error = 0x%lx\n"),
              lpvAddr, GetLastError());
  } else {
    _ftprintf(stderr, TEXT("Lock Achieved at %lp\n"), lpvAddr);
  }

  // Try to lock the committed memory again. This succeeds the second
  // time because the guard page status was removed by the first 
  // access attempt.

  bLocked = VirtualLock(lpvAddr, dwPageSize);

  if (!bLocked) {
    _ftprintf(stderr, TEXT("Cannot get 2nd lock at %lp, error = %lx\n"),
              lpvAddr, GetLastError());
  } else {
    _ftprintf(stderr, TEXT("2nd Lock Achieved at %lp\n"), lpvAddr);
  }

  return 0;
}

메모리 블록을 잠그려는 첫 번째 시도가 실패하여 STATUS_GUARD_PAGE_VIOLATION 예외가 발생합니다. 메모리 블록의 보호 페이지 보호가 첫 번째 시도에서 해제되었기 때문에 두 번째 시도가 성공합니다.