Index: code/tools/asm/q3asm.c =================================================================== --- code/tools/asm/q3asm.c (revision 1457) +++ code/tools/asm/q3asm.c (working copy) @@ -1442,7 +1442,8 @@ 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++ ) { Index: code/qcommon/vm.c =================================================================== --- code/qcommon/vm.c (revision 1457) +++ code/qcommon/vm.c (working copy) @@ -34,6 +34,15 @@ */ #include "vm_local.h" +#include +#ifdef _WIN32 +#include +#else +#include +#ifndef MAP_ANONYMOUS +#define MAP_ANONYMOUS MAP_ANON +#endif +#endif vm_t *currentVM = NULL; @@ -423,7 +432,15 @@ if( alloc ) { // allocate zero filled space for initialized and uninitialized data - vm->dataBase = Hunk_Alloc( dataLength, h_high ); +#ifdef _WIN32 + vm->dataBase = VirtualAlloc( NULL, dataLength, MEM_COMMIT, PAGE_READWRITE ); + if(!vm->dataBase) + Com_Error(ERR_DROP, "VM_LoadQVM: VirtualAlloc failed"); +#else + vm->dataBase = mmap( NULL, dataLength, PROT_WRITE | PROT_READ, MAP_SHARED | MAP_ANONYMOUS, -1, 0 ); + if(vm->dataBase == (void*)-1) + Com_Error(ERR_DROP, "VM_LoadQVM: can't mmap memory"); +#endif vm->dataMask = dataLength - 1; } else { // clear the data @@ -438,6 +455,17 @@ *(int *)(vm->dataBase + i) = LittleLong( *(int *)(vm->dataBase + i ) ); } + // lock the first page to catch NULL pointers (only do this if the loaded qvm supports it) + // Fail silently + if ( vm->dataBase[0] == 1 ) { +#ifdef _WIN32 + DWORD _unused = 0; + VirtualProtect( vm->dataBase, 4096, PAGE_NOACCESS, &_unused ); +#else + mprotect( vm->dataBase, 4096, PROT_NONE ); +#endif + } + if( header->vmMagic == VM_MAGIC_VER2 ) { vm->numJumpTableTargets = header->jtrgLength >> 2; Com_Printf( "Loading %d jump table targets\n", vm->numJumpTableTargets ); @@ -631,13 +659,17 @@ Sys_UnloadDll( vm->dllHandle ); Com_Memset( vm, 0, sizeof( *vm ) ); } + if ( vm->dataBase ) { +#ifdef _WIN32 + VirtualFree( vm->dataBase, 0, 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 ); }