From 00e516e57549f29387ef858de7847e7e4ca0c1c0 Mon Sep 17 00:00:00 2001 From: Bob Weinand Date: Mon, 28 Nov 2016 23:16:24 +0100 Subject: [PATCH] Fix memory leaks with FE_RESET upon empty iterator Solved by manually freeing and jumping to the opcode *after* FE_FREE --- Zend/tests/foreach_empty_loop_leak.phpt | 23 ++++ Zend/zend_compile.c | 8 +- Zend/zend_vm_def.h | 34 +++--- Zend/zend_vm_execute.h | 136 +++++++++--------------- ext/opcache/Optimizer/block_pass.c | 6 +- ext/opcache/Optimizer/zend_cfg.c | 4 +- 6 files changed, 98 insertions(+), 113 deletions(-) create mode 100644 Zend/tests/foreach_empty_loop_leak.phpt diff --git a/Zend/tests/foreach_empty_loop_leak.phpt b/Zend/tests/foreach_empty_loop_leak.phpt new file mode 100644 index 0000000000..70b391181b --- /dev/null +++ b/Zend/tests/foreach_empty_loop_leak.phpt @@ -0,0 +1,23 @@ +--TEST-- +Empty foreach loops with exception must not leak +--FILE-- + +--EXPECT-- +Exception caught diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 3fe46292f2..ff64164bf7 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -4525,15 +4525,15 @@ void zend_compile_foreach(zend_ast *ast) /* {{{ */ zend_emit_jump(opnum_fetch); - opline = &CG(active_op_array)->opcodes[opnum_reset]; - opline->op2.opline_num = get_next_op_number(CG(active_op_array)); - opline = &CG(active_op_array)->opcodes[opnum_fetch]; opline->extended_value = get_next_op_number(CG(active_op_array)); zend_end_loop(opnum_fetch, &reset_node); - opline = zend_emit_op(NULL, ZEND_FE_FREE, &reset_node, NULL); + zend_emit_op(NULL, ZEND_FE_FREE, &reset_node, NULL); + + opline = &CG(active_op_array)->opcodes[opnum_reset]; + opline->op2.opline_num = get_next_op_number(CG(active_op_array)); } /* }}} */ diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index f08342d4f1..f56095b089 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -5744,7 +5744,7 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET_R, CONST|TMP|VAR|CV, JMP_ADDR) while (1) { if (UNEXPECTED(pos >= fe_ht->nNumUsed)) { FREE_OP1_IF_VAR(); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; + zval_ptr_dtor_nogc(EX_VAR(opline->result.var)); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && @@ -5790,27 +5790,20 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET_R, CONST|TMP|VAR|CV, JMP_ADDR) is_empty = iter->funcs->valid(iter) != SUCCESS; - if (UNEXPECTED(EG(exception) != NULL)) { - OBJ_RELEASE(&iter->std); - FREE_OP1(); - HANDLE_EXCEPTION(); - } - iter->index = -1; /* will be set to 0 before using next handler */ - - ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; - FREE_OP1(); if (is_empty) { + OBJ_RELEASE(&iter->std); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } else { + iter->index = -1; /* will be set to 0 before using next handler */ + + ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std); + Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } } } else { zend_error(E_WARNING, "Invalid argument supplied for foreach()"); - ZVAL_UNDEF(EX_VAR(opline->result.var)); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; FREE_OP1(); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } @@ -5859,7 +5852,7 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, JMP_ADDR) while (1) { if (UNEXPECTED(pos >= fe_ht->nNumUsed)) { FREE_OP1_VAR_PTR(); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; + zval_ptr_dtor_nogc(EX_VAR(opline->result.var)); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && @@ -5899,7 +5892,7 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, JMP_ADDR) while (1) { if (UNEXPECTED(pos >= fe_ht->nNumUsed)) { FREE_OP1_VAR_PTR(); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; + zval_ptr_dtor_nogc(EX_VAR(opline->result.var)); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && @@ -5959,10 +5952,6 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, JMP_ADDR) } HANDLE_EXCEPTION(); } - iter->index = -1; /* will be set to 0 before using next handler */ - - ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; if (OP1_TYPE == IS_VAR) { FREE_OP1_VAR_PTR(); @@ -5970,15 +5959,18 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, JMP_ADDR) FREE_OP1(); } if (is_empty) { + zval_ptr_dtor_nogc(&iter->std); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } else { + iter->index = -1; /* will be set to 0 before using next handler */ + + ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std); + Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } } } else { zend_error(E_WARNING, "Invalid argument supplied for foreach()"); - ZVAL_UNDEF(EX_VAR(opline->result.var)); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; if (OP1_TYPE == IS_VAR) { FREE_OP1_VAR_PTR(); } else { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 9a051acf90..1b2ff75922 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -3514,7 +3514,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_R_SPEC_CONST_HANDLER( while (1) { if (UNEXPECTED(pos >= fe_ht->nNumUsed)) { - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; + zval_ptr_dtor_nogc(EX_VAR(opline->result.var)); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && @@ -3559,26 +3559,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_R_SPEC_CONST_HANDLER( is_empty = iter->funcs->valid(iter) != SUCCESS; - if (UNEXPECTED(EG(exception) != NULL)) { - OBJ_RELEASE(&iter->std); - - HANDLE_EXCEPTION(); - } - iter->index = -1; /* will be set to 0 before using next handler */ - - ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; - if (is_empty) { + OBJ_RELEASE(&iter->std); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } else { + iter->index = -1; /* will be set to 0 before using next handler */ + + ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std); + Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } } } else { zend_error(E_WARNING, "Invalid argument supplied for foreach()"); - ZVAL_UNDEF(EX_VAR(opline->result.var)); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } @@ -3627,7 +3620,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_CONST_HANDLER while (1) { if (UNEXPECTED(pos >= fe_ht->nNumUsed)) { - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; + zval_ptr_dtor_nogc(EX_VAR(opline->result.var)); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && @@ -3666,7 +3659,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_CONST_HANDLER while (1) { if (UNEXPECTED(pos >= fe_ht->nNumUsed)) { - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; + zval_ptr_dtor_nogc(EX_VAR(opline->result.var)); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && @@ -3725,10 +3718,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_CONST_HANDLER } HANDLE_EXCEPTION(); } - iter->index = -1; /* will be set to 0 before using next handler */ - - ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; if (IS_CONST == IS_VAR) { @@ -3736,15 +3725,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_CONST_HANDLER } if (is_empty) { + zval_ptr_dtor_nogc(&iter->std); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } else { + iter->index = -1; /* will be set to 0 before using next handler */ + + ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std); + Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } } } else { zend_error(E_WARNING, "Invalid argument supplied for foreach()"); - ZVAL_UNDEF(EX_VAR(opline->result.var)); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; if (IS_CONST == IS_VAR) { } else { @@ -12828,7 +12820,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_R_SPEC_TMP_HANDLER(ZE while (1) { if (UNEXPECTED(pos >= fe_ht->nNumUsed)) { - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; + zval_ptr_dtor_nogc(EX_VAR(opline->result.var)); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && @@ -12873,27 +12865,20 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_R_SPEC_TMP_HANDLER(ZE is_empty = iter->funcs->valid(iter) != SUCCESS; - if (UNEXPECTED(EG(exception) != NULL)) { - OBJ_RELEASE(&iter->std); - zval_ptr_dtor_nogc(free_op1); - HANDLE_EXCEPTION(); - } - iter->index = -1; /* will be set to 0 before using next handler */ - - ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; - zval_ptr_dtor_nogc(free_op1); if (is_empty) { + OBJ_RELEASE(&iter->std); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } else { + iter->index = -1; /* will be set to 0 before using next handler */ + + ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std); + Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } } } else { zend_error(E_WARNING, "Invalid argument supplied for foreach()"); - ZVAL_UNDEF(EX_VAR(opline->result.var)); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; zval_ptr_dtor_nogc(free_op1); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } @@ -12942,7 +12927,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(Z while (1) { if (UNEXPECTED(pos >= fe_ht->nNumUsed)) { - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; + zval_ptr_dtor_nogc(EX_VAR(opline->result.var)); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && @@ -12981,7 +12966,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(Z while (1) { if (UNEXPECTED(pos >= fe_ht->nNumUsed)) { - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; + zval_ptr_dtor_nogc(EX_VAR(opline->result.var)); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && @@ -13040,10 +13025,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(Z } HANDLE_EXCEPTION(); } - iter->index = -1; /* will be set to 0 before using next handler */ - - ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; if (IS_TMP_VAR == IS_VAR) { @@ -13051,15 +13032,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(Z zval_ptr_dtor_nogc(free_op1); } if (is_empty) { + zval_ptr_dtor_nogc(&iter->std); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } else { + iter->index = -1; /* will be set to 0 before using next handler */ + + ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std); + Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } } } else { zend_error(E_WARNING, "Invalid argument supplied for foreach()"); - ZVAL_UNDEF(EX_VAR(opline->result.var)); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; if (IS_TMP_VAR == IS_VAR) { } else { @@ -16387,7 +16371,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_R_SPEC_VAR_HANDLER(ZE while (1) { if (UNEXPECTED(pos >= fe_ht->nNumUsed)) { zval_ptr_dtor_nogc(free_op1); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; + zval_ptr_dtor_nogc(EX_VAR(opline->result.var)); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && @@ -16433,27 +16417,20 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_R_SPEC_VAR_HANDLER(ZE is_empty = iter->funcs->valid(iter) != SUCCESS; - if (UNEXPECTED(EG(exception) != NULL)) { - OBJ_RELEASE(&iter->std); - zval_ptr_dtor_nogc(free_op1); - HANDLE_EXCEPTION(); - } - iter->index = -1; /* will be set to 0 before using next handler */ - - ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; - zval_ptr_dtor_nogc(free_op1); if (is_empty) { + OBJ_RELEASE(&iter->std); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } else { + iter->index = -1; /* will be set to 0 before using next handler */ + + ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std); + Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } } } else { zend_error(E_WARNING, "Invalid argument supplied for foreach()"); - ZVAL_UNDEF(EX_VAR(opline->result.var)); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; zval_ptr_dtor_nogc(free_op1); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } @@ -16502,7 +16479,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(Z while (1) { if (UNEXPECTED(pos >= fe_ht->nNumUsed)) { if (UNEXPECTED(free_op1)) {zval_ptr_dtor_nogc(free_op1);}; - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; + zval_ptr_dtor_nogc(EX_VAR(opline->result.var)); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && @@ -16542,7 +16519,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(Z while (1) { if (UNEXPECTED(pos >= fe_ht->nNumUsed)) { if (UNEXPECTED(free_op1)) {zval_ptr_dtor_nogc(free_op1);}; - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; + zval_ptr_dtor_nogc(EX_VAR(opline->result.var)); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && @@ -16602,10 +16579,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(Z } HANDLE_EXCEPTION(); } - iter->index = -1; /* will be set to 0 before using next handler */ - - ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; if (IS_VAR == IS_VAR) { if (UNEXPECTED(free_op1)) {zval_ptr_dtor_nogc(free_op1);}; @@ -16613,15 +16586,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(Z zval_ptr_dtor_nogc(free_op1); } if (is_empty) { + zval_ptr_dtor_nogc(&iter->std); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } else { + iter->index = -1; /* will be set to 0 before using next handler */ + + ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std); + Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } } } else { zend_error(E_WARNING, "Invalid argument supplied for foreach()"); - ZVAL_UNDEF(EX_VAR(opline->result.var)); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; if (IS_VAR == IS_VAR) { if (UNEXPECTED(free_op1)) {zval_ptr_dtor_nogc(free_op1);}; } else { @@ -35424,7 +35400,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_R_SPEC_CV_HANDLER(ZEN while (1) { if (UNEXPECTED(pos >= fe_ht->nNumUsed)) { - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; + zval_ptr_dtor_nogc(EX_VAR(opline->result.var)); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && @@ -35469,26 +35445,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_R_SPEC_CV_HANDLER(ZEN is_empty = iter->funcs->valid(iter) != SUCCESS; - if (UNEXPECTED(EG(exception) != NULL)) { - OBJ_RELEASE(&iter->std); - - HANDLE_EXCEPTION(); - } - iter->index = -1; /* will be set to 0 before using next handler */ - - ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; - if (is_empty) { + OBJ_RELEASE(&iter->std); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } else { + iter->index = -1; /* will be set to 0 before using next handler */ + + ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std); + Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } } } else { zend_error(E_WARNING, "Invalid argument supplied for foreach()"); - ZVAL_UNDEF(EX_VAR(opline->result.var)); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } @@ -35537,7 +35506,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZE while (1) { if (UNEXPECTED(pos >= fe_ht->nNumUsed)) { - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; + zval_ptr_dtor_nogc(EX_VAR(opline->result.var)); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && @@ -35576,7 +35545,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZE while (1) { if (UNEXPECTED(pos >= fe_ht->nNumUsed)) { - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; + zval_ptr_dtor_nogc(EX_VAR(opline->result.var)); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } if (EXPECTED(Z_TYPE(p->val) != IS_UNDEF) && @@ -35635,10 +35604,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZE } HANDLE_EXCEPTION(); } - iter->index = -1; /* will be set to 0 before using next handler */ - - ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; if (IS_CV == IS_VAR) { @@ -35646,15 +35611,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZE } if (is_empty) { + zval_ptr_dtor_nogc(&iter->std); ZEND_VM_JMP(OP_JMP_ADDR(opline, opline->op2)); } else { + iter->index = -1; /* will be set to 0 before using next handler */ + + ZVAL_OBJ(EX_VAR(opline->result.var), &iter->std); + Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } } } else { zend_error(E_WARNING, "Invalid argument supplied for foreach()"); - ZVAL_UNDEF(EX_VAR(opline->result.var)); - Z_FE_ITER_P(EX_VAR(opline->result.var)) = (uint32_t)-1; if (IS_CV == IS_VAR) { } else { diff --git a/ext/opcache/Optimizer/block_pass.c b/ext/opcache/Optimizer/block_pass.c index 53647fec50..9de4bd5414 100644 --- a/ext/opcache/Optimizer/block_pass.c +++ b/ext/opcache/Optimizer/block_pass.c @@ -862,13 +862,15 @@ static void assemble_code_blocks(zend_cfg *cfg, zend_op_array *op_array) case ZEND_JMPNZ: case ZEND_JMPZ_EX: case ZEND_JMPNZ_EX: - case ZEND_FE_RESET_R: - case ZEND_FE_RESET_RW: case ZEND_JMP_SET: case ZEND_COALESCE: case ZEND_ASSERT_CHECK: ZEND_SET_OP_JMP_ADDR(opline, opline->op2, new_opcodes + blocks[b->successors[0]].start); break; + case ZEND_FE_RESET_R: + case ZEND_FE_RESET_RW: + ZEND_SET_OP_JMP_ADDR(opline, opline->op2, new_opcodes + blocks[b->successors[0]].start + 1); + break; case ZEND_CATCH: if (!opline->result.var) { opline->extended_value = ZEND_OPLINE_TO_OFFSET(opline, new_opcodes + blocks[b->successors[0]].start); diff --git a/ext/opcache/Optimizer/zend_cfg.c b/ext/opcache/Optimizer/zend_cfg.c index f39f9650ae..b2a3ba1dd4 100644 --- a/ext/opcache/Optimizer/zend_cfg.c +++ b/ext/opcache/Optimizer/zend_cfg.c @@ -397,7 +397,7 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b break; case ZEND_FE_RESET_R: case ZEND_FE_RESET_RW: - BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes); + BB_START(OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes - 1); BB_START(i + 1); break; case ZEND_UNSET_VAR: @@ -540,7 +540,7 @@ int zend_build_cfg(zend_arena **arena, const zend_op_array *op_array, uint32_t b break; case ZEND_FE_RESET_R: case ZEND_FE_RESET_RW: - record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes]); + record_successor(blocks, j, 0, block_map[OP_JMP_ADDR(opline, opline->op2) - op_array->opcodes - 1]); record_successor(blocks, j, 1, j + 1); break; case ZEND_FAST_CALL: -- 2.40.0