Search code examples
c++memoryx86windows-10-desktopvirtual-address-space

Understanding base addresses in VirtualAlloc


In my application I'm trying to allocate a large block of memory (approximately 1GB-2GB) through VirtualAlloc on startup that I can then later divide up for use throughout the rest of the application. When in debug mode I want to pass a base address in the VirtualAlloc call to keep pointer addresses consistent for easier debugging but I'm struggling to understand what would be a valid base address that I could use.

Here's a snippet of the code where the allocation takes place

s32 CALLBACK WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdLine, s32 showCode)
{
    SYSTEM_INFO info = {};
    GetSystemInfo(&info);

    // In my case info.lpMinimumApplicationAddress gives me 64kb
    LPVOID base = info.lpMinimumApplicationAddress;
    u32 totalSize = MEGABYTES(8);
    void *test = VirtualAlloc(base, totalSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

    ...
}

The application is x86 running on a 64bit version of Windows and according to this information that I've found: https://www.tenouk.com/WinVirtualAddressSpace.html

The virtual memory space reserved for application only should range from 4MB to 2GB. But when I try to allocate even a small amount of memory like in the snippet above with a base address of 64KB (as given by the system info) or in and around 4MB as per the referenced website VirtualAlloc returns 0. I've tried investigating the virtual memory space by using VirtualQueryEx and the largest block of memory I could find was approximately 2GB in size but was at a base address of 2GB. Which according to the information above would mean I was allocating in to system memory which could be potentially dangerous?

So in short I was wondering if anyone could clarify if the information I'm referring to on that website is accurate and whether having a large base address of say 1GB or 2GB is safe to use? My only other thoughts for a solution would be to scan through the virtual address space for a large enough block and use the first one I find as a base address but I'm unsure if that base address would remain consistent between successive runs for the sake of debugging.

Thanks in advance.


Solution

  • The linked article is for 32-bit mode. In 64-bit mode reserved addresses start from 128 TB. Here's what MSDN says about it:

    For a 32-bit process, the virtual address space is usually the 2-gigabyte range 0x00000000 through 0x7FFFFFFF. For a 64-bit process on 64-bit Windows, virtual address space is the 128-terabyte range 0x000'00000000 through 0x7FFF'FFFFFFFF. A range of virtual addresses is sometimes called a range of virtual memory. For more info, see Memory and Address Space Limits.

    So you're safe.

    But you should not care or probe for base address at all - simply pass NULL as the base address and VirtualAlloc will select one for you:

    lpAddress

    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. . . . If this parameter is NULL, the system determines where to allocate the region.