com php-src: Fixed exception habdling on "return" statement. Such exceptions shouldn't be caught in the same function.:
Zend/tests/return_types/029.phpt Zend/tests/return _types/030.phpt Zend/tests/temporary_cleaning_ 008.phpt Zend/tests/temporary_cleaning_009 .phpt
Zend/zend_opcode.c Zend/zend_vm_def.h Z end/zend_vm_execute.h
| From: | Dmitry Stogov | Date: | Thu, 09 Jul 2015 17:47:25 +0000 |
| Subject: | com php-src: Fixed exception habdling on "return" statement. Such exceptions shouldn't be caught in the same function.: Zend/tests/return_types/029.phpt Zend/tests/return _types/030.phpt Zend/tests/temporary_cleaning_ 008.phpt Zend/tests/temporary_cleaning_009 .phpt Zend/zend_opcode.c Zend/zend_vm_def.h Z end/zend_vm_execute.h |
||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-87871@lists.php.net to get a copy of this message | ||
Commit: 17c5315bdf8f8087979aeb55f6d3a512ba197cf5
Author: Dmitry Stogov <dmitry@zend.com> Thu, 9 Jul 2015 20:47:25 +0300
Parents: d91aad5966f01259f0e1a431a754d917807761b5
Branches: master
Link: http://git.php.net/?p=php-src.git;a=commitdiff;h=17c5315bdf8f8087979aeb55f6d3a512ba197cf5
Log:
Fixed exception habdling on "return" statement.
Such exceptions shouldn't be caught in the same function.
Changed paths:
M Zend/tests/return_types/029.phpt
A Zend/tests/return_types/030.phpt
A Zend/tests/temporary_cleaning_008.phpt
A Zend/tests/temporary_cleaning_009.phpt
M Zend/zend_opcode.c
M Zend/zend_vm_def.h
M Zend/zend_vm_execute.h
diff --git a/Zend/tests/return_types/029.phpt b/Zend/tests/return_types/029.phpt index 3758745..c854456 100644 --- a/Zend/tests/return_types/029.phpt +++ b/Zend/tests/return_types/029.phpt @@ -8,12 +8,15 @@ function foo(): string { try { return $class; // invalid return type } catch (TypeError $e) { - return "no leak or segfault"; + return "BAG!"; } } } -print foo(); - +try { + print foo(); +} catch (TypeError $e) { + print "no leak or segfault"; +} ?> --EXPECT-- no leak or segfault diff --git a/Zend/tests/return_types/030.phpt b/Zend/tests/return_types/030.phpt new file mode 100644 index 0000000..73b512e --- /dev/null +++ b/Zend/tests/return_types/030.phpt @@ -0,0 +1,23 @@ +--TEST-- +Return types must not double free loop variables +--FILE-- +<?php + +function foo(): string { + $a = []; + try { + return $a; // invalid return type + } catch (TypeError $e) { + echo "BAG!\n"; + return "ops!\n"; + } +} +try { + echo foo(); +} catch (TypeError $e) { + echo "OK\n"; +} + +?> +--EXPECT-- +OK diff --git a/Zend/tests/temporary_cleaning_008.phpt b/Zend/tests/temporary_cleaning_008.phpt new file mode 100644 index 0000000..cbbbc6c --- /dev/null +++ b/Zend/tests/temporary_cleaning_008.phpt @@ -0,0 +1,42 @@ +--TEST-- +Exception inside a foreach loop with on an object with destructor +--FILE-- +<?php +class bar { + public $foo = 1; + public $bar = 2; + function __destruct() { + throw new Exception("test"); + } +} +function foo(): string { + foreach (new bar() as $foo) { + try { + $foo = new Exception; + return; + } catch (Exception $e) { + echo "Exception1: " . $e->getMessage() . "\n"; + } catch (Error $e) { + echo "Error1: " . $e->getMessage() . "\n"; + } + } + echo "bag!\n"; +} +try { + foo(); +} catch (Throwable $e) { + echo (($e instanceof Exception) ? "Exception2: " : "Error2: ") . + $e->getMessage() . "\n"; + $e = $e->getPrevious(); + while ($e instanceof Throwable) { + echo "\tPrev " . (($e instanceof Exception) ? "Exception2: " : "Error2: ") . + $e->getMessage() . "\n"; + $e = $e->getPrevious(); + } +} +echo "ok\n"; +?> +--EXPECTF-- +Exception2: test + Prev Error2: Return value of foo() must be of the type string, none returned in %stemporary_cleaning_008.php on line %d +ok diff --git a/Zend/tests/temporary_cleaning_009.phpt b/Zend/tests/temporary_cleaning_009.phpt new file mode 100644 index 0000000..c6f747e --- /dev/null +++ b/Zend/tests/temporary_cleaning_009.phpt @@ -0,0 +1,29 @@ +--TEST-- +Exception inside a foreach loop with on an object with destructor +--FILE-- +<?php +class bar { + public $foo = 1; + function __destruct() { + throw new Exception; + } +} + +function foo() { + foreach (new bar() as &$foo) { + try { + $foo = new Exception; + return; + } catch (Exception $e) { + echo "Exception1\n"; + } + } +} +try { + foo(); +} catch (Exception $e) { + echo "Exception2\n"; +} +?> +--EXPECT-- +Exception2 diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 64ba656..e84edd5 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -992,7 +992,8 @@ static zend_always_inline uint32_t *generate_var_liveliness_info_ex(zend_op_arra && opline->opcode != ZEND_CASE && opline->opcode != ZEND_FE_FETCH_R && opline->opcode != ZEND_FE_FETCH_RW - /* the following opcodes are not the "final" */ + /* the following opcodes are parts of "return" statement */ + && opline->opcode != ZEND_VERIFY_RETURN_TYPE && (opline->opcode != ZEND_FREE || !(opline->extended_value & ZEND_FREE_ON_RETURN)) && (opline->opcode != ZEND_FE_FREE || !(opline->extended_value & ZEND_FREE_ON_RETURN)) ) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 8744bf3..9b36b80 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2610,10 +2610,13 @@ ZEND_VM_HANDLER(47, ZEND_JMPNZ_EX, CONST|TMPVAR|CV, ANY) ZEND_VM_HANDLER(70, ZEND_FREE, TMPVAR, ANY) { + zval *var; USE_OPLINE SAVE_OPLINE(); - zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + var = EX_VAR(opline->op1.var); + zval_ptr_dtor_nogc(var); + ZVAL_NULL(var); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -2626,8 +2629,10 @@ ZEND_VM_HANDLER(127, ZEND_FE_FREE, TMPVAR, ANY) var = EX_VAR(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)); + Z_FE_ITER_P(var) = (uint32_t)-1; } zval_ptr_dtor_nogc(var); + ZVAL_NULL(var); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -3883,6 +3888,9 @@ ZEND_VM_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV, UNUSED) if (UNEXPECTED(EG(exception) != NULL)) { FREE_OP1(); + if (OP1_TYPE == IS_TMP_VAR || OP1_TYPE == IS_VAR) { + ZVAL_NULL(retval_ref); + } } #endif } @@ -7074,6 +7082,15 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) } } + if (catch_op_num || finally_op_num) { + if (EX(func)->op_array.opcodes[op_num].opcode == ZEND_VERIFY_RETURN_TYPE + || (EX(func)->op_array.opcodes[op_num].opcode == ZEND_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_RETURN)) + || (EX(func)->op_array.opcodes[op_num].opcode == ZEND_FE_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_RETURN)) + ) { + catch_op_num = finally_op_num = 0; + } + } + i_cleanup_unfinished_execution(execute_data, op_num, catch_op_num); if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index c45d2ee..6089b2e 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1500,6 +1500,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER( } } + if (catch_op_num || finally_op_num) { + if (EX(func)->op_array.opcodes[op_num].opcode == ZEND_VERIFY_RETURN_TYPE + || (EX(func)->op_array.opcodes[op_num].opcode == ZEND_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_RETURN)) + || (EX(func)->op_array.opcodes[op_num].opcode == ZEND_FE_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_RETURN)) + ) { + catch_op_num = finally_op_num = 0; + } + } + i_cleanup_unfinished_execution(execute_data, op_num, catch_op_num); if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) { @@ -7740,6 +7749,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CONST_ if (UNEXPECTED(EG(exception) != NULL)) { + if (IS_CONST == IS_TMP_VAR || IS_CONST == IS_VAR) { + ZVAL_NULL(retval_ref); + } } #endif } @@ -13536,6 +13548,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_TMP_UN if (UNEXPECTED(EG(exception) != NULL)) { zval_ptr_dtor_nogc(free_op1); + if (IS_TMP_VAR == IS_TMP_VAR || IS_TMP_VAR == IS_VAR) { + ZVAL_NULL(retval_ref); + } } #endif } @@ -19225,6 +19240,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_VAR_UN if (UNEXPECTED(EG(exception) != NULL)) { zval_ptr_dtor_nogc(free_op1); + if (IS_VAR == IS_TMP_VAR || IS_VAR == IS_VAR) { + ZVAL_NULL(retval_ref); + } } #endif } @@ -24910,6 +24928,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_UNUSED if (UNEXPECTED(EG(exception) != NULL)) { + if (IS_UNUSED == IS_TMP_VAR || IS_UNUSED == IS_VAR) { + ZVAL_NULL(retval_ref); + } } #endif } @@ -34346,6 +34367,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CV_UNU if (UNEXPECTED(EG(exception) != NULL)) { + if (IS_CV == IS_TMP_VAR || IS_CV == IS_VAR) { + ZVAL_NULL(retval_ref); + } } #endif } @@ -40164,10 +40188,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMPNZ_EX_SPEC_TMPVAR_HANDLER(Z static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FREE_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { + zval *var; USE_OPLINE SAVE_OPLINE(); - zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + var = EX_VAR(opline->op1.var); + zval_ptr_dtor_nogc(var); + ZVAL_NULL(var); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -40180,8 +40207,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FREE_SPEC_TMPVAR_HANDLER(ZE var = EX_VAR(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)); + Z_FE_ITER_P(var) = (uint32_t)-1; } zval_ptr_dtor_nogc(var); + ZVAL_NULL(var); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); }
diff --git a/Zend/tests/return_types/029.phpt b/Zend/tests/return_types/029.phpt index 3758745..c854456 100644 --- a/Zend/tests/return_types/029.phpt +++ b/Zend/tests/return_types/029.phpt @@ -8,12 +8,15 @@ function foo(): string { try { return $class; // invalid return type } catch (TypeError $e) { - return "no leak or segfault"; + return "BAG!"; } } } -print foo(); - +try { + print foo(); +} catch (TypeError $e) { + print "no leak or segfault"; +} ?> --EXPECT-- no leak or segfault diff --git a/Zend/tests/return_types/030.phpt b/Zend/tests/return_types/030.phpt new file mode 100644 index 0000000..73b512e --- /dev/null +++ b/Zend/tests/return_types/030.phpt @@ -0,0 +1,23 @@ +--TEST-- +Return types must not double free loop variables +--FILE-- +<?php + +function foo(): string { + $a = []; + try { + return $a; // invalid return type + } catch (TypeError $e) { + echo "BAG!\n"; + return "ops!\n"; + } +} +try { + echo foo(); +} catch (TypeError $e) { + echo "OK\n"; +} + +?> +--EXPECT-- +OK diff --git a/Zend/tests/temporary_cleaning_008.phpt b/Zend/tests/temporary_cleaning_008.phpt new file mode 100644 index 0000000..cbbbc6c --- /dev/null +++ b/Zend/tests/temporary_cleaning_008.phpt @@ -0,0 +1,42 @@ +--TEST-- +Exception inside a foreach loop with on an object with destructor +--FILE-- +<?php +class bar { + public $foo = 1; + public $bar = 2; + function __destruct() { + throw new Exception("test"); + } +} +function foo(): string { + foreach (new bar() as $foo) { + try { + $foo = new Exception; + return; + } catch (Exception $e) { + echo "Exception1: " . $e->getMessage() . "\n"; + } catch (Error $e) { + echo "Error1: " . $e->getMessage() . "\n"; + } + } + echo "bag!\n"; +} +try { + foo(); +} catch (Throwable $e) { + echo (($e instanceof Exception) ? "Exception2: " : "Error2: ") . + $e->getMessage() . "\n"; + $e = $e->getPrevious(); + while ($e instanceof Throwable) { + echo "\tPrev " . (($e instanceof Exception) ? "Exception2: " : "Error2: ") . + $e->getMessage() . "\n"; + $e = $e->getPrevious(); + } +} +echo "ok\n"; +?> +--EXPECTF-- +Exception2: test + Prev Error2: Return value of foo() must be of the type string, none returned in %stemporary_cleaning_008.php on line %d +ok diff --git a/Zend/tests/temporary_cleaning_009.phpt b/Zend/tests/temporary_cleaning_009.phpt new file mode 100644 index 0000000..c6f747e --- /dev/null +++ b/Zend/tests/temporary_cleaning_009.phpt @@ -0,0 +1,29 @@ +--TEST-- +Exception inside a foreach loop with on an object with destructor +--FILE-- +<?php +class bar { + public $foo = 1; + function __destruct() { + throw new Exception; + } +} + +function foo() { + foreach (new bar() as &$foo) { + try { + $foo = new Exception; + return; + } catch (Exception $e) { + echo "Exception1\n"; + } + } +} +try { + foo(); +} catch (Exception $e) { + echo "Exception2\n"; +} +?> +--EXPECT-- +Exception2 diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index 64ba656..e84edd5 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -992,7 +992,8 @@ static zend_always_inline uint32_t *generate_var_liveliness_info_ex(zend_op_arra && opline->opcode != ZEND_CASE && opline->opcode != ZEND_FE_FETCH_R && opline->opcode != ZEND_FE_FETCH_RW - /* the following opcodes are not the "final" */ + /* the following opcodes are parts of "return" statement */ + && opline->opcode != ZEND_VERIFY_RETURN_TYPE && (opline->opcode != ZEND_FREE || !(opline->extended_value & ZEND_FREE_ON_RETURN)) && (opline->opcode != ZEND_FE_FREE || !(opline->extended_value & ZEND_FREE_ON_RETURN)) ) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 8744bf3..9b36b80 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2610,10 +2610,13 @@ ZEND_VM_HANDLER(47, ZEND_JMPNZ_EX, CONST|TMPVAR|CV, ANY) ZEND_VM_HANDLER(70, ZEND_FREE, TMPVAR, ANY) { + zval *var; USE_OPLINE SAVE_OPLINE(); - zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + var = EX_VAR(opline->op1.var); + zval_ptr_dtor_nogc(var); + ZVAL_NULL(var); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -2626,8 +2629,10 @@ ZEND_VM_HANDLER(127, ZEND_FE_FREE, TMPVAR, ANY) var = EX_VAR(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)); + Z_FE_ITER_P(var) = (uint32_t)-1; } zval_ptr_dtor_nogc(var); + ZVAL_NULL(var); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -3883,6 +3888,9 @@ ZEND_VM_HANDLER(124, ZEND_VERIFY_RETURN_TYPE, CONST|TMP|VAR|UNUSED|CV, UNUSED) if (UNEXPECTED(EG(exception) != NULL)) { FREE_OP1(); + if (OP1_TYPE == IS_TMP_VAR || OP1_TYPE == IS_VAR) { + ZVAL_NULL(retval_ref); + } } #endif } @@ -7074,6 +7082,15 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY) } } + if (catch_op_num || finally_op_num) { + if (EX(func)->op_array.opcodes[op_num].opcode == ZEND_VERIFY_RETURN_TYPE + || (EX(func)->op_array.opcodes[op_num].opcode == ZEND_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_RETURN)) + || (EX(func)->op_array.opcodes[op_num].opcode == ZEND_FE_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_RETURN)) + ) { + catch_op_num = finally_op_num = 0; + } + } + i_cleanup_unfinished_execution(execute_data, op_num, catch_op_num); if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index c45d2ee..6089b2e 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1500,6 +1500,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER( } } + if (catch_op_num || finally_op_num) { + if (EX(func)->op_array.opcodes[op_num].opcode == ZEND_VERIFY_RETURN_TYPE + || (EX(func)->op_array.opcodes[op_num].opcode == ZEND_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_RETURN)) + || (EX(func)->op_array.opcodes[op_num].opcode == ZEND_FE_FREE && (EX(func)->op_array.opcodes[op_num].extended_value & ZEND_FREE_ON_RETURN)) + ) { + catch_op_num = finally_op_num = 0; + } + } + i_cleanup_unfinished_execution(execute_data, op_num, catch_op_num); if (finally_op_num && (!catch_op_num || catch_op_num >= finally_op_num)) { @@ -7740,6 +7749,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CONST_ if (UNEXPECTED(EG(exception) != NULL)) { + if (IS_CONST == IS_TMP_VAR || IS_CONST == IS_VAR) { + ZVAL_NULL(retval_ref); + } } #endif } @@ -13536,6 +13548,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_TMP_UN if (UNEXPECTED(EG(exception) != NULL)) { zval_ptr_dtor_nogc(free_op1); + if (IS_TMP_VAR == IS_TMP_VAR || IS_TMP_VAR == IS_VAR) { + ZVAL_NULL(retval_ref); + } } #endif } @@ -19225,6 +19240,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_VAR_UN if (UNEXPECTED(EG(exception) != NULL)) { zval_ptr_dtor_nogc(free_op1); + if (IS_VAR == IS_TMP_VAR || IS_VAR == IS_VAR) { + ZVAL_NULL(retval_ref); + } } #endif } @@ -24910,6 +24928,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_UNUSED if (UNEXPECTED(EG(exception) != NULL)) { + if (IS_UNUSED == IS_TMP_VAR || IS_UNUSED == IS_VAR) { + ZVAL_NULL(retval_ref); + } } #endif } @@ -34346,6 +34367,9 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CV_UNU if (UNEXPECTED(EG(exception) != NULL)) { + if (IS_CV == IS_TMP_VAR || IS_CV == IS_VAR) { + ZVAL_NULL(retval_ref); + } } #endif } @@ -40164,10 +40188,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMPNZ_EX_SPEC_TMPVAR_HANDLER(Z static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FREE_SPEC_TMPVAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { + zval *var; USE_OPLINE SAVE_OPLINE(); - zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); + var = EX_VAR(opline->op1.var); + zval_ptr_dtor_nogc(var); + ZVAL_NULL(var); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -40180,8 +40207,10 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_FREE_SPEC_TMPVAR_HANDLER(ZE var = EX_VAR(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)); + Z_FE_ITER_P(var) = (uint32_t)-1; } zval_ptr_dtor_nogc(var); + ZVAL_NULL(var); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); }