From: Dmitry Stogov Date: Fri, 13 Nov 2015 12:35:07 +0000 (+0300) Subject: Squashed commit of the following: X-Git-Tag: php-7.1.0alpha1~619^2~1 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3a5fa926bfc409963f500144ea6d5e890e712a86;p=php Squashed commit of the following: commit afe963e6cc289696e60c6c679796ba2197c52b3b Author: Dmitry Stogov Date: Fri Nov 13 15:32:29 2015 +0300 Added news entry commit a126b891c97848dd7ef8f1abf716328c46e0f19c Author: Dmitry Stogov Date: Fri Nov 13 15:29:21 2015 +0300 VERIFY_RETURN_TYPE doesn't have to cleanup operand on exception, bacause now, live temporary variables are released by exception unwinder. commit 0db475e98786e6bcaa8401ee3e0b33743b9a2f2b Author: Dmitry Stogov Date: Thu Nov 12 22:55:39 2015 +0300 Fixed copy/paste commit 0ac73fe7174bec9de9a610319a98b259bea67f7f Author: Dmitry Stogov Date: Wed Nov 11 16:11:50 2015 +0300 Fixed bug #62210 (Exceptions can leak temporary variables) --- diff --git a/NEWS b/NEWS index 8c459625bf..1d9fd2a100 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? 2016, PHP 7.1.0 +Core: + . Fixed bug #62210 (Exceptions can leak temporary variables). (Dmitry, Bob) + Standard . Implemented FR #55716 (Add an option to pass a custom stream context to get_headers()). (Ferenc) diff --git a/Zend/tests/temporary_cleaning_001.phpt b/Zend/tests/temporary_cleaning_001.phpt index 40340bc3da..f2ccbb35b8 100644 --- a/Zend/tests/temporary_cleaning_001.phpt +++ b/Zend/tests/temporary_cleaning_001.phpt @@ -1,7 +1,5 @@ --TEST-- Temporary leak on exception ---XFAIL-- -See Bug #62210 and attempt to fix it in "tmp_livelibess" branch --FILE-- +--EXPECT-- +exception diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index c2bc756c84..e2398b7f62 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -86,6 +86,8 @@ ZEND_API zend_compiler_globals compiler_globals; ZEND_API zend_executor_globals executor_globals; #endif +static zend_op *zend_emit_op(znode *result, zend_uchar opcode, znode *op1, znode *op2); + static void zend_destroy_property_info_internal(zval *zv) /* {{{ */ { zend_property_info *property_info = Z_PTR_P(zv); @@ -588,7 +590,7 @@ static uint32_t zend_start_live_range(zend_op_array *op_array, uint32_t start) / } /* }}} */ -static void zend_end_live_range(zend_op_array *op_array, uint32_t offset, uint32_t end) /* {{{ */ +static void zend_end_live_range(zend_op_array *op_array, uint32_t offset, uint32_t end, uint32_t kind, uint32_t var) /* {{{ */ { zend_live_range *range = op_array->live_range + offset; @@ -596,6 +598,7 @@ static void zend_end_live_range(zend_op_array *op_array, uint32_t offset, uint32 op_array->last_live_range--; } else { range->end = end; + range->var = (var * sizeof(zval)) | kind; } } /* }}} */ @@ -629,7 +632,7 @@ static inline void zend_begin_loop(zend_uchar free_opcode, const znode *loop_var } /* }}} */ -static inline void zend_end_loop(int cont_addr) /* {{{ */ +static inline void zend_end_loop(int cont_addr, const znode *var_node) /* {{{ */ { uint32_t end = get_next_op_number(CG(active_op_array)); zend_brk_cont_element *brk_cont_element @@ -640,7 +643,9 @@ static inline void zend_end_loop(int cont_addr) /* {{{ */ if (brk_cont_element->start != -1) { zend_loop_var *loop_var = zend_stack_top(&CG(loop_var_stack)); - zend_end_live_range(CG(active_op_array), loop_var->u.live_range_offset, end); + zend_end_live_range(CG(active_op_array), loop_var->u.live_range_offset, end, + loop_var->opcode == ZEND_FE_FREE ? ZEND_LIVE_LOOP : ZEND_LIVE_TMPVAR, + var_node->u.op.var); } zend_stack_del_top(&CG(loop_var_stack)); @@ -650,11 +655,7 @@ static inline void zend_end_loop(int cont_addr) /* {{{ */ void zend_do_free(znode *op1) /* {{{ */ { if (op1->op_type==IS_TMP_VAR) { - zend_op *opline = get_next_op(CG(active_op_array)); - - opline->opcode = ZEND_FREE; - SET_NODE(opline->op1, op1); - SET_UNUSED(opline->op2); + zend_emit_op(NULL, ZEND_FREE, op1, NULL); } else if (op1->op_type==IS_VAR) { zend_op *opline = &CG(active_op_array)->opcodes[CG(active_op_array)->last-1]; @@ -670,10 +671,7 @@ void zend_do_free(znode *op1) /* {{{ */ /* It's very rare and useless case. It's better to use additional FREE opcode and simplify the FETCH handlers their selves */ - opline = get_next_op(CG(active_op_array)); - opline->opcode = ZEND_FREE; - SET_NODE(opline->op1, op1); - SET_UNUSED(opline->op2); + zend_emit_op(NULL, ZEND_FREE, op1, NULL); } else { opline->result_type |= EXT_TYPE_UNUSED; } @@ -682,11 +680,7 @@ void zend_do_free(znode *op1) /* {{{ */ if (opline->opcode == ZEND_FETCH_LIST && opline->op1_type == IS_VAR && opline->op1.var == op1->u.op.var) { - opline = get_next_op(CG(active_op_array)); - - opline->opcode = ZEND_FREE; - SET_NODE(opline->op1, op1); - SET_UNUSED(opline->op2); + zend_emit_op(NULL, ZEND_FREE, op1, NULL); return; } if (opline->result_type==IS_VAR @@ -1889,6 +1883,119 @@ static inline void zend_make_tmp_result(znode *result, zend_op *opline) /* {{{ * } /* }}} */ +static void zend_find_live_range(zend_op *opline, zend_uchar type, uint32_t var) /* {{{ */ +{ + zend_op *def = opline; + + while (def != CG(active_op_array)->opcodes) { + def--; + if (def->result_type == type && def->result.var == var) { + if (def->opcode == ZEND_ADD_ARRAY_ELEMENT || + def->opcode == ZEND_ROPE_ADD) { + /* not a real definition */ + continue; + } else if (def->opcode == ZEND_JMPZ_EX || + def->opcode == ZEND_JMPNZ_EX || + def->opcode == ZEND_BOOL || + def->opcode == ZEND_BOOL_NOT) { + /* result IS_BOOL, it does't have to be destroyed */ + break; + } else if (def->opcode == ZEND_DECLARE_CLASS || + def->opcode == ZEND_DECLARE_INHERITED_CLASS || + def->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED || + def->opcode == ZEND_DECLARE_ANON_CLASS || + def->opcode == ZEND_DECLARE_ANON_INHERITED_CLASS) { + /* classes don't have to be destroyed */ + break; + } else if (def->opcode == ZEND_FAST_CALL) { + /* fast_calls don't have to be destroyed */ + break; + } else if (def->opcode == ZEND_NEW) { + /* Objects created via ZEND_NEW are only fully initialized + * after the DO_FCALL (constructor call) */ + def = CG(active_op_array)->opcodes + def->op2.opline_num - 1; + if (def + 1 == opline) { + break; + } + } + zend_end_live_range(CG(active_op_array), + zend_start_live_range(CG(active_op_array), + def + 1 - CG(active_op_array)->opcodes), + opline - CG(active_op_array)->opcodes, + ZEND_LIVE_TMPVAR, def->result.var); + break; + } + } +} +/* }}} */ + +static zend_always_inline int zend_is_def_range(zend_op *opline, zend_uchar type, uint32_t var) /* {{{ */ +{ + return opline->result_type == type && + opline->result.var == var && + opline->opcode != ZEND_ADD_ARRAY_ELEMENT && + opline->opcode != ZEND_ROPE_ADD; +} +/* }}} */ + +static void zend_check_live_ranges(zend_op *opline) /* {{{ */ +{ + if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && + !zend_is_def_range(opline - 1, opline->op1_type, opline->op1.var)) { + + if (opline->opcode == ZEND_OP_DATA) { + if (!zend_is_def_range(opline - 2, opline->op1_type, opline->op1.var)) { + zend_find_live_range(opline - 1, opline->op1_type, opline->op1.var); + } + } else if (opline->opcode == ZEND_INIT_STATIC_METHOD_CALL || + opline->opcode == ZEND_NEW || + opline->opcode == ZEND_FETCH_CLASS_CONSTANT || + opline->opcode == ZEND_ADD_INTERFACE || + opline->opcode == ZEND_ADD_TRAIT || + opline->opcode == ZEND_BIND_TRAITS || + opline->opcode == ZEND_VERIFY_ABSTRACT_CLASS) { + /* classes don't have to be destroyed */ + } else if (opline->opcode == ZEND_FAST_RET) { + /* fast_calls don't have to be destroyed */ + } else if (opline->opcode == ZEND_CASE || + opline->opcode == ZEND_FE_FETCH_R || + opline->opcode == ZEND_FE_FETCH_RW || + opline->opcode == ZEND_FE_FREE || + opline->opcode == ZEND_ROPE_ADD || + opline->opcode == ZEND_ROPE_END || + opline->opcode == ZEND_END_SILENCE || + opline->opcode == ZEND_FETCH_LIST || + opline->opcode == ZEND_VERIFY_RETURN_TYPE) { + /* these opcodes are handled separately */ + } else { + zend_find_live_range(opline, opline->op1_type, opline->op1.var); + } + } + + if ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) && + !zend_is_def_range(opline - 1, opline->op2_type, opline->op2.var)) { + + if (opline->opcode == ZEND_OP_DATA) { + if (!zend_is_def_range(opline - 2, opline->op2_type, opline->op2.var)) { + zend_find_live_range(opline-1, opline->op2_type, opline->op2.var); + } + } else if (opline->opcode == ZEND_FETCH_STATIC_PROP_R || + opline->opcode == ZEND_FETCH_STATIC_PROP_W || + opline->opcode == ZEND_FETCH_STATIC_PROP_RW || + opline->opcode == ZEND_FETCH_STATIC_PROP_IS || + opline->opcode == ZEND_FETCH_STATIC_PROP_FUNC_ARG || + opline->opcode == ZEND_FETCH_STATIC_PROP_UNSET || + opline->opcode == ZEND_UNSET_STATIC_PROP || + opline->opcode == ZEND_ISSET_ISEMPTY_STATIC_PROP || + opline->opcode == ZEND_INSTANCEOF) { + /* classes don't have to be destroyed */ + } else { + zend_find_live_range(opline, opline->op2_type, opline->op2.var); + } + } +} +/* }}} */ + static zend_op *zend_emit_op(znode *result, zend_uchar opcode, znode *op1, znode *op2) /* {{{ */ { zend_op *opline = get_next_op(CG(active_op_array)); @@ -1906,6 +2013,8 @@ static zend_op *zend_emit_op(znode *result, zend_uchar opcode, znode *op1, znode SET_NODE(opline->op2, op2); } + zend_check_live_ranges(opline); + if (result) { zend_make_var_result(result, opline); } @@ -1930,6 +2039,8 @@ static zend_op *zend_emit_op_tmp(znode *result, zend_uchar opcode, znode *op1, z SET_NODE(opline->op2, op2); } + zend_check_live_ranges(opline); + if (result) { zend_make_tmp_result(result, opline); } @@ -2044,6 +2155,7 @@ static zend_op *zend_delayed_compile_end(uint32_t offset) /* {{{ */ for (i = offset; i < count; ++i) { opline = get_next_op(CG(active_op_array)); memcpy(opline, &oplines[i], sizeof(zend_op)); + zend_check_live_ranges(opline); } CG(delayed_oplines_stack).top = offset; return opline; @@ -2838,10 +2950,7 @@ uint32_t zend_compile_args(zend_ast *ast, zend_function *fbc) /* {{{ */ } } - opline = get_next_op(CG(active_op_array)); - opline->opcode = opcode; - SET_NODE(opline->op1, &arg_node); - SET_UNUSED(opline->op2); + opline = zend_emit_op(NULL, opcode, &arg_node, NULL); opline->op2.opline_num = arg_num; opline->result.var = (uint32_t)(zend_intptr_t)ZEND_CALL_ARG(NULL, arg_num); @@ -2944,13 +3053,14 @@ void zend_compile_ns_call(znode *result, znode *name_node, zend_ast *args_ast) / void zend_compile_dynamic_call(znode *result, znode *name_node, zend_ast *args_ast) /* {{{ */ { - zend_op *opline = get_next_op(CG(active_op_array)); if (name_node->op_type == IS_CONST && Z_TYPE(name_node->u.constant) == IS_STRING) { const char *colon; zend_string *str = Z_STR(name_node->u.constant); if ((colon = zend_memrchr(ZSTR_VAL(str), ':', ZSTR_LEN(str))) != NULL && colon > ZSTR_VAL(str) && *(colon - 1) == ':') { zend_string *class = zend_string_init(ZSTR_VAL(str), colon - ZSTR_VAL(str) - 1, 0); zend_string *method = zend_string_init(colon + 1, ZSTR_LEN(str) - (colon - ZSTR_VAL(str)) - 1, 0); + zend_op *opline = get_next_op(CG(active_op_array)); + opline->opcode = ZEND_INIT_STATIC_METHOD_CALL; opline->op1_type = IS_CONST; opline->op1.constant = zend_add_class_name_literal(CG(active_op_array), class); @@ -2959,6 +3069,8 @@ void zend_compile_dynamic_call(znode *result, znode *name_node, zend_ast *args_a zend_alloc_cache_slot(opline->op2.constant); zval_ptr_dtor(&name_node->u.constant); } else { + zend_op *opline = get_next_op(CG(active_op_array)); + opline->opcode = ZEND_INIT_FCALL_BY_NAME; SET_UNUSED(opline->op1); opline->op2_type = IS_CONST; @@ -2966,9 +3078,7 @@ void zend_compile_dynamic_call(znode *result, znode *name_node, zend_ast *args_a zend_alloc_cache_slot(opline->op2.constant); } } else { - opline->opcode = ZEND_INIT_DYNAMIC_CALL; - SET_UNUSED(opline->op1); - SET_NODE(opline->op2, name_node); + zend_emit_op(NULL, ZEND_INIT_DYNAMIC_CALL, NULL, name_node); } zend_compile_call_common(result, args_ast, NULL); @@ -3419,6 +3529,7 @@ void zend_compile_static_call(znode *result, zend_ast *ast, uint32_t type) /* {{ } else { SET_NODE(opline->op2, &method_node); } + zend_check_live_ranges(opline); zend_compile_call_common(result, args_ast, NULL); } @@ -3871,7 +3982,7 @@ void zend_compile_while(zend_ast *ast) /* {{{ */ zend_emit_cond_jump(ZEND_JMPNZ, &cond_node, opnum_start); - zend_end_loop(opnum_cond); + zend_end_loop(opnum_cond, NULL); } /* }}} */ @@ -3893,7 +4004,7 @@ void zend_compile_do_while(zend_ast *ast) /* {{{ */ zend_emit_cond_jump(ZEND_JMPNZ, &cond_node, opnum_start); - zend_end_loop(opnum_cond); + zend_end_loop(opnum_cond, NULL); } /* }}} */ @@ -3949,7 +4060,7 @@ void zend_compile_for(zend_ast *ast) /* {{{ */ zend_emit_cond_jump(ZEND_JMPNZ, &result, opnum_start); - zend_end_loop(opnum_loop); + zend_end_loop(opnum_loop, NULL); } /* }}} */ @@ -4028,7 +4139,7 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */ opline = &CG(active_op_array)->opcodes[opnum_fetch]; opline->extended_value = get_next_op_number(CG(active_op_array)); - zend_end_loop(opnum_fetch); + zend_end_loop(opnum_fetch, &reset_node); opline = zend_emit_op(NULL, ZEND_FE_FREE, &reset_node, NULL); } @@ -4150,10 +4261,14 @@ void zend_compile_switch(zend_ast *ast) /* {{{ */ zend_update_jump_target_to_next(opnum_default_jmp); } - zend_end_loop(get_next_op_number(CG(active_op_array))); + zend_end_loop(get_next_op_number(CG(active_op_array)), &expr_node); if (expr_node.op_type == IS_VAR || expr_node.op_type == IS_TMP_VAR) { - opline = zend_emit_op(NULL, ZEND_FREE, &expr_node, NULL); + /* don't use emit_op() to prevent automatic live-range construction */ + opline = get_next_op(CG(active_op_array)); + opline->opcode = ZEND_FREE; + SET_NODE(opline->op1, &expr_node); + SET_UNUSED(opline->op2); } else if (expr_node.op_type == IS_CONST) { zval_dtor(&expr_node.u.constant); } @@ -6482,7 +6597,8 @@ void zend_compile_silence(znode *result, zend_ast *ast) /* {{{ */ /* Store BEGIN_SILENCE/END_SILENCE pair to restore previous * EG(error_reporting) value on exception */ - zend_end_live_range(CG(active_op_array), range, get_next_op_number(CG(active_op_array))); + zend_end_live_range(CG(active_op_array), range, get_next_op_number(CG(active_op_array)), + ZEND_LIVE_SILENCE, silence_node.u.op.var); zend_emit_op(NULL, ZEND_END_SILENCE, &silence_node, NULL); } @@ -6819,7 +6935,8 @@ static void zend_compile_encaps_list(znode *result, zend_ast *ast) /* {{{ */ i--; } - zend_end_live_range(CG(active_op_array), range, opline - CG(active_op_array)->opcodes); + zend_end_live_range(CG(active_op_array), range, opline - CG(active_op_array)->opcodes, + ZEND_LIVE_ROPE, var); /* Update all the previous opcodes to use the same variable */ while (opline != init_opline) { diff --git a/Zend/zend_compile.h b/Zend/zend_compile.h index 6e37aa5bb3..ff74ec26e5 100644 --- a/Zend/zend_compile.h +++ b/Zend/zend_compile.h @@ -173,7 +173,14 @@ typedef struct _zend_try_catch_element { uint32_t finally_end; } zend_try_catch_element; +#define ZEND_LIVE_TMPVAR 0 +#define ZEND_LIVE_LOOP 1 +#define ZEND_LIVE_SILENCE 2 +#define ZEND_LIVE_ROPE 3 +#define ZEND_LIVE_MASK 3 + typedef struct _zend_live_range { + uint32_t var; /* low bits are used for variable type (ZEND_LIVE_* macros) */ uint32_t start; uint32_t end; } zend_live_range; diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index c0c9271f4b..aa48b06767 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2556,18 +2556,18 @@ static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num, break; } else if (op_num < range->end) { if (!catch_op_num || catch_op_num >= range->end) { - zend_op *opline = &EX(func)->op_array.opcodes[range->end]; - uint32_t var_num = opline->op1.var; + uint32_t kind = range->var & ZEND_LIVE_MASK; + uint32_t var_num = range->var & ~ZEND_LIVE_MASK; zval *var = EX_VAR(var_num); - if (opline->opcode == ZEND_FREE) { + if (kind == ZEND_LIVE_TMPVAR) { zval_ptr_dtor_nogc(var); - } else if (opline->opcode == ZEND_FE_FREE) { + } else if (kind == ZEND_LIVE_LOOP) { if (Z_TYPE_P(var) != IS_ARRAY && Z_FE_ITER_P(var) != (uint32_t)-1) { zend_hash_iterator_del(Z_FE_ITER_P(var)); } zval_ptr_dtor_nogc(var); - } else if (opline->opcode == ZEND_ROPE_END) { + } else if (kind == ZEND_LIVE_ROPE) { zend_string **rope = (zend_string **)var; zend_op *last = EX(func)->op_array.opcodes + op_num; while ((last->opcode != ZEND_ROPE_ADD && last->opcode != ZEND_ROPE_INIT) @@ -2583,7 +2583,7 @@ static void cleanup_live_vars(zend_execute_data *execute_data, uint32_t op_num, zend_string_release(rope[j]); } while (j--); } - } else if (opline->opcode == ZEND_END_SILENCE) { + } else if (kind == ZEND_LIVE_SILENCE) { /* restore previous error_reporting value */ if (!EG(error_reporting) && Z_LVAL_P(var) != 0) { EG(error_reporting) = Z_LVAL_P(var); diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 73f3744341..86fe4020a7 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -707,6 +707,16 @@ ZEND_API int pass_two(zend_op_array *op_array) opline++; } + if (op_array->live_range) { + uint32_t i; + + for (i = 0; i < op_array->last_live_range; i++) { + op_array->live_range[i].var = + (uint32_t)(zend_intptr_t)ZEND_CALL_VAR_NUM(NULL, op_array->last_var + (op_array->live_range[i].var / sizeof(zval))) | + (op_array->live_range[i].var & ZEND_LIVE_MASK); + } + } + op_array->fn_flags |= ZEND_ACC_DONE_PASS_TWO; return 0; } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index f8f0fd9c0f..093f9f851e 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -3999,8 +3999,6 @@ ZEND_VM_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV, UNUSED) if (UNEXPECTED(EG(exception) != NULL)) { if (OP1_TYPE == IS_CONST) { zval_ptr_dtor_nogc(retval_ptr); - } else { - FREE_OP1(); } } #endif diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index c4aee3fa3e..a2e63a1a8d 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -7590,8 +7590,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CONST_ if (UNEXPECTED(EG(exception) != NULL)) { if (IS_CONST == IS_CONST) { zval_ptr_dtor_nogc(retval_ptr); - } else { - } } #endif @@ -13443,8 +13441,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_TMP_UN if (UNEXPECTED(EG(exception) != NULL)) { if (IS_TMP_VAR == IS_CONST) { zval_ptr_dtor_nogc(retval_ptr); - } else { - zval_ptr_dtor_nogc(free_op1); } } #endif @@ -19125,8 +19121,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_VAR_UN if (UNEXPECTED(EG(exception) != NULL)) { if (IS_VAR == IS_CONST) { zval_ptr_dtor_nogc(retval_ptr); - } else { - zval_ptr_dtor_nogc(free_op1); } } #endif @@ -25227,8 +25221,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_UNUSED if (UNEXPECTED(EG(exception) != NULL)) { if (IS_UNUSED == IS_CONST) { zval_ptr_dtor_nogc(retval_ptr); - } else { - } } #endif @@ -34859,8 +34851,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CV_UNU if (UNEXPECTED(EG(exception) != NULL)) { if (IS_CV == IS_CONST) { zval_ptr_dtor_nogc(retval_ptr); - } else { - } } #endif diff --git a/ext/opcache/Optimizer/optimize_temp_vars_5.c b/ext/opcache/Optimizer/optimize_temp_vars_5.c index 172f9a1a62..586471017c 100644 --- a/ext/opcache/Optimizer/optimize_temp_vars_5.c +++ b/ext/opcache/Optimizer/optimize_temp_vars_5.c @@ -224,6 +224,14 @@ void optimize_temporary_variables(zend_op_array *op_array, zend_optimizer_ctx *c opline--; } + if (op_array->live_range) { + for (i = 0; i < op_array->last_live_range; i++) { + op_array->live_range[i].var = + NUM_VAR(map_T[VAR_NUM(op_array->live_range[i].var & ~ZEND_LIVE_MASK) - offset] + offset) | + (op_array->live_range[i].var & ZEND_LIVE_MASK); + } + } + zend_arena_release(&ctx->arena, checkpoint); op_array->T = max + 1; } diff --git a/ext/opcache/Optimizer/zend_optimizer.c b/ext/opcache/Optimizer/zend_optimizer.c index 70b240fdf1..9fb7493054 100644 --- a/ext/opcache/Optimizer/zend_optimizer.c +++ b/ext/opcache/Optimizer/zend_optimizer.c @@ -358,7 +358,7 @@ void zend_optimizer_remove_live_range(zend_op_array *op_array, uint32_t var) map = (uint32_t *)do_alloca(sizeof(uint32_t) * op_array->last_live_range, use_heap); do { - if (op_array->opcodes[op_array->live_range[i].end].op1.var != var) { + if ((op_array->live_range[i].var & ~ZEND_LIVE_MASK) != var) { map[i] = j; if (i != j) { op_array->live_range[j] = op_array->live_range[i];