diff --git a/sourcepawn/include/sp_vm_types.h b/sourcepawn/include/sp_vm_types.h index d6dd8989..e6973b74 100644 --- a/sourcepawn/include/sp_vm_types.h +++ b/sourcepawn/include/sp_vm_types.h @@ -30,6 +30,7 @@ typedef int32_t cell_t; #define SP_ERROR_STACKLEAK 18 /* A native leaked an item on the stack */ #define SP_ERROR_HEAPLEAK 19 /* A native leaked an item on the heap */ #define SP_ERROR_ARRAY_TOO_BIG 20 /* A dynamic array is too big */ +#define SP_ERROR_TRACKER_BOUNDS 21 /* Tracker stack is out of bounds */ /********************************************** *** The following structures are reference structures. diff --git a/sourcepawn/vm/jit/x86/jit_x86.cpp b/sourcepawn/vm/jit/x86/jit_x86.cpp index a55fb07e..6a48bbd2 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.cpp +++ b/sourcepawn/vm/jit/x86/jit_x86.cpp @@ -983,21 +983,6 @@ inline void WriteOp_Fill(JitWriter *jit) IA32_Pop_Reg(jit, REG_EDI); } -inline void WriteOp_Heap_I(JitWriter *jit) -{ - //sub [esi+hea], 4 - //mov ecx, [esi+hea] - //mov ecx, [ebp+ecx] - //sub [esi+hea], ecx - IA32_Sub_Rm_Imm8_Disp8(jit, AMX_REG_INFO, 4, AMX_INFO_HEAP); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); - IA32_Mov_Reg_RmEBP_Disp_Reg(jit, AMX_REG_TMP, AMX_REG_DAT, AMX_REG_TMP, NOSCALE); - IA32_Add_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_TMP, AMX_INFO_HEAP); - - Write_CheckHeap_Min(jit); - Write_CheckHeap_Low(jit); -} - inline void WriteOp_GenArray(JitWriter *jit, bool autozero) { cell_t val = jit->read_cell(); @@ -1064,19 +1049,6 @@ inline void WriteOp_GenArray(JitWriter *jit, bool autozero) } } -inline void WriteOp_Push_Heap_C(JitWriter *jit) -{ - //mov ecx, [esi+hea] - //mov [ebp+ecx], - //add [esi+hea], 4 - cell_t val = jit->read_cell(); - IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, AMX_REG_INFO, AMX_INFO_HEAP); - IA32_Mov_RmEBP_Imm32_Disp_Reg(jit, AMX_REG_DAT, AMX_REG_TMP, NOSCALE, val); - IA32_Add_Rm_Imm8_Disp8(jit, AMX_REG_INFO, 4, AMX_INFO_HEAP); - - Write_CheckHeap_Low(jit); -} - inline void WriteOp_Load_Both(JitWriter *jit) { WriteOp_Load_Pri(jit); @@ -1622,6 +1594,97 @@ inline void WriteOp_Sysreq_N(JitWriter *jit) } } +inline void WriteOp_Tracker_Push_C(JitWriter *jit) +{ + CompData *data = (CompData *)jit->data; + cell_t val = jit->read_cell(); + + /* Save registers that may be damaged by the call */ + //push eax + //push edx + IA32_Push_Reg(jit, AMX_REG_PRI); + IA32_Push_Reg(jit, AMX_REG_ALT); + + /* Get the context ptr, push it and call the check */ + //mov eax, [esi+context] + //push eax + //call JIT_VerifyOrAllocateTracker + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Push_Reg(jit, REG_EAX); + jitoffs_t call = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32_Abs(jit, call, JIT_VerifyOrAllocateTracker); + + /* Check for errors */ + //pop eax + //cmp [eax+err], 0 + //jnz :error + IA32_Pop_Reg(jit, REG_EAX); + IA32_Cmp_Rm_Disp8_Imm8(jit, REG_EAX, offsetof(sp_context_t, err), 0); + IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_error_tracker_bounds); + + /* Push the value into the stack and increment pCur */ + //mov edx, [eax+vm[]] + //mov ecx, [edx+pcur] + //mov [ecx], + //add [edx+pcur], 4 + IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER])); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, REG_EDX, offsetof(tracker_t, pCur)); + IA32_Mov_Rm_Imm32(jit, AMX_REG_TMP, val, MOD_MEM_REG); + IA32_Add_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur)); + + /* Restore PRI & ALT */ + //pop edx + //pop eax + IA32_Pop_Reg(jit, AMX_REG_ALT); + IA32_Pop_Reg(jit, AMX_REG_PRI); +} + +inline void WriteOp_Tracker_Pop_SetHeap(JitWriter *jit) +{ + CompData *data = (CompData *)jit->data; + + /* Save registers that may be damaged by the call */ + //push eax + //push edx + IA32_Push_Reg(jit, AMX_REG_PRI); + IA32_Push_Reg(jit, AMX_REG_ALT); + + /* Get the context ptr, push it and call the check */ + //mov eax, [esi+context] + //push eax + //call JIT_VerifyLowBoundTracker + IA32_Mov_Reg_Rm_Disp8(jit, REG_EAX, AMX_REG_INFO, AMX_INFO_CONTEXT); + IA32_Push_Reg(jit, REG_EAX); + jitoffs_t call = IA32_Call_Imm32(jit, 0); + IA32_Write_Jump32_Abs(jit, call, JIT_VerifyLowBoundTracker); + + /* Check for errors */ + //pop eax + //cmp [eax+err], 0 + //jnz :error + IA32_Pop_Reg(jit, REG_EAX); + IA32_Cmp_Rm_Disp8_Imm8(jit, REG_EAX, offsetof(sp_context_t, err), 0); + IA32_Jump_Cond_Imm32_Abs(jit, CC_NZ, data->jit_error_tracker_bounds); + + /* Pop the value from the stack and decrease the heap by it*/ + //mov edx, [eax+vm[]] + //sub [edx+pcur], 4 + //mov ecx, [edx+pcur] + //mov ecx, [ecx] + //sub [esi+hea], ecx + IA32_Mov_Reg_Rm_Disp8(jit, REG_EDX, REG_EAX, offsetof(sp_context_t, vm[JITVARS_TRACKER])); + IA32_Sub_Rm_Imm8_Disp8(jit, REG_EDX, 4, offsetof(tracker_t, pCur)); + IA32_Mov_Reg_Rm_Disp8(jit, AMX_REG_TMP, REG_EDX, offsetof(tracker_t, pCur)); + IA32_Mov_Reg_Rm(jit, AMX_REG_TMP, AMX_REG_TMP, MOD_MEM_REG); + IA32_Sub_Rm_Reg_Disp8(jit, AMX_REG_INFO, AMX_REG_TMP, AMX_INFO_HEAP); + + /* Restore PRI & ALT */ + //pop edx + //pop eax + IA32_Pop_Reg(jit, AMX_REG_ALT); + IA32_Pop_Reg(jit, AMX_REG_PRI); +} + /************************************************* ************************************************* * JIT PROPER ************************************ @@ -1732,6 +1795,9 @@ void WriteErrorRoutines(CompData *data, JitWriter *jit) data->jit_error_array_too_big = jit->get_outputpos(); Write_SetError(jit, SP_ERROR_ARRAY_TOO_BIG); + data->jit_error_tracker_bounds = jit->get_outputpos(); + Write_SetError(jit, SP_ERROR_TRACKER_BOUNDS); + data->jit_extern_error = jit->get_outputpos(); Write_GetError(jit); } @@ -1969,6 +2035,12 @@ jit_rewind: } } + tracker_t *trk = new tracker_t; + ctx->vm[JITVARS_TRACKER] = trk; + trk->pBase = (ucell_t *)malloc(1024); + trk->pCur = trk->pBase; + trk->size = 1024; + /* clean up relocation+compilation memory */ AbortCompilation(co); @@ -1999,6 +2071,8 @@ void JITX86::FreeContext(sp_context_t *ctx) delete [] ctx->publics; delete [] ctx->pubvars; delete [] ctx->symbols; + free(((tracker_t *)(ctx->vm[JITVARS_TRACKER]))->pBase); + delete ctx->vm[JITVARS_TRACKER]; delete ctx; } diff --git a/sourcepawn/vm/jit/x86/jit_x86.h b/sourcepawn/vm/jit/x86/jit_x86.h index 28673ecd..f4f40f4c 100644 --- a/sourcepawn/vm/jit/x86/jit_x86.h +++ b/sourcepawn/vm/jit/x86/jit_x86.h @@ -11,6 +11,15 @@ using namespace SourcePawn; #define JIT_INLINE_NATIVES (1<<1) #define STACK_MARGIN 64 //8 parameters of safety, I guess +#define JITVARS_TRACKER 0 //important: don't change this to avoid trouble + +typedef struct tracker_s +{ + size_t size; + ucell_t *pBase; + ucell_t *pCur; +} tracker_t; + class CompData : public ICompilation { public: @@ -36,6 +45,7 @@ public: jitoffs_t jit_error_heaplow; jitoffs_t jit_error_heapmin; jitoffs_t jit_error_array_too_big; + jitoffs_t jit_error_tracker_bounds; jitoffs_t jit_extern_error; /* returning generic error */ jitoffs_t jit_sysreq_c; /* old version! */ uint32_t codesize; /* total codesize */ diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.cpp b/sourcepawn/vm/jit/x86/opcode_helpers.cpp index 993f30e7..a00dffda 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.cpp +++ b/sourcepawn/vm/jit/x86/opcode_helpers.cpp @@ -1,5 +1,6 @@ #include #include +#include #include "jit_x86.h" #include "opcode_helpers.h" #include "x86_macros.h" @@ -687,3 +688,38 @@ void WriteOp_Sysreq_N_Function(JitWriter *jit) IA32_Return(jit); } +void JIT_VerifyOrAllocateTracker(sp_context_t *ctx) +{ + tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]); + + if ((size_t)(trk->pCur - trk->pBase) >= trk->size) + { + ctx->err = SP_ERROR_TRACKER_BOUNDS; + return; + } + + if (trk->pCur+1 - (trk->pBase + trk->size) == 0) + { + size_t disp = trk->size - 1; + trk->size *= 2; + trk->pBase = (ucell_t *)realloc(trk->pBase, trk->size); + + if (!trk->pBase) + { + ctx->err = SP_ERROR_TRACKER_BOUNDS; + return; + } + + trk->pCur = trk->pBase + disp; + } +} + +void JIT_VerifyLowBoundTracker(sp_context_t *ctx) +{ + tracker_t *trk = (tracker_t *)(ctx->vm[JITVARS_TRACKER]); + + if (trk->pCur <= trk->pBase) + { + ctx->err = SP_ERROR_TRACKER_BOUNDS; + } +} \ No newline at end of file diff --git a/sourcepawn/vm/jit/x86/opcode_helpers.h b/sourcepawn/vm/jit/x86/opcode_helpers.h index 669b9215..f47e85bc 100644 --- a/sourcepawn/vm/jit/x86/opcode_helpers.h +++ b/sourcepawn/vm/jit/x86/opcode_helpers.h @@ -66,6 +66,12 @@ void Macro_PushN_S(JitWriter *jit, int i); void Macro_PushN_C(JitWriter *jit, int i); void Macro_PushN(JitWriter *jit, int i); +/** +* Bound checking for the tracker stack, +*/ +void JIT_VerifyLowBoundTracker(sp_context_t *ctx); +void JIT_VerifyOrAllocateTracker(sp_context_t *ctx); + /** * Legend for Statuses: * ****** *** ******** @@ -245,8 +251,8 @@ typedef enum OP_SYSREQ_D, // !GEN UNSUPPORT OP_SYSREQ_ND, // !GEN UNSUPPORT /* ----- */ - OP_HEAP_I, //VERIFIED - OP_PUSH_HEAP_C, //VERIFIED + OP_TRACKER_PUSH_C, //DONE + OP_TRACKER_POP_SETHEAP, //DONE OP_GENARRAY, //VERIFIED OP_GENARRAY_Z, //-VERIFIED (not tested for 1D arrays) /* ----- */ diff --git a/sourcepawn/vm/jit/x86/opcode_switch.inc b/sourcepawn/vm/jit/x86/opcode_switch.inc index d5786fec..febe45e6 100644 --- a/sourcepawn/vm/jit/x86/opcode_switch.inc +++ b/sourcepawn/vm/jit/x86/opcode_switch.inc @@ -643,14 +643,14 @@ } break; } - case OP_PUSH_HEAP_C: + case OP_TRACKER_PUSH_C: { - WriteOp_Push_Heap_C(jit); + WriteOp_Tracker_Push_C(jit); break; } - case OP_HEAP_I: + case OP_TRACKER_POP_SETHEAP: { - WriteOp_Heap_I(jit); + WriteOp_Tracker_Pop_SetHeap(jit); break; } case OP_GENARRAY: diff --git a/sourcepawn/vm/jit/x86/x86_macros.h b/sourcepawn/vm/jit/x86/x86_macros.h index a99904e1..e623c6c8 100644 --- a/sourcepawn/vm/jit/x86/x86_macros.h +++ b/sourcepawn/vm/jit/x86/x86_macros.h @@ -398,6 +398,13 @@ inline void IA32_Sub_Reg_Rm_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t jit->write_byte(disp8); } +inline void IA32_Sub_Rm_Reg_Disp8(JitWriter *jit, jit_uint8_t dest, jit_uint8_t src, jit_int8_t disp8) +{ + jit->write_ubyte(IA32_SUB_RM_REG); + jit->write_ubyte(ia32_modrm(MOD_DISP8, src, dest)); + jit->write_byte(disp8); +} + inline void IA32_Sub_Rm_Imm8(JitWriter *jit, jit_uint8_t reg, jit_int8_t val, jit_uint8_t mode) { jit->write_ubyte(IA32_SUB_RM_IMM8);