mirror of
https://github.com/UberGames/ioef.git
synced 2024-12-01 00:21:19 +00:00
- Use MAP_FAILED error code for check whether mmap() was successful
- Replace various malloc() with Z_Malloc - Fix several memory leaks when VM compilation failed and Com_Error is called - Make failed mmap/VirtualAlloc/malloc calls fatal
This commit is contained in:
parent
5e0d0efd2e
commit
544a1c0c1a
5 changed files with 50 additions and 27 deletions
|
@ -1837,7 +1837,7 @@ PPC_ComputeCode( vm_t *vm )
|
||||||
unsigned char *dataAndCode = mmap( NULL, codeLength,
|
unsigned char *dataAndCode = mmap( NULL, codeLength,
|
||||||
PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0 );
|
PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0 );
|
||||||
|
|
||||||
if ( ! dataAndCode )
|
if (dataAndCode == MAP_FAILED)
|
||||||
DIE( "Not enough memory" );
|
DIE( "Not enough memory" );
|
||||||
|
|
||||||
ppc_instruction_t *codeNow, *codeBegin;
|
ppc_instruction_t *codeNow, *codeBegin;
|
||||||
|
|
|
@ -1427,7 +1427,7 @@ static void sparc_compute_code(vm_t *vm, struct func_info * const fp)
|
||||||
|
|
||||||
data_and_code = mmap(NULL, code_length, PROT_READ | PROT_WRITE,
|
data_and_code = mmap(NULL, code_length, PROT_READ | PROT_WRITE,
|
||||||
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
|
||||||
if (!data_and_code)
|
if (data_and_code == MAP_FAILED)
|
||||||
DIE("Not enough memory");
|
DIE("Not enough memory");
|
||||||
|
|
||||||
code_now = code_begin = (unsigned int *)
|
code_now = code_begin = (unsigned int *)
|
||||||
|
|
|
@ -53,6 +53,7 @@ static void VM_Destroy_Compiled(vm_t* self);
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#define VMFREE_BUFFERS() {Z_Free(buf); Z_Free(jused);}
|
||||||
static byte *buf = NULL;
|
static byte *buf = NULL;
|
||||||
static byte *jused = NULL;
|
static byte *jused = NULL;
|
||||||
static int compiledOfs = 0;
|
static int compiledOfs = 0;
|
||||||
|
@ -289,6 +290,7 @@ static int Hex( int c ) {
|
||||||
return c - '0';
|
return c - '0';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VMFREE_BUFFERS();
|
||||||
Com_Error( ERR_DROP, "Hex: bad char '%c'", c );
|
Com_Error( ERR_DROP, "Hex: bad char '%c'", c );
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -408,6 +410,7 @@ qboolean EmitMovEBXEDI(vm_t *vm, int andit) {
|
||||||
#define JUSED(x) \
|
#define JUSED(x) \
|
||||||
do { \
|
do { \
|
||||||
if (x < 0 || x >= jusedSize) { \
|
if (x < 0 || x >= jusedSize) { \
|
||||||
|
VMFREE_BUFFERS(); \
|
||||||
Com_Error( ERR_DROP, \
|
Com_Error( ERR_DROP, \
|
||||||
"VM_CompileX86: jump target out of range at offset %d", pc ); \
|
"VM_CompileX86: jump target out of range at offset %d", pc ); \
|
||||||
} \
|
} \
|
||||||
|
@ -429,7 +432,7 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
|
||||||
|
|
||||||
// allocate a very large temp buffer, we will shrink it later
|
// allocate a very large temp buffer, we will shrink it later
|
||||||
maxLength = header->codeLength * 8;
|
maxLength = header->codeLength * 8;
|
||||||
buf = Z_Malloc( maxLength );
|
buf = Z_Malloc(maxLength);
|
||||||
jused = Z_Malloc(jusedSize);
|
jused = Z_Malloc(jusedSize);
|
||||||
|
|
||||||
Com_Memset(jused, 0, jusedSize);
|
Com_Memset(jused, 0, jusedSize);
|
||||||
|
@ -454,16 +457,21 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
|
||||||
|
|
||||||
LastCommand = LAST_COMMAND_NONE;
|
LastCommand = LAST_COMMAND_NONE;
|
||||||
|
|
||||||
while ( instruction < header->instructionCount ) {
|
while(instruction < header->instructionCount)
|
||||||
if ( compiledOfs > maxLength - 16 ) {
|
{
|
||||||
Com_Error( ERR_FATAL, "VM_CompileX86: maxLength exceeded" );
|
if(compiledOfs > maxLength - 16)
|
||||||
|
{
|
||||||
|
VMFREE_BUFFERS();
|
||||||
|
Com_Error(ERR_DROP, "VM_CompileX86: maxLength exceeded");
|
||||||
}
|
}
|
||||||
|
|
||||||
vm->instructionPointers[ instruction ] = compiledOfs;
|
vm->instructionPointers[ instruction ] = compiledOfs;
|
||||||
instruction++;
|
instruction++;
|
||||||
|
|
||||||
if ( pc > header->codeLength ) {
|
if(pc > header->codeLength)
|
||||||
Com_Error( ERR_FATAL, "VM_CompileX86: pc > header->codeLength" );
|
{
|
||||||
|
VMFREE_BUFFERS();
|
||||||
|
Com_Error(ERR_DROP, "VM_CompileX86: pc > header->codeLength");
|
||||||
}
|
}
|
||||||
|
|
||||||
op = code[ pc ];
|
op = code[ pc ];
|
||||||
|
@ -1075,7 +1083,8 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
|
||||||
Emit4( (int)vm->instructionPointers );
|
Emit4( (int)vm->instructionPointers );
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Com_Error( ERR_DROP, "VM_CompileX86: bad opcode %i at offset %i", op, pc );
|
VMFREE_BUFFERS();
|
||||||
|
Com_Error(ERR_DROP, "VM_CompileX86: bad opcode %i at offset %i", op, pc);
|
||||||
}
|
}
|
||||||
pop0 = pop1;
|
pop0 = pop1;
|
||||||
pop1 = op;
|
pop1 = op;
|
||||||
|
@ -1086,13 +1095,13 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
|
||||||
vm->codeLength = compiledOfs;
|
vm->codeLength = compiledOfs;
|
||||||
#ifdef VM_X86_MMAP
|
#ifdef VM_X86_MMAP
|
||||||
vm->codeBase = mmap(NULL, compiledOfs, PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
|
vm->codeBase = mmap(NULL, compiledOfs, PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
|
||||||
if(vm->codeBase == (void*)-1)
|
if(vm->codeBase == MAP_FAILED)
|
||||||
Com_Error(ERR_DROP, "VM_CompileX86: can't mmap memory");
|
Com_Error(ERR_FATAL, "VM_CompileX86: can't mmap memory");
|
||||||
#elif _WIN32
|
#elif _WIN32
|
||||||
// allocate memory with EXECUTE permissions under windows.
|
// allocate memory with EXECUTE permissions under windows.
|
||||||
vm->codeBase = VirtualAlloc(NULL, compiledOfs, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
vm->codeBase = VirtualAlloc(NULL, compiledOfs, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
|
||||||
if(!vm->codeBase)
|
if(!vm->codeBase)
|
||||||
Com_Error(ERR_DROP, "VM_CompileX86: VirtualAlloc failed");
|
Com_Error(ERR_FATAL, "VM_CompileX86: VirtualAlloc failed");
|
||||||
#else
|
#else
|
||||||
vm->codeBase = malloc(compiledOfs);
|
vm->codeBase = malloc(compiledOfs);
|
||||||
#endif
|
#endif
|
||||||
|
@ -1101,14 +1110,14 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
|
||||||
|
|
||||||
#ifdef VM_X86_MMAP
|
#ifdef VM_X86_MMAP
|
||||||
if(mprotect(vm->codeBase, compiledOfs, PROT_READ|PROT_EXEC))
|
if(mprotect(vm->codeBase, compiledOfs, PROT_READ|PROT_EXEC))
|
||||||
Com_Error(ERR_DROP, "VM_CompileX86: mprotect failed");
|
Com_Error(ERR_FATAL, "VM_CompileX86: mprotect failed");
|
||||||
#elif _WIN32
|
#elif _WIN32
|
||||||
{
|
{
|
||||||
DWORD oldProtect = 0;
|
DWORD oldProtect = 0;
|
||||||
|
|
||||||
// remove write permissions.
|
// remove write permissions.
|
||||||
if(!VirtualProtect(vm->codeBase, compiledOfs, PAGE_EXECUTE_READ, &oldProtect))
|
if(!VirtualProtect(vm->codeBase, compiledOfs, PAGE_EXECUTE_READ, &oldProtect))
|
||||||
Com_Error(ERR_DROP, "VM_CompileX86: VirtualProtect failed");
|
Com_Error(ERR_FATAL, "VM_CompileX86: VirtualProtect failed");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,8 @@ static FILE* qdasmout;
|
||||||
#define Dfprintf(args...)
|
#define Dfprintf(args...)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define VM_FREEBUFFERS(vm) {assembler_init(0); VM_Destroy_Compiled(vm);}
|
||||||
|
|
||||||
void assembler_set_output(char* buf);
|
void assembler_set_output(char* buf);
|
||||||
size_t assembler_get_code_size(void);
|
size_t assembler_get_code_size(void);
|
||||||
void assembler_init(int pass);
|
void assembler_init(int pass);
|
||||||
|
@ -251,6 +253,7 @@ void emit(const char* fmt, ...)
|
||||||
|
|
||||||
#define CHECK_INSTR(nr) \
|
#define CHECK_INSTR(nr) \
|
||||||
do { if(nr < 0 || nr >= header->instructionCount) { \
|
do { if(nr < 0 || nr >= header->instructionCount) { \
|
||||||
|
VM_FREEBUFFERS(vm); \
|
||||||
Com_Error( ERR_DROP, \
|
Com_Error( ERR_DROP, \
|
||||||
"%s: jump target 0x%x out of range at offset %d", __func__, nr, pc ); \
|
"%s: jump target 0x%x out of range at offset %d", __func__, nr, pc ); \
|
||||||
} } while(0)
|
} } while(0)
|
||||||
|
@ -430,6 +433,8 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
|
||||||
// const optimization
|
// const optimization
|
||||||
unsigned got_const = 0, const_value = 0;
|
unsigned got_const = 0, const_value = 0;
|
||||||
|
|
||||||
|
vm->codeBase = NULL;
|
||||||
|
|
||||||
gettimeofday(&tvstart, NULL);
|
gettimeofday(&tvstart, NULL);
|
||||||
|
|
||||||
for (pass = 0; pass < 2; ++pass) {
|
for (pass = 0; pass < 2; ++pass) {
|
||||||
|
@ -441,15 +446,17 @@ void VM_Compile( vm_t *vm, vmHeader_t *header ) {
|
||||||
|
|
||||||
#ifdef VM_X86_64_MMAP
|
#ifdef VM_X86_64_MMAP
|
||||||
vm->codeBase = mmap(NULL, compiledOfs, PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
|
vm->codeBase = mmap(NULL, compiledOfs, PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
|
||||||
if(vm->codeBase == (void*)-1)
|
if(vm->codeBase == MAP_FAILED)
|
||||||
Com_Error(ERR_DROP, "VM_CompileX86: can't mmap memory");
|
Com_Error(ERR_FATAL, "VM_CompileX86_64: can't mmap memory");
|
||||||
#elif __WIN64__
|
#elif __WIN64__
|
||||||
// allocate memory with write permissions under windows.
|
// allocate memory with write permissions under windows.
|
||||||
vm->codeBase = VirtualAlloc(NULL, compiledOfs, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
|
vm->codeBase = VirtualAlloc(NULL, compiledOfs, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
|
||||||
if(!vm->codeBase)
|
if(!vm->codeBase)
|
||||||
Com_Error(ERR_DROP, "VM_CompileX86: VirtualAlloc failed");
|
Com_Error(ERR_FATAL, "VM_CompileX86_64: VirtualAlloc failed");
|
||||||
#else
|
#else
|
||||||
vm->codeBase = malloc(compiledOfs);
|
vm->codeBase = malloc(compiledOfs);
|
||||||
|
if(!vm_codeBase)
|
||||||
|
Com_Error(ERR_FATAL, "VM_CompileX86_64: Failed to allocate memory");
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
assembler_set_output((char*)vm->codeBase);
|
assembler_set_output((char*)vm->codeBase);
|
||||||
|
@ -930,7 +937,9 @@ emit_do_syscall:
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if(got_const) {
|
if(got_const)
|
||||||
|
{
|
||||||
|
VM_FREEBUFFERS(vm);
|
||||||
Com_Error(ERR_DROP, "leftover const\n");
|
Com_Error(ERR_DROP, "leftover const\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -943,14 +952,14 @@ emit_do_syscall:
|
||||||
|
|
||||||
#ifdef VM_X86_64_MMAP
|
#ifdef VM_X86_64_MMAP
|
||||||
if(mprotect(vm->codeBase, compiledOfs, PROT_READ|PROT_EXEC))
|
if(mprotect(vm->codeBase, compiledOfs, PROT_READ|PROT_EXEC))
|
||||||
Com_Error(ERR_DROP, "VM_CompileX86: mprotect failed");
|
Com_Error(ERR_FATAL, "VM_CompileX86_64: mprotect failed");
|
||||||
#elif __WIN64__
|
#elif __WIN64__
|
||||||
{
|
{
|
||||||
DWORD oldProtect = 0;
|
DWORD oldProtect = 0;
|
||||||
|
|
||||||
// remove write permissions; give exec permision
|
// remove write permissions; give exec permision
|
||||||
if(!VirtualProtect(vm->codeBase, compiledOfs, PAGE_EXECUTE_READ, &oldProtect))
|
if(!VirtualProtect(vm->codeBase, compiledOfs, PAGE_EXECUTE_READ, &oldProtect))
|
||||||
Com_Error(ERR_DROP, "VM_CompileX86: VirtualProtect failed");
|
Com_Error(ERR_FATAL, "VM_CompileX86_64: VirtualProtect failed");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -987,11 +996,16 @@ emit_do_syscall:
|
||||||
|
|
||||||
void VM_Destroy_Compiled(vm_t* self)
|
void VM_Destroy_Compiled(vm_t* self)
|
||||||
{
|
{
|
||||||
#ifdef _WIN32
|
if(self && self->codeBase)
|
||||||
|
{
|
||||||
|
#ifdef VM_X86_64_MMAP
|
||||||
|
munmap(self->codeBase, self->codeLength);
|
||||||
|
#elif __WIN64__
|
||||||
VirtualFree(self->codeBase, 0, MEM_RELEASE);
|
VirtualFree(self->codeBase, 0, MEM_RELEASE);
|
||||||
#else
|
#else
|
||||||
munmap(self->codeBase, self->codeLength);
|
free(self->codeBase);
|
||||||
#endif
|
#endif
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -244,10 +244,10 @@ static void hash_add_label(const char* label, unsigned address)
|
||||||
int labellen;
|
int labellen;
|
||||||
|
|
||||||
i %= sizeof(labelhash)/sizeof(labelhash[0]);
|
i %= sizeof(labelhash)/sizeof(labelhash[0]);
|
||||||
h = malloc(sizeof(struct hashentry));
|
h = Z_Malloc(sizeof(struct hashentry));
|
||||||
|
|
||||||
labellen = strlen(label) + 1;
|
labellen = strlen(label) + 1;
|
||||||
h->label = malloc(labellen);
|
h->label = Z_Malloc(labellen);
|
||||||
memcpy(h->label, label, labellen);
|
memcpy(h->label, label, labellen);
|
||||||
|
|
||||||
h->address = address;
|
h->address = address;
|
||||||
|
@ -282,8 +282,8 @@ static void labelhash_free(void)
|
||||||
while(h)
|
while(h)
|
||||||
{
|
{
|
||||||
struct hashentry* next = h->next;
|
struct hashentry* next = h->next;
|
||||||
free(h->label);
|
Z_Free(h->label);
|
||||||
free(h);
|
Z_Free(h);
|
||||||
h = next;
|
h = next;
|
||||||
++n;
|
++n;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue