From: Dmitry Stogov Date: Thu, 30 Apr 2020 12:32:01 +0000 (+0300) Subject: Replace ZEND_ASSERT() by conditional compilation abort. X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3c04ce43edea5c7b0b4a06babb3c73c1a6019213;p=php Replace ZEND_ASSERT() by conditional compilation abort. Prevent endless loop through ESCAPE code. --- diff --git a/ext/opcache/jit/zend_jit_internal.h b/ext/opcache/jit/zend_jit_internal.h index c787bbf8b1..b5f8428689 100644 --- a/ext/opcache/jit/zend_jit_internal.h +++ b/ext/opcache/jit/zend_jit_internal.h @@ -351,6 +351,7 @@ typedef struct _zend_jit_trace_info { uint32_t code_size; /* size of native code */ uint32_t exit_counters; /* offset in exit counters array */ uint32_t stack_map_size; + const zend_op *opline; /* first opline */ const void *code_start; /* address of native code */ zend_jit_trace_exit_info *exit_info; /* info about side exits */ zend_jit_trace_stack *stack_map; diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index 20696f5f5f..88d927213a 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -1056,7 +1056,10 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin stack = frame->stack; op_array = p->op_array; level++; - ZEND_ASSERT(ssa_vars_count < 0xff); + // TODO: remove this restriction ??? + if (ssa_vars_count >= 0xff) { + return NULL; + } p->first_ssa_var = ssa_vars_count; for (i = 0; i < op_array->last_var; i++) { SET_STACK_VAR(stack, i, ssa_vars_count++); @@ -1066,7 +1069,10 @@ static zend_ssa *zend_jit_trace_build_tssa(zend_jit_trace_rec *trace_buffer, uin frame = zend_jit_trace_ret_frame(frame, op_array); stack = frame->stack; if (level == 0) { - ZEND_ASSERT(ssa_vars_count <= 0xff); + // TODO: remove this restriction ??? + if (ssa_vars_count >= 0xff) { + return NULL; + } p->first_ssa_var = ssa_vars_count; for (i = 0; i < op_array->last_var + op_array->T; i++) { SET_STACK_VAR(stack, i, ssa_vars_count++); @@ -2456,6 +2462,12 @@ static const void *zend_jit_trace(zend_jit_trace_rec *trace_buffer, uint32_t par ssa = zend_jit_trace_build_tssa(trace_buffer, parent_trace, exit_num, script, op_arrays, &num_op_arrays); + if (!ssa) { + zend_arena_release(&CG(arena), checkpoint); + JIT_G(current_trace) = NULL; + return NULL; + } + /* Register allocation */ if (zend_jit_reg_alloc && zend_jit_level >= ZEND_JIT_LEVEL_INLINE) { ra = zend_jit_trace_allocate_registers(trace_buffer, ssa, parent_trace, exit_num); @@ -3990,7 +4002,7 @@ done: t->link = zend_jit_find_trace(p->opline->handler); zend_jit_trace_link_to_root(&dasm_state, p->opline->handler); } else if (p->stop == ZEND_JIT_TRACE_STOP_RETURN) { - zend_jit_trace_return(&dasm_state); + zend_jit_trace_return(&dasm_state, 0); } else { // TODO: not implemented ??? ZEND_ASSERT(0 && p->stop); @@ -4053,6 +4065,7 @@ static const void *zend_jit_trace_exit_to_vm(uint32_t trace_num, uint32_t exit_n const zend_op *opline; uint32_t i, stack_size; zend_jit_trace_stack *stack; + zend_bool original_handler = 0; if (!zend_jit_trace_exit_needs_deoptimization(trace_num, exit_num)) { return dasm_labels[zend_lbtrace_escape]; @@ -4084,9 +4097,13 @@ static const void *zend_jit_trace_exit_to_vm(uint32_t trace_num, uint32_t exit_n opline = (const zend_op*)((uintptr_t)opline & ~(ZEND_JIT_EXIT_JITED|ZEND_JIT_EXIT_BLACKLISTED)); if (opline) { zend_jit_set_ip(&dasm_state, opline); + if (opline == zend_jit_traces[zend_jit_traces[trace_num].root].opline) { + /* prevent endless loop */ + original_handler = 1; + } } - zend_jit_trace_return(&dasm_state); + zend_jit_trace_return(&dasm_state, original_handler); handler = dasm_link_and_encode(&dasm_state, NULL, NULL, NULL, NULL, name, 1); @@ -4123,6 +4140,7 @@ static zend_jit_trace_stop zend_jit_compile_root_trace(zend_jit_trace_rec *trace t->exit_count = 0; t->child_count = 0; t->stack_map_size = 0; + t->opline = ((zend_jit_trace_start_rec*)trace_buffer)->opline; t->exit_info = exit_info; t->stack_map = NULL; @@ -4674,6 +4692,7 @@ static zend_jit_trace_stop zend_jit_compile_side_trace(zend_jit_trace_rec *trace t->exit_count = 0; t->child_count = 0; t->stack_map_size = 0; + t->opline = NULL; t->exit_info = exit_info; t->stack_map = NULL; diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 9501e08375..11377f051e 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -2995,23 +2995,38 @@ static int zend_jit_trace_link_to_root(dasm_State **Dst, const void *code) return 1; } -static int zend_jit_trace_return(dasm_State **Dst) +static int zend_jit_trace_return(dasm_State **Dst, zend_bool original_handler) { #if 0 | jmp ->trace_escape #else if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) { | add r4, HYBRID_SPAD - | JMP_IP + if (!original_handler) { + | JMP_IP + } else { + | mov r0, EX->func + | mov r0, aword [r0 + offsetof(zend_op_array, reserved[zend_func_info_rid])] + | mov r0, aword [r0 + offsetof(zend_jit_op_array_trace_extension, offset)] + | jmp aword [IP + r0] + } } else if (GCC_GLOBAL_REGS) { | add r4, SPAD // stack alignment - | JMP_IP + if (!original_handler) { + | JMP_IP + } else { + | mov r0, EX->func + | mov r0, aword [r0 + offsetof(zend_op_array, reserved[zend_func_info_rid])] + | mov r0, aword [r0 + offsetof(zend_jit_op_array_trace_extension, offset)] + | jmp aword [IP + r0] + } } else { | mov FP, aword T2 // restore FP | mov RX, aword T3 // restore IP | add r4, NR_SPAD // stack alignment | mov r0, 2 // ZEND_VM_LEAVE | ret + // TODO: support for "original_handler" ???? } #endif return 1;