]> granicus.if.org Git - php/commitdiff
Squashed commit of the following:
authorDmitry Stogov <dmitry@zend.com>
Fri, 13 Nov 2015 12:35:07 +0000 (15:35 +0300)
committerDmitry Stogov <dmitry@zend.com>
Fri, 13 Nov 2015 12:35:07 +0000 (15:35 +0300)
commit afe963e6cc289696e60c6c679796ba2197c52b3b
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Fri Nov 13 15:32:29 2015 +0300

    Added news entry

commit a126b891c97848dd7ef8f1abf716328c46e0f19c
Author: Dmitry Stogov <dmitry@zend.com>
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 <dmitry@zend.com>
Date:   Thu Nov 12 22:55:39 2015 +0300

    Fixed copy/paste

commit 0ac73fe7174bec9de9a610319a98b259bea67f7f
Author: Dmitry Stogov <dmitry@zend.com>
Date:   Wed Nov 11 16:11:50 2015 +0300

    Fixed bug #62210 (Exceptions can leak temporary variables)

15 files changed:
NEWS
Zend/tests/temporary_cleaning_001.phpt
Zend/tests/temporary_cleaning_003.phpt
Zend/tests/temporary_cleaning_004.phpt
Zend/tests/temporary_cleaning_005.phpt
Zend/tests/temporary_cleaning_006.phpt
Zend/tests/temporary_cleaning_011.phpt [new file with mode: 0644]
Zend/zend_compile.c
Zend/zend_compile.h
Zend/zend_execute.c
Zend/zend_opcode.c
Zend/zend_vm_def.h
Zend/zend_vm_execute.h
ext/opcache/Optimizer/optimize_temp_vars_5.c
ext/opcache/Optimizer/zend_optimizer.c

diff --git a/NEWS b/NEWS
index 8c459625bfbac56a16e2ab13a0f5ab77b9c01873..1d9fd2a100798428f3b3b567880beec4f27c9e80 100644 (file)
--- 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)
index 40340bc3dafd3366f7326de2883c3a1b0e24e12d..f2ccbb35b8f1dab5d3d8cf0ec9dcec6cfc19ed8c 100644 (file)
@@ -1,7 +1,5 @@
 --TEST--
 Temporary leak on exception
---XFAIL--
-See Bug #62210 and attempt to fix it in "tmp_livelibess" branch
 --FILE--
 <?php
 
index 0f7d9450eb6b9f9c93920c8962501405db149499..acff8c85f0c445572eac07f8342ec8ed5d58085f 100644 (file)
@@ -1,7 +1,5 @@
 --TEST--
 Fundamental memory leak test on temporaries
---XFAIL--
-See Bug #62210 and attempt to fix it in "tmp_livelibess" branch
 --FILE--
 <?php
 
index e2b093654f4b1d68cf1d13bf514a107f019796b3..b8a02516b0efc186227db7e9ef78a2054c5ca64a 100644 (file)
@@ -1,7 +1,5 @@
 --TEST--
 Temporary leak with switch
---XFAIL--
-See Bug #62210 and attempt to fix it in "tmp_livelibess" branch
 --FILE--
 <?php
 
index f671c325439118456bef5718468b476c2e1bd93e..e8c7febe0b12ddc4c5cbfe606aed6056ab2c928d 100644 (file)
@@ -1,7 +1,5 @@
 --TEST--
 Temporary leak with foreach
---XFAIL--
-See Bug #62210 and attempt to fix it in "tmp_livelibess" branch
 --FILE--
 <?php
 
index 435e7b12dd082287071e679a9b0329f24241ab85..a7936d3915edb6ea740755663979f3b501b9e1c7 100644 (file)
@@ -1,7 +1,5 @@
 --TEST--
 Exception after separation during indirect write to fcall result
---XFAIL--
-See Bug #62210 and attempt to fix it in "tmp_livelibess" branch
 --FILE--
 <?php
 
diff --git a/Zend/tests/temporary_cleaning_011.phpt b/Zend/tests/temporary_cleaning_011.phpt
new file mode 100644 (file)
index 0000000..e4a6af3
--- /dev/null
@@ -0,0 +1,20 @@
+--TEST--
+Live range & lists
+--FILE--
+<?php
+class A {
+       function __destruct() {
+               throw new Exception();
+       }
+}
+$b = new A();
+$x = 0;
+$c = [[$x,$x]]; 
+try {
+       list($a, $b) = $c[0];
+} catch (Exception $e) {
+       echo "exception\n";
+}
+?>
+--EXPECT--
+exception
index c2bc756c849edbe2156dae7124f6f2d4057b29c8..e2398b7f6208ac9fc8d04d071b04d513f6eec80c 100644 (file)
@@ -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) {
index 6e37aa5bb336450da50d9906e3cad5e2dfcb9696..ff74ec26e5b45f4ffbcf72ba407469248f634b54 100644 (file)
@@ -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;
index c0c9271f4b879e82b0ebc3eafb1065f9ca3c03db..aa48b06767e230e614fc92d7ffbf590662281910 100644 (file)
@@ -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);
index 73f3744341402182a9c1f4eb01382199b5c66dca..86fe4020a71a006ee885d850c3e7eb66cb9bb175 100644 (file)
@@ -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;
 }
index f8f0fd9c0fcc11261a725d8ff5bb0c743fcb5119..093f9f851e2d3f8878bf8c66206309c08f28dd9c 100644 (file)
@@ -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
index c4aee3fa3e9c1a7e92ed970bb2f426a4ee1a6c93..a2e63a1a8dddbf9d4f73f48f6c840db9905ba1f6 100644 (file)
@@ -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
index 172f9a1a62c6fa08bbc70731d218146614bf0ac7..586471017c5e8e20ce49b98f1f63e4c087468a42 100644 (file)
@@ -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;
 }
index 70b240fdf15e1ea952bd498f9f3db40a2683fc8e..9fb7493054ae3b2a4132ffba09b00976064bdeb4 100644 (file)
@@ -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];