1

Here's another question I met when reading < Windows via C/C++ 5th Edition >. First, let's see some quotation.

LPVOID WINAPI VirtualAlloc(
  __in_opt  LPVOID lpAddress,
  __in      SIZE_T dwSize,
  __in      DWORD fdwAllocationType,
  __in      DWORD fdwProtect
);

The last parameter, fdwProtect, indicates the protection attribute that should be assigned to the region. The protection attribute associated with the region has no effect on the committed storage mapped to the region.

When reserving a region, assign the protection attribute that will be used most often with the storage committed to the region. For example, if you intend to commit physical storage with a protection attribute of PAGE_READWRITE, you should reserve the region with PAGE_READWRITE. The system's internal record keeping behaves more efficiently when the region's protection attribute matches the committed storage's protection attribute.

(When commiting storage)...you usually pass the same page protection attribute that was used when VirtualAlloc was called to reserve the region, although you can specify a different protection attribute.

The above quotation totally puzzled me.

  • If the protection attribute associated with the region has no effect on the committed storage, why do we need it?

  • Since it is recommended to use the same protection attribute for both reserving and committing, why does Windows still offer us the option to use different attribute? Isn't it mis-leading and kind of a paradox?

  • Where exactly is the protection attribute stored for reserved region and committed storage, repectively?

Many thanks for your insights.

smwikipedia
  • 61,609
  • 92
  • 309
  • 482

2 Answers2

3

It's important to read it in context.

The protection attribute associated with the region has no effect on the committed storage mapped to the region.

was referring to reserving, not committing regions.

A reserved page has no backing store, so it's protection is always conceptually PAGE_NOACCESS, regardless of what you pass to VirtualAlloc. I.e. if a thread attempts to read/write to an address in a reserved region, an access violation is raised.

From linked article:

Reserved addresses are always PAGE_NOACCESS, a default enforced by the system no matter what value is passed to the function. Committed pages can be either read-only, read-write, or no-access.

Re:

  • Where exactly is the protection attribute stored for reserved region and committed storage, repectively?

The protection attributes for virtual address regions are stored in the VAD tree, per process. (VAD == Virtual Address Descriptor, see Windows Internals, or linked article)

Since it is recommended to use the same protection attribute for both reserving and committing, why does Windows still offer us the option to use different attribute? Isn't it mis-leading and kind of a paradox?

Because the function always accepts a protection parameter, but its behaviour depends on fdwAllocationType. Protection only makes sense for committed storage.

The reason Richter suggests using the same protection setting is presumably because fewer changes in the protection flags in a region mean fewer "blocks" (see your book for definition), and hence a smaller AVL tree for the VADs. I.e. if all pages in a region are committed with the same flags, there'll only be 1 block. Otherwise there could be as many blocks as pages in the region. And you need a VAD for each block (not page).

Block == set of consecutive pages with identical protection/state.

If the protection attribute associated with the region has no effect on the committed storage, why do we need it?

As above.

Alex Budovski
  • 17,947
  • 6
  • 53
  • 58
  • Many thanks Alex. Your explanation is very educative. And you direct me to a wealth of knowledge. I will update this thread with my new thoughts later. Thanks again. – smwikipedia Nov 23 '10 at 16:08
2

Well... One reason could be so you could use guard pages so you can commit memory as you use it.

Think of the thread stack in Windows; the page immediately below the stack is set as a guard page, typically with read and write ability. Once the guard page is touched, an exception handler runs and commits the guard page and makes the next page a guard.

See here for a better description. Also, that link is part of a series on how windows handles low level resources and is pretty good reading.

Another reason for allowing you to respecify the protection attributes could be for copy on write techniques. Pages are set to read only until they're changed, which can raise an exception you can handle etc etc etc.

On the 386 family of Intel chips, the commit, read/write/reserve flags are stored in the page tables. Take a look at a 386 chip reference for more details. Edit: I poked around for a bit and could not find where MS stores the PAGE_GUARD bit. Now I'm curious where I saw it. :) Too bad I threw out about 500 pounds of old reference material last spring...

Hope this helps :)

JimR
  • 15,513
  • 2
  • 20
  • 26
  • It seems that the stack can grow automatically because of the guard page. I think this couldn't be achieved without the cpu hardware's support. The PAGE_GUARD attribute is stored in the Page Table Entry (PTE) and the CPU could detect access to such a page and trig an exception. Am I right on this? – smwikipedia Nov 23 '10 at 09:34
  • 3
    @smwikipedia, PTEs don't have enough bits for a GUARD flag or anything else the OS could come up with. The GUARD flag and other "extended" protection bits must be in the VAD. So guard pages have the V bit off in the PTE, which triggers a PFE and the handler code looks up the VAD tree and figures out that the page is a guard page. – Alex Budovski Nov 23 '10 at 10:08
  • Thanks again, Alex. It seems the second book for me after < Windows via C/C++ > will be < Windows Internals >. Is this sequence all right? Could you give me some suggestions if this is not a good idea? :) – smwikipedia Nov 24 '10 at 01:19
  • 1
    @smwikipedia Your statement about guard pages is correct. Russinovich explains it very well in the first link I gave in the answer. I tried (and failed) to find out where the guard page bit is stored. Alex is correct that it not in the actual processor page tables. – JimR Nov 24 '10 at 04:28