summaryrefslogtreecommitdiff
path: root/Zend/zend_execute.c
diff options
context:
space:
mode:
Diffstat (limited to 'Zend/zend_execute.c')
-rw-r--r--Zend/zend_execute.c131
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));
+ }
+ }
+ }
+ }
+ }
}
/* }}} */