com php-src: Fixed bug #66041: list() fails to unpack yielded ArrayAccess object: NEWS Zend/tests/generators/bug66041.phpt Zend/zend_co mpile.c
Zend/zend_generators.c Zend/zend_generators .h Zend/zend_vm_def.h Zend/zend_vm_execute.h
| From: | Nikita Popov | Date: | Sat, 30 Nov 2013 12:08:31 +0000 |
| Subject: | com php-src: Fixed bug #66041: list() fails to unpack yielded ArrayAccess object: NEWS Zend/tests/generators/bug66041.phpt Zend/zend_co mpile.c Zend/zend_generators.c Zend/zend_generators .h Zend/zend_vm_def.h Zend/zend_vm_execute.h |
||
| Groups: | php.cvs | ||
| Request: | Send a blank email to php-cvs+get-74179@lists.php.net to get a copy of this message | ||
Commit: 9589cae8cb1b13710ca36491f30b569113f9e329
Author: Nikita Popov <nikic@php.net> Sat, 30 Nov 2013 13:05:40 +0100
Parents: 5f09944662e09ea0b3f93cfab8702f188955e68c
Branches: PHP-5.5 PHP-5.6 master
Link: http://git.php.net/?p=php-src.git;a=commitdiff;h=9589cae8cb1b13710ca36491f30b569113f9e329
Log:
Fixed bug #66041: list() fails to unpack yielded ArrayAccess object
Yield return values now use IS_VAR rather than IS_TMP_VAR. This
fixes the issue with list() and should also be faster as it avoids
doing a zval copy.
Bugs:
https://bugs.php.net/66041
Changed paths:
M NEWS
A Zend/tests/generators/bug66041.phpt
M Zend/zend_compile.c
M Zend/zend_generators.c
M Zend/zend_generators.h
M Zend/zend_vm_def.h
M Zend/zend_vm_execute.h
diff --git a/NEWS b/NEWS index 55ee92e..008b22d 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,8 @@ PHP NEWS - Core: . Added validation of class names in the autoload process. (Dmitry) + . Fixed buf #66041 (list() fails to unpack yielded ArrayAccess object). + (Nikita) - Date: . Fixed bug #66060 (Heap buffer over-read in DateInterval). (Remi) diff --git a/Zend/tests/generators/bug66041.phpt b/Zend/tests/generators/bug66041.phpt new file mode 100644 index 0000000..d944224 --- /dev/null +++ b/Zend/tests/generators/bug66041.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #66041: list() fails to unpack yielded ArrayAccess object +--FILE-- +<?php +function dumpElement() { + list($value) = yield; + var_dump($value); +}; + +$fixedArray = new SplFixedArray(1); +$fixedArray[0] = 'the element'; + +$generator = dumpElement(); +$generator->send($fixedArray); +?> +--EXPECT-- +string(11) "the element" diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 60b9e3e..c5f3769 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2782,7 +2782,7 @@ void zend_do_yield(znode *result, znode *value, const znode *key, zend_bool is_v SET_UNUSED(opline->op2); } - opline->result_type = IS_TMP_VAR; + opline->result_type = IS_VAR; opline->result.var = get_temporary_variable(CG(active_op_array)); GET_NODE(result, opline->result); } diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 0af20f4..c011633 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -55,6 +55,11 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished zval_ptr_dtor(&execute_data->current_this); } + if (!finished_execution && generator->send_target) { + Z_DELREF_PP(generator->send_target); + generator->send_target = NULL; + } + /* A fatal error / die occurred during the generator execution. Trying to clean * up the stack may not be safe in this case. */ if (CG(unclean_shutdown)) { @@ -519,8 +524,12 @@ ZEND_METHOD(Generator, send) return; } - /* Put sent value into the TMP_VAR slot */ - MAKE_COPY_ZVAL(&value, &generator->send_target->tmp_var); + /* Put sent value in the target VAR slot, if it is used */ + if (generator->send_target) { + Z_DELREF_PP(generator->send_target); + Z_ADDREF_P(value); + *generator->send_target = value; + } zend_generator_resume(generator TSRMLS_CC); diff --git a/Zend/zend_generators.h b/Zend/zend_generators.h index bc12565..d5f6101 100644 --- a/Zend/zend_generators.h +++ b/Zend/zend_generators.h @@ -49,7 +49,7 @@ typedef struct _zend_generator { /* Current key */ zval *key; /* Variable to put sent value into */ - temp_variable *send_target; + zval **send_target; /* Largest used integer key for auto-incrementing keys */ long largest_used_integer_key; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 05557e9..9db6ea1 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -5353,11 +5353,15 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index ec29f9e..3a0a70e 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -4198,11 +4198,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLE ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -4887,11 +4891,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -5904,11 +5912,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -6625,11 +6637,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDL ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -7373,11 +7389,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_A ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -9400,11 +9420,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -10091,11 +10115,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -11110,11 +11138,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -11690,11 +11722,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -12378,11 +12414,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -16265,11 +16305,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -18350,11 +18394,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -20818,11 +20866,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -21970,11 +22022,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -24104,11 +24160,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -25602,11 +25662,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDL ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -26916,11 +26980,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -28231,11 +28299,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -28653,11 +28725,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HAND ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -29964,11 +30040,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -33449,11 +33529,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_A ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -35396,11 +35480,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -37725,11 +37813,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -38729,11 +38821,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -40724,11 +40820,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */
diff --git a/NEWS b/NEWS index 55ee92e..008b22d 100644 --- a/NEWS +++ b/NEWS @@ -4,6 +4,8 @@ PHP NEWS - Core: . Added validation of class names in the autoload process. (Dmitry) + . Fixed buf #66041 (list() fails to unpack yielded ArrayAccess object). + (Nikita) - Date: . Fixed bug #66060 (Heap buffer over-read in DateInterval). (Remi) diff --git a/Zend/tests/generators/bug66041.phpt b/Zend/tests/generators/bug66041.phpt new file mode 100644 index 0000000..d944224 --- /dev/null +++ b/Zend/tests/generators/bug66041.phpt @@ -0,0 +1,17 @@ +--TEST-- +Bug #66041: list() fails to unpack yielded ArrayAccess object +--FILE-- +<?php +function dumpElement() { + list($value) = yield; + var_dump($value); +}; + +$fixedArray = new SplFixedArray(1); +$fixedArray[0] = 'the element'; + +$generator = dumpElement(); +$generator->send($fixedArray); +?> +--EXPECT-- +string(11) "the element" diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 60b9e3e..c5f3769 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2782,7 +2782,7 @@ void zend_do_yield(znode *result, znode *value, const znode *key, zend_bool is_v SET_UNUSED(opline->op2); } - opline->result_type = IS_TMP_VAR; + opline->result_type = IS_VAR; opline->result.var = get_temporary_variable(CG(active_op_array)); GET_NODE(result, opline->result); } diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 0af20f4..c011633 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -55,6 +55,11 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished zval_ptr_dtor(&execute_data->current_this); } + if (!finished_execution && generator->send_target) { + Z_DELREF_PP(generator->send_target); + generator->send_target = NULL; + } + /* A fatal error / die occurred during the generator execution. Trying to clean * up the stack may not be safe in this case. */ if (CG(unclean_shutdown)) { @@ -519,8 +524,12 @@ ZEND_METHOD(Generator, send) return; } - /* Put sent value into the TMP_VAR slot */ - MAKE_COPY_ZVAL(&value, &generator->send_target->tmp_var); + /* Put sent value in the target VAR slot, if it is used */ + if (generator->send_target) { + Z_DELREF_PP(generator->send_target); + Z_ADDREF_P(value); + *generator->send_target = value; + } zend_generator_resume(generator TSRMLS_CC); diff --git a/Zend/zend_generators.h b/Zend/zend_generators.h index bc12565..d5f6101 100644 --- a/Zend/zend_generators.h +++ b/Zend/zend_generators.h @@ -49,7 +49,7 @@ typedef struct _zend_generator { /* Current key */ zval *key; /* Variable to put sent value into */ - temp_variable *send_target; + zval **send_target; /* Largest used integer key for auto-incrementing keys */ long largest_used_integer_key; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 05557e9..9db6ea1 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -5353,11 +5353,15 @@ ZEND_VM_HANDLER(160, ZEND_YIELD, CONST|TMP|VAR|CV|UNUSED, CONST|TMP|VAR|CV|UNUSE ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index ec29f9e..3a0a70e 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -4198,11 +4198,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CONST_HANDLER(ZEND_OPCODE_HANDLE ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -4887,11 +4891,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_TMP_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -5904,11 +5912,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_VAR_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -6625,11 +6637,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDL ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -7373,11 +7389,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CONST_CV_HANDLER(ZEND_OPCODE_HANDLER_A ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -9400,11 +9420,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CONST_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -10091,11 +10115,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -11110,11 +11138,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -11690,11 +11722,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_UNUSED_HANDLER(ZEND_OPCODE_HANDLER ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -12378,11 +12414,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_TMP_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -16265,11 +16305,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CONST_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -18350,11 +18394,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_TMP_HANDLER(ZEND_OPCODE_HANDLER_AR ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -20818,11 +20866,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_VAR_HANDLER(ZEND_OPCODE_HANDLER_AR ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -21970,11 +22022,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_UNUSED_HANDLER(ZEND_OPCODE_HANDLER ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -24104,11 +24160,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_VAR_CV_HANDLER(ZEND_OPCODE_HANDLER_ARG ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -25602,11 +25662,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CONST_HANDLER(ZEND_OPCODE_HANDL ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -26916,11 +26980,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_TMP_HANDLER(ZEND_OPCODE_HANDLER ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -28231,11 +28299,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_VAR_HANDLER(ZEND_OPCODE_HANDLER ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -28653,11 +28725,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_UNUSED_HANDLER(ZEND_OPCODE_HAND ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -29964,11 +30040,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_UNUSED_CV_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -33449,11 +33529,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CONST_HANDLER(ZEND_OPCODE_HANDLER_A ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -35396,11 +35480,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARG ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -37725,11 +37813,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARG ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -38729,11 +38821,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */ @@ -40724,11 +40820,15 @@ static int ZEND_FASTCALL ZEND_YIELD_SPEC_CV_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS ZVAL_LONG(generator->key, generator->largest_used_integer_key); } - /* If a value is sent it should go into the result var */ - generator->send_target = &EX_T(opline->result.var); - - /* Initialize the sent value to NULL */ - EX_T(opline->result.var).tmp_var = EG(uninitialized_zval); + if (RETURN_VALUE_USED(opline)) { + /* If the return value of yield is used set the send + * target and initialize it to NULL */ + generator->send_target = &EX_T(opline->result.var).var.ptr; + Z_ADDREF(EG(uninitialized_zval)); + EX_T(opline->result.var).var.ptr = &EG(uninitialized_zval); + } else { + generator->send_target = NULL; + } /* We increment to the next op, so we are at the correct position when the * generator is resumed. */