diff -r 63cff207ded9 src/qcommon/vm.c --- a/src/qcommon/vm.c Mon Aug 04 08:30:10 2008 +0800 +++ b/src/qcommon/vm.c Mon Aug 04 16:27:51 2008 +0800 @@ -35,6 +35,8 @@ and one exported function: Perform */ #include "vm_local.h" +#include +#include vm_t *currentVM = NULL; @@ -424,7 +426,12 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboole if( alloc ) { // allocate zero filled space for initialized and uninitialized data - vm->dataBase = Hunk_Alloc( dataLength, h_high ); +#ifdef _WIN32 + DWORD _unused; + vm->dataBase = VirtualAlloc( NULL, dataLength, MEM_COMMIT, PAGE_READWRITE ); +#else + vm->dataBase = mmap( NULL, dataLength, PROT_WRITE, MAP_ANONYMOUS, -1, 0 ); +#endif vm->dataMask = dataLength - 1; } else { // clear the data @@ -437,6 +444,16 @@ vmHeader_t *VM_LoadQVM( vm_t *vm, qboole // byte swap the longs for ( i = 0 ; i < header->dataLength ; i += 4 ) { *(int *)(vm->dataBase + i) = LittleLong( *(int *)(vm->dataBase + i ) ); + } + + // lock the first page to catch NULL pointers + if ( vm->dataBase[0] == 1 ) { +#ifdef _WIN32 + DWORD _unused; + VirtualProtect( vm->dataBase, 4096, PAGE_NOACCESS, &_unused ); +#else + mmap( vm->dataBase, 4096, PROT_NONE, MAP_ANONYMOUS | MAP_FIXED, -1, 0 ); +#endif } if( header->vmMagic == VM_MAGIC_VER2 ) { @@ -632,12 +649,16 @@ void VM_Free( vm_t *vm ) { Sys_UnloadDll( vm->dllHandle ); Com_Memset( vm, 0, sizeof( *vm ) ); } + if ( vm->dataBase ) { +#ifdef _WIN32 + VirtualFree( vm->dataBase, vm->dataMask + 1, MEM_RELEASE ); +#else + munmap( vm->dataBase, vm->dataMask + 1 ); +#endif + } #if 0 // now automatically freed by hunk if ( vm->codeBase ) { Z_Free( vm->codeBase ); - } - if ( vm->dataBase ) { - Z_Free( vm->dataBase ); } if ( vm->instructionPointers ) { Z_Free( vm->instructionPointers ); diff -r 63cff207ded9 src/tools/asm/q3asm.c --- a/src/tools/asm/q3asm.c Mon Aug 04 08:30:10 2008 +0800 +++ b/src/tools/asm/q3asm.c Mon Aug 04 16:27:51 2008 +0800 @@ -1443,7 +1443,8 @@ static void Assemble( void ) { for ( i = 0 ; i < NUM_SEGMENTS ; i++ ) { segment[i].imageUsed = 0; } - segment[DATASEG].imageUsed = 4; // skip the 0 byte, so NULL pointers are fixed up properly + segment[DATASEG].imageUsed = 4096; // skip the first page, so NULL pointers get caught + segment[DATASEG].image[0] = 1; // tell the qvm loader the first page is free so it can be unmapped instructionCount = 0; for ( i = 0 ; i < numAsmFiles ; i++ ) {