VirtualAlloc Error

I am trying to use VirtualAlloc to reserve and commit a block of memory, and then again to expand that block. Unfortunately, it returns NULL with the ERROR_INVALID_ADDRESS error, even though VirtualQuery says the requested range of addresses is free. Here is my code:

void* allocation = VirtualAlloc(NULL, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); void* desiredNextAllocation = (char*)allocation + 4096; MEMORY_BASIC_INFORMATION info; size_t memory_info = VirtualQuery(desiredNextAllocation, &info, sizeof(info)); void* extended = VirtualAlloc(desiredNextAllocation, 4096, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); 

The first distribution returns 0x00000000000d0000. A call to VirtualQuery results in the following data in "info":

  BaseAddress 0x00000000000d1000 void * AllocationBase 0x0000000000000000 void * AllocationProtect 0x00000000 unsigned long RegionSize 0x00000000000ff000 unsigned __int64 State 0x00010000 unsigned long Protect 0x00000001 unsigned long Type 0x00000000 unsigned long 

I interpret this as meaning that there are 0xff pages available, starting with 0xd1000, that are in the MEM_FREE state. So why is my attempt to freeze the page at 0xd1000 fail?

I am running Windows 7 and this is a 64 bit build.

I read a few StackOverflow posts about VirtualAlloc, but they all seem to imply that this code should work just like my understanding of the documentation.

+6
source share
2 answers

From the documentation for VirtualAlloc :

If the memory is reserved, the specified address is rounded to the nearest multiple distribution granularity.

In this case, the address 0xd1000 is rounded to the address 0xd0000, which is already reserved and therefore invalid.

+1
source

If you want to specify adjacent pages for distributions, you want to separate the allocation of address space from the allocation of memory to return it. With that in mind, we could implement the code like this:

 #include <windows.h> #include <iostream> #include <iomanip> std::ostream &operator<<(std::ostream &os, MEMORY_BASIC_INFORMATION const &mi) { return os << std::setw(20) << "Allocation Base: " << mi.AllocationBase << "\n" << std::setw(20) << "BaseAddress: " << mi.BaseAddress << "\n" << std::setw(20) << "Protection: " << mi.Protect << "\n" << std::setw(20) << "Region size: " << mi.RegionSize; } void show_page(void *page) { MEMORY_BASIC_INFORMATION info; VirtualQuery(page, &info, sizeof(info)); std::cout << info << "\n\n"; } static const int page_size = 4096; void *alloc_page(char *address) { void *ret = VirtualAlloc(address, page_size, MEM_COMMIT, PAGE_READWRITE); show_page(ret); return ret; } int main() { static const int region_size = 65536; char * alloc = static_cast<char *>(VirtualAlloc(NULL, region_size, MEM_RESERVE, PAGE_READWRITE)); for (int i = 0; i < 4; i++) alloc_page(alloc + page_size * i); } 

Result:

 Allocation Base: 00000000000C0000 BaseAddress: 00000000000C0000 Protection: 4 Region size: 4096 Allocation Base: 00000000000C0000 BaseAddress: 00000000000C1000 Protection: 4 Region size: 4096 Allocation Base: 00000000000C0000 BaseAddress: 00000000000C2000 Protection: 4 Region size: 4096 Allocation Base: 00000000000C0000 BaseAddress: 00000000000C3000 Protection: 4 Region size: 4096 

As you can see, all distributions are now doing well. Aside: when you reserve an address space, the smallest size you can allocate is 64K (as shown above). You really need to get the page size and minimum region size by calling GetSystemInfo , and using dwPageSize and dwAllocationGranularity in the SYSTEM_INFO structure that it will provide you.

+4
source

Source: https://habr.com/ru/post/985982/


All Articles