לדלג לתוכן

פתרון הגנות וחיי מיפוי

בכתיבה לדף read only מתקבלת תקלה בגלל סוג הגישה, אף שהכתובת committed וקריאה ממנה אפשרית. הכתובת אינה נעשית תקינה לכתיבה רק מפני שהמצביע ב־C++ אינו const.

לאחר guard fault הסימון מוסר. הקריאה ל־VirtualQuery אמורה לשקף את ההגנה הבסיסית שנותרה במצב הניסוי. אם רוצים אזעקה נוספת צריך להחזיר PAGE_GUARD במפורש, תוך הבנת המרוץ האפשרי עם משתמשים אחרים.

הדוגמה הבאה מדגימה חיי אובייקט מורכב בתוך דף. היא תוכנית נפרדת; האובייקט קטן מהדף ויישורו מתאים ליישור שמספקת ההקצאה.

#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <cstdio>
#include <memory>
#include <string>

struct Item {
    std::string name;
    explicit Item(const char* text) : name(text) {}
    ~Item() { std::printf("destroy %s\n", name.c_str()); }
};

int main() {
    SYSTEM_INFO info{};
    GetSystemInfo(&info);
    if (sizeof(Item) > info.dwPageSize) return 1;
    void* storage = VirtualAlloc(nullptr, info.dwPageSize,
        MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    if (!storage) return 2;
    try {
        Item* item = std::construct_at(static_cast<Item*>(storage), "sample");
        std::printf("%s\n", item->name.c_str());
        std::destroy_at(item);
    } catch (...) {
        VirtualFree(storage, 0, MEM_RELEASE);
        throw;
    }
    return VirtualFree(storage, 0, MEM_RELEASE) ? 0 : 3;
}

הבנאי יכול להיכשל בזמן בניית string. במקרה הזה האובייקט המלא לא נוצר, אך צריך עדיין לשחרר את האחסון. אחרי בנייה מוצלחת הדוגמה מפעילה destructor לפני release. בממשק רחב יותר נעטוף גם את האובייקט שנבנה כדי שניקויו יתבצע אם פעולה מאוחרת זורקת.

מעטפת הגנות לטווח הטרוגני שומרת רשומות נפרדות לפי גבולות האזורים שנמצאו. אם שינוי חלקי נכשל, היא צריכה להחזיר את השינויים שכבר בוצעו ולדווח אם גם rollback נכשל. חלופה פשוטה יותר היא לדרוש מראש טווח הומוגני ולדחות כל קלט אחר.

ה־PAGE_NOACCESS מתאים למחסום קבוע כל עוד ההגנה נשארת כך. ה־PAGE_GUARD מתאים להתראה חד־פעמית. הגנת read only מזהה כתיבה אך מאפשר קריאה. אף אחד מהם אינו מזהה בהכרח גישה לאיבר הלא נכון בתוך אותו דף מותר.