2015-04-26 4 views
6

Sto tentando di utilizzare VirtualAlloc per riservare e memorizzare un blocco di memoria e quindi di nuovo per estendere tale blocco. Sfortunatamente, restituisce NULL con errore ERROR_INVALID_ADDRESS nonostante VirtualQuery affermi che l'intervallo di indirizzi richiesto è libero. Ecco il mio codice:Errore VirtualAlloc

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

La prima allocazione restituisce 0x00000000000d0000. La chiamata ai risultati VirtualQuery nei seguenti dati 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 

ho interpretare che per significare che ci sono pagine disponibili 0xff inizio alle 0xd1000, che si trovano nello stato MEM_FREE. Allora perché il mio tentativo di impegnare la pagina su 0xd1000 fallisce?

Sono in esecuzione Windows 7 e questa è una build a 64 bit.

Ho letto diversi post StackOverflow su VirtualAlloc ma sembrano tutti implicare che questo codice dovrebbe funzionare come la mia comprensione della documentazione.

risposta

1

Dal documentation for VirtualAlloc:

Se la memoria viene riservata, l'indirizzo specificato viene arrotondato al multiplo più vicino della granularità di allocazione.

In questo caso, l'indirizzo 0xd1000 viene arrotondato per difetto all'indirizzo 0xd0000, che è già prenotato e quindi non valido.

4

Se si desidera specificare le pagine contigue per le allocazioni, si desidera separare allocare lo spazio degli indirizzi dall'allocazione della memoria al suo back-up. Tenendo questo in mente, abbiamo potuto implementare il codice simile al seguente:

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

risultato Esempio:

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 

Come si può vedere, tutte le allocazioni ora riescono. A parte: quando stai riservando lo spazio degli indirizzi, la dimensione più piccola che puoi assegnare è 64 KB (come mostrato sopra). Si dovrebbe veramente ottenere la dimensione della pagina e la dimensione minima della regione chiamando GetSystemInfo e usando lo dwPageSize e dwAllocationGranularity nella struttura SYSTEM_INFO che fornisce.