Сбой VirtualAlloc

Я пытаюсь использовать VirtualAlloc для резервирования и фиксации блока памяти, а затем снова для расширения этого блока. К сожалению, он возвращает NULL с ошибкой ERROR_INVALID_ADDRESS, несмотря на то, что VirtualQuery говорит, что запрошенный диапазон адресов свободен. Вот мой код:

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);

Первое распределение возвращает 0x00000000000d0000. Вызов VirtualQuery приводит к следующим данным в ‘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

Я понимаю, что это означает, что есть 0xff доступных страниц, начинающихся с 0xd1000, которые находятся в состоянии MEM_FREE. Так почему моя попытка зафиксировать страницу в 0xd1000 не удалась?

Я использую Windows 7, и это 64-битная сборка.

Я прочитал несколько сообщений StackOverflow о VirtualAlloc, но, похоже, все они подразумевают, что этот код должен работать так же, как и мое понимание документации.

6

Решение

От документация для VirtualAlloc:

Если память зарезервирована, указанный адрес округляется до ближайшего кратного гранулярности выделения.

В этом случае адрес 0xd1000 округляется до адреса 0xd0000, который уже зарезервирован и, следовательно, недействителен.

1

Другие решения

Если вы хотите указать смежные страницы для выделения, вы хотите отделить выделение адресного пространства от выделения памяти для его поддержки. Помня об этом, мы могли бы реализовать код примерно так:

#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);
}

Пример результата:

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

Как видите, все распределения теперь выполнены успешно. Кроме того: когда вы резервируете адресное пространство, наименьший размер, который вы можете выделить, составляет 64 КБ (как показано выше). Вы должны действительно получить размер страницы и минимальный размер региона, позвонив GetSystemInfoи используя dwPageSize а также dwAllocationGranularity в SYSTEM_INFO структура это дает вам.

4

По вопросам рекламы [email protected]