Creazione di pagine guard

Una pagina di protezione fornisce un allarme unico per l'accesso alla pagina di memoria. Ciò può essere utile per un'applicazione che deve monitorare la crescita di strutture di dati dinamiche di grandi dimensioni. Ad esempio, esistono sistemi operativi che usano pagine di protezione per implementare il controllo dello stack automatico.

Per creare una pagina di protezione, impostare il modificatore di protezione della pagina PAGE_GUARD per la pagina. Questo valore può essere specificato, insieme ad altri modificatori di protezione delle pagine, nelle funzioni VirtualAlloc, VirtualAllocEx, VirtualProtect e VirtualProtectEx . Il modificatore PAGE_GUARD può essere usato con qualsiasi altro modificatore di protezione della pagina, ad eccezione di PAGE_NOACCESS.

Se un programma tenta di accedere a un indirizzo all'interno di una pagina guard, il sistema genera un'eccezione STATUS_GUARD_PAGE_VIOLATION (0x80000001). Il sistema cancella anche il modificatore PAGE_GUARD , rimuovendo lo stato della pagina di protezione della pagina di memoria. Il sistema non arresterà il tentativo successivo di accedere alla pagina della memoria con un'eccezione STATUS_GUARD_PAGE_VIOLATION .

Se si verifica un'eccezione della pagina di protezione durante un servizio di sistema, il servizio ha esito negativo e restituisce in genere un indicatore di stato di errore. Poiché il sistema rimuove anche lo stato della pagina di protezione della pagina di memoria pertinente, la chiamata successiva dello stesso servizio di sistema non avrà esito negativo a causa di un'eccezione STATUS_GUARD_PAGE_VIOLATION (a meno che, naturalmente, qualcuno riestablisi la pagina di protezione).

Il breve programma seguente illustra il comportamento di protezione delle pagine di protezione.

/* 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;
}

Il primo tentativo di bloccare il blocco di memoria ha esito negativo, generando un'eccezione STATUS_GUARD_PAGE_VIOLATION . Il secondo tentativo ha esito positivo, perché la protezione della pagina di protezione del blocco di memoria è stata disattivata dal primo tentativo.