Search code examples
c++winapimemory-managementallocationvirtual-memory

Why can't I reserve two contiguous memory regions in the same allocation without reserving both with a single call?


I have two memory regions I'm allocating with VirtualAlloc: 0x1E0000 (Size: 0x39000, Reserve) and 0x219000 (Size: 0x3000, Commit). These are both within the same allocation boundary (which in this case is rounded to 0x40000 (64K*4)), and the second region starts where the first ends.

Now forget the commit part for a minute. If I MEM_RESERVE the first 0x39000 and then MEM_RESERVE the next 0x3000, I get ERROR_INVALID_ADDRESS. However, if I MEM_RESERVE both in one go, 0x39000+0x3000=0x3C000, then it works, and I can use MEM_COMMIT to commit the second region successfully.

Why is that? Why can't I reserve each part on its own instead of as one big reserved region? After reserving the first region the remaining area within the allocation (0x219000-0x21FFFF) will have the MEM_FREE state, so how come I cannot reserve the first 0x3000 of the remaining 0x7000 in the allocation boundary?


Solution

  • You cannot have two separate reservations within the same allocation boundary.

    From the documentation for VirtualAlloc:

    lpAddress [in, optional] The starting address of the region to allocate. If the memory is being reserved, the specified address is rounded down to the nearest multiple of the allocation granularity.

    (emphasis mine)

    So your request to reserve memory starting at 0x219000 actually attempts to reserve memory starting at 0x210000, which is inside the existing allocation and hence illegal.

    (It should also be noted that there is no guarantee that any particular region of virtual memory will be available for you to reserve; Windows may have already reserved it for some other purpose. Best practice is to always set the lpAddress parameter to NULL, allowing Windows to choose an address for you.)