How can I reserve a range of address space and receive notifications when the program first reads or writes a page in the range?

Date:January 24, 2018 / year-entry #20
Tags:code
Orig Link:https://blogs.msdn.microsoft.com/oldnewthing/20180124-00/?p=97875
Comments:    4
Summary:Be in the exception handler chain.

A customer wanted to reserve a range of address space and be notified when the program first reads or writes a page in the range.

It's not clear what the customer's goal is, but if it's true that all they want is to be notified of the access, without affecting the underlying memory, then it's not so hard.

In the simplest case, you can mark the page as PAGE_GUARD. This will raise a guard page violation the first time the program reads from or writes to the memory. You can log whatever you need and then indicate that you handled the exception and want execution to continue as if no exception had occurred. The guard page violation is raised only once per page. After it's done, the memory behaves normally, either as a normal read-only page or a normal read-write page, depending on how you allocated the memory.

In the more complicated case where you want to detect reads and writes separately, you can mark the page as PAGE_NO­ACCESS. If that's all you do, then this will raise an access violation every time the program reads from or writes to the memory. But what you can do is to inspect the exception reason, and if it's "read", then change the protection from PAGE_NO­ACCESS PAGE_READ­ONLY to upgrade the page from no-access to read-only. If it's "write", then upgrade all the way to PAGE_READ­WRITE. Log the information, change the page protections, and indicate that execution should continue.

Watch out for the multithreaded case, if two threads take access violations simultaneously on the same page.

If you want this fancy memory management only for the duration of a function call, then you can install a structured exception handler around the code whose access is being monitored. If you need this beyond the scope of a single function, then you can use a vectored exception handler.

A variation of this is where you want to commit empty pages on demand. In that case, you the same technique that the Format­Message function used to use: Reserve a bunch of memory, and then install an exception handler that creates the memory on demand in response to an accss violation on one of the pages you're managing.

There is a gotcha here: Your custom page fault handler will be called only for page faults incurred by user mode. If the program passes a buffer to kernel mode (say as the source of a Write­File or the destination of a Read­File), then kernel mode will complain that the buffer is invalid because not all the pages are committed with appropriate access. To work around this, you'll have to manually fault in the pages with the appropriate protections before using then as source or destination buffers in kernel calls.

Okay, so this works in the case where the program merely wants to be notified of the access, or if it wants to swoop in and allocate blank pages. Next time, we'll look at a more complicated scenario.


Comments (4)

  1. M says:

    “It’s not clear what the customer’s goal is,”…The first thing that comes to mind is a data breakpoint on a range of addresses

  2. Peter Doubleday says:

    What a bizarre request. The last time I needed to reserve a memory range was when I dealt with dual-ported memory between a Z8530 board and some sort of M68000 mini-computer.

    Shared memory? Use the API given to you by the OS. In fact, just rely on the OS. Any OS. This sort of question suggests that the customer has never heard of virtual memory and associated software support going way back into the 1990s.

    (I’m wide open to being proven wrong in cases I haven’t considered. But, really. It’s a waste of your time.)

  3. Brian says:

    One of the 1990s era Object-Oriented databases did funky things like this with virtual memory. It made for some interesting behavior when things when you started using it – there all sorts of unexpected side-effects.

  4. Tanveer Badar says:

    There are too many typos in this post. :(


*DISCLAIMER: I DO NOT OWN THIS CONTENT. If you are the owner and would like it removed, please contact me. The content herein is an archived reproduction of entries from Raymond Chen's "Old New Thing" Blog (most recent link is here). It may have slight formatting modifications for consistency and to improve readability.

WHY DID I DUPLICATE THIS CONTENT HERE? Let me first say this site has never had anything to sell and has never shown ads of any kind. I have nothing monetarily to gain by duplicating content here. Because I had made my own local copy of this content throughout the years, for ease of using tools like grep, I decided to put it online after I discovered some of the original content previously and publicly available, had disappeared approximately early to mid 2019. At the same time, I present the content in an easily accessible theme-agnostic way.

The information provided by Raymond's blog is, for all practical purposes, more authoritative on Windows Development than Microsoft's own MSDN documentation and should be considered supplemental reading to that documentation. The wealth of missing details provided by this blog that Microsoft could not or did not document about Windows over the years is vital enough, many would agree an online "backup" of these details is a necessary endeavor. Specifics include:

<-- Back to Old New Thing Archive Index