diff options
Diffstat (limited to 'Zend/zend_execute.c')
-rw-r--r-- | Zend/zend_execute.c | 131 |
1 files changed, 71 insertions, 60 deletions
diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 54841e26b5..50af005c22 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1939,6 +1939,31 @@ static zend_always_inline void zend_fetch_property_address(zval *result, zval *c } } +static inline zend_brk_cont_element* zend_brk_cont(int nest_levels, int array_offset, const zend_op_array *op_array, const zend_execute_data *execute_data) +{ + zend_brk_cont_element *jmp_to; + + do { + ZEND_ASSERT(array_offset != -1); + jmp_to = &op_array->brk_cont_array[array_offset]; + if (nest_levels > 1 && jmp_to->start >= 0) { + zend_op *brk_opline = &op_array->opcodes[jmp_to->brk]; + + if (brk_opline->opcode == ZEND_FREE) { + zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var)); + } else if (brk_opline->opcode == ZEND_FE_FREE) { + zval *var = EX_VAR(brk_opline->op1.var); + 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); + } + } + array_offset = jmp_to->parent; + } while (--nest_levels > 0); + return jmp_to; +} + #if ZEND_INTENSIVE_DEBUGGING #define CHECK_SYMBOL_TABLES() \ @@ -2359,66 +2384,7 @@ static zend_always_inline zend_generator *zend_get_running_generator(zend_execut static zend_always_inline void i_cleanup_unfinished_execution(zend_execute_data *execute_data, uint32_t op_num, uint32_t catch_op_num) /* {{{ */ { - if (EX(func)->op_array.T_liveliness - && op_num < EX(func)->op_array.last - && EX(func)->op_array.T_liveliness[op_num] != (uint32_t)-1) { - uint32_t *off = EX(func)->op_array.T_liveliness + EX(func)->op_array.T_liveliness[op_num]; - uint32_t *catch_off = NULL; - uint32_t var = *off; - - if (catch_op_num && EX(func)->op_array.T_liveliness[catch_op_num] != (uint32_t)-1) { - catch_off = EX(func)->op_array.T_liveliness + EX(func)->op_array.T_liveliness[catch_op_num]; - } - - do { - /* we should be safe to assume that all temporaries at catch_op_num will be present at op_num too, in same order */ - if (catch_off && *catch_off == var) { - catch_off++; - var = *(++off); - continue; - } - - if ((var & ZEND_LIVE_MASK) == ZEND_LIVE_ROPE) { - /* free incomplete rope */ - zend_string **rope; - zend_op *last; - - var = var & ~ZEND_LIVE_ROPE; - rope = (zend_string **) EX_VAR(var); - last = EX(func)->op_array.opcodes + op_num; - while ((last->opcode != ZEND_ROPE_ADD && last->opcode != ZEND_ROPE_INIT) - || last->result.var != var) { - ZEND_ASSERT(last >= EX(func)->op_array.opcodes); - last--; - } - if (last->opcode == ZEND_ROPE_INIT) { - zend_string_release(*rope); - } else { - int j = last->extended_value; - do { - zend_string_release(rope[j]); - } while (j--); - } - } else if ((var & ZEND_LIVE_MASK) == ZEND_LIVE_SILENCE) { - /* restore previous error_reporting value */ - var = var & ~ZEND_LIVE_SILENCE; - if (!EG(error_reporting) && Z_LVAL_P(EX_VAR(var)) != 0) { - EG(error_reporting) = Z_LVAL_P(EX_VAR(var)); - } - } else if ((var & ZEND_LIVE_MASK) == ZEND_LIVE_LOOP) { - /* free loop variables */ - var = var & ~ZEND_LIVE_LOOP; - if (Z_TYPE_P(EX_VAR(var)) != IS_ARRAY && Z_FE_ITER_P(EX_VAR(var)) != (uint32_t) -1) { - zend_hash_iterator_del(Z_FE_ITER_P(EX_VAR(var))); - } - zval_ptr_dtor_nogc(EX_VAR(var)); - } else { - zval_ptr_dtor_nogc(EX_VAR(var)); - } - var = *(++off); - } while (var != (uint32_t)-1); - } - + int i; if (UNEXPECTED(EX(call))) { zend_execute_data *call = EX(call); zend_op *opline = EX(func)->op_array.opcodes + op_num; @@ -2532,6 +2498,51 @@ static zend_always_inline void i_cleanup_unfinished_execution(zend_execute_data call = EX(call); } while (call); } + + for (i = 0; i < EX(func)->op_array.last_brk_cont; i++) { + const zend_brk_cont_element *brk_cont = &EX(func)->op_array.brk_cont_array[i]; + if (brk_cont->start < 0) { + continue; + } else if (brk_cont->start > op_num) { + /* further blocks will not be relevant... */ + break; + } else if (op_num < brk_cont->brk) { + if (!catch_op_num || catch_op_num >= brk_cont->brk) { + zend_op *brk_opline = &EX(func)->op_array.opcodes[brk_cont->brk]; + + if (brk_opline->opcode == ZEND_FREE) { + zval_ptr_dtor_nogc(EX_VAR(brk_opline->op1.var)); + } else if (brk_opline->opcode == ZEND_FE_FREE) { + zval *var = EX_VAR(brk_opline->op1.var); + 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 (brk_opline->opcode == ZEND_ROPE_END) { + zend_string **rope = (zend_string **) EX_VAR(brk_opline->op1.var); + zend_op *last = EX(func)->op_array.opcodes + op_num; + while ((last->opcode != ZEND_ROPE_ADD && last->opcode != ZEND_ROPE_INIT) + || last->result.var != brk_opline->op1.var) { + ZEND_ASSERT(last >= EX(func)->op_array.opcodes); + last--; + } + if (last->opcode == ZEND_ROPE_INIT) { + zend_string_release(*rope); + } else { + int j = last->extended_value; + do { + zend_string_release(rope[j]); + } while (j--); + } + } else if (brk_opline->opcode == ZEND_END_SILENCE) { + /* restore previous error_reporting value */ + if (!EG(error_reporting) && Z_LVAL_P(EX_VAR(brk_opline->op1.var)) != 0) { + EG(error_reporting) = Z_LVAL_P(EX_VAR(brk_opline->op1.var)); + } + } + } + } + } } /* }}} */ |