From: Dmitry Stogov Date: Thu, 16 Jul 2020 12:14:11 +0000 (+0300) Subject: Check type guard on result of FETCH_OBJ_R/IS instructions X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=d50919a03b227999d283be084918ac83a6dad14d;p=php Check type guard on result of FETCH_OBJ_R/IS instructions --- diff --git a/ext/opcache/jit/zend_jit_trace.c b/ext/opcache/jit/zend_jit_trace.c index b64429b1a7..b15346545c 100644 --- a/ext/opcache/jit/zend_jit_trace.c +++ b/ext/opcache/jit/zend_jit_trace.c @@ -5554,7 +5554,10 @@ int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf if (t->exit_info[exit_num].flags & ZEND_JIT_EXIT_FREE_OP1) { ZEND_ASSERT((opline-1)->opcode == ZEND_FETCH_DIM_R || (opline-1)->opcode == ZEND_FETCH_DIM_IS - || (opline-1)->opcode == ZEND_FETCH_DIM_FUNC_ARG); + || (opline-1)->opcode == ZEND_FETCH_DIM_FUNC_ARG + || (opline-1)->opcode == ZEND_FETCH_OBJ_R + || (opline-1)->opcode == ZEND_FETCH_OBJ_IS + || (opline-1)->opcode == ZEND_FETCH_OBJ_FUNC_ARG); EX(opline) = opline-1; zval_ptr_dtor_nogc(EX_VAR((opline-1)->op1.var)); } diff --git a/ext/opcache/jit/zend_jit_x86.dasc b/ext/opcache/jit/zend_jit_x86.dasc index 5a181b0df8..407d8a178d 100644 --- a/ext/opcache/jit/zend_jit_x86.dasc +++ b/ext/opcache/jit/zend_jit_x86.dasc @@ -1023,6 +1023,23 @@ static void* dasm_labels[zend_lb_MAX]; /* the same as above, but "src" may overlap with "tmp_reg1" */ |.macro ZVAL_COPY_VALUE, dst_addr, dst_info, src_addr, src_info, tmp_reg1, tmp_reg2 +| ZVAL_COPY_VALUE_V dst_addr, dst_info, src_addr, src_info, tmp_reg1, tmp_reg2 +|| if ((src_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE)) && +|| !(src_info & MAY_BE_GUARD) && +|| has_concrete_type(src_info & MAY_BE_ANY)) { +|| if (Z_MODE(dst_addr) == IS_MEM_ZVAL) { +|| if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD))) { +|| zend_uchar type = concrete_type(src_info); +| SET_ZVAL_TYPE_INFO dst_addr, type +|| } +|| } +|| } else { +| GET_ZVAL_TYPE_INFO Rd(tmp_reg1), src_addr +| SET_ZVAL_TYPE_INFO dst_addr, Rd(tmp_reg1) +|| } +|.endmacro + +|.macro ZVAL_COPY_VALUE_V, dst_addr, dst_info, src_addr, src_info, tmp_reg1, tmp_reg2 || if (src_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) { || if ((src_info & (MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_LONG) { || if (Z_MODE(src_addr) == IS_REG) { @@ -1066,19 +1083,6 @@ static void* dasm_labels[zend_lb_MAX]; | .endif || } || } -|| if ((src_info & (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE)) && -|| !(src_info & MAY_BE_GUARD) && -|| has_concrete_type(src_info & MAY_BE_ANY)) { -|| if (Z_MODE(dst_addr) == IS_MEM_ZVAL) { -|| if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (src_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD))) { -|| zend_uchar type = concrete_type(src_info); -| SET_ZVAL_TYPE_INFO dst_addr, type -|| } -|| } -|| } else { -| GET_ZVAL_TYPE_INFO Rd(tmp_reg1), src_addr -| SET_ZVAL_TYPE_INFO dst_addr, Rd(tmp_reg1) -|| } |.endmacro |.macro ZVAL_COPY_VALUE_2, dst_addr, dst_info, res_addr, src_addr, src_info, tmp_reg1, tmp_reg2 @@ -11235,8 +11239,61 @@ static int zend_jit_fetch_obj(dasm_State **Dst, const zend_op *opline, const zen | SET_ZVAL_PTR res_addr, FCARG1a | SET_ZVAL_TYPE_INFO res_addr, IS_INDIRECT } else { - if (!zend_jit_zval_copy_deref(Dst, res_addr, prop_addr, ZREG_R2)) { - return 0; + uint32_t res_info = RES_INFO(); + + if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info) { + uint32_t flags = 0; + uint32_t old_info; + zend_jit_trace_stack *stack = JIT_G(current_frame)->stack; + int32_t exit_point; + const void *exit_addr; + zend_uchar type; + zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_R0, 0); + + if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !use_this) { + flags = ZEND_JIT_EXIT_FREE_OP1; + } + + | LOAD_ZVAL_ADDR r0, prop_addr + + old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var)); + SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN); + SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_ZVAL_COPY_R0); + exit_point = zend_jit_trace_get_exit_point(opline, opline+1, NULL, flags); + SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info); + exit_addr = zend_jit_trace_get_exit_addr(exit_point); + if (!exit_addr) { + return 0; + } + + res_info &= ~MAY_BE_GUARD; + ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD; + type = concrete_type(res_info); + + | // ZVAL_DEREF() + | IF_NOT_TYPE dl, IS_REFERENCE, >1 + | GET_Z_PTR r0, r0 + | add r0, offsetof(zend_reference, val) + if (type < IS_STRING) { + |1: + | IF_NOT_ZVAL_TYPE val_addr, type, &exit_addr + } else { + | GET_ZVAL_TYPE_INFO edx, val_addr + |1: + | IF_NOT_TYPE dl, type, &exit_addr + } + | // ZVAL_COPY + | ZVAL_COPY_VALUE_V res_addr, -1, val_addr, res_info, ZREG_R2, ZREG_R1 + if (type < IS_STRING) { + | SET_ZVAL_TYPE_INFO res_addr, type + } else { + | SET_ZVAL_TYPE_INFO res_addr, edx + | TRY_ADDREF res_info, dh, r1 + } + } else { + if (!zend_jit_zval_copy_deref(Dst, res_addr, prop_addr, ZREG_R2)) { + return 0; + } } }