Erstellen von Schutzseiten

Eine Schutzseite bietet einen Einmaligen Alarm für den Zugriff auf die Speicherseite. Dies kann für eine Anwendung nützlich sein, die das Wachstum großer dynamischer Datenstrukturen überwachen muss. Beispielsweise gibt es Betriebssysteme, die Schutzseiten verwenden, um die automatische Stapelüberprüfung zu implementieren.

Um eine Schutzseite zu erstellen, legen Sie den PAGE_GUARD-Seitenschutzmodifizierer für die Seite fest. Dieser Wert kann zusammen mit anderen Seitenschutzmodifizierern in den Funktionen VirtualAlloc, VirtualAllocEx, VirtualProtect und VirtualProtectEx angegeben werden. Der PAGE_GUARD-Modifizierer kann mit allen anderen Seitenschutzmodifizierern mit Ausnahme PAGE_NOACCESS verwendet werden.

Wenn ein Programm versucht, auf eine Adresse innerhalb einer Schutzseite zuzugreifen, löst das System eine STATUS_GUARD_PAGE_VIOLATION (0x80000001)-Ausnahme aus. Das System löscht auch den PAGE_GUARD-Modifizierer und entfernt die Schutzseite der Speicherseite status. Das System beendet den nächsten Versuch, auf die Speicherseite zuzugreifen, nicht mit einer STATUS_GUARD_PAGE_VIOLATION Ausnahme.

Wenn während eines Systemdiensts eine Ausnahme für die Schutzseite auftritt, schlägt der Dienst fehl und gibt in der Regel einen Fehler status Indikators zurück. Da das System auch die Schutzseite der relevanten Speicherseite status entfernt, schlägt der nächste Aufruf desselben Systemdiensts aufgrund einer STATUS_GUARD_PAGE_VIOLATION Ausnahme nicht fehl (es sei denn, jemand führt natürlich die Überwachungsseite wieder ein).

Das folgende kurze Programm veranschaulicht das Verhalten des Schutzseitenschutzes.

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

Der erste Versuch, den Speicherblock zu sperren, schlägt fehl, wodurch eine STATUS_GUARD_PAGE_VIOLATION Ausnahme ausgelöst wird. Der zweite Versuch ist erfolgreich, da der Schutzseitenschutz des Speicherblocks beim ersten Versuch deaktiviert wurde.