Guard ページの作成

ガード ページは、メモリ ページ アクセス用のワンショット アラームを提供します。 これは、大規模な動的データ構造の増加を監視する必要があるアプリケーションに役立ちます。 たとえば、ガード ページを使用して自動スタック チェックを実装するオペレーティング システムがあります。

ガード ページを作成するには、ページの PAGE_GUARD ページ保護修飾子を設定します。 この値は、VirtualAlloc、VirtualAllocExVirtualProtect、および 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 例外が発生します。 メモリ ブロックのガード ページ保護が最初の試行によってオフに切り替えられたため、2 回目の試行は成功します。