]> granicus.if.org Git - php/commitdiff
Fixed bug #66041: list() fails to unpack yielded ArrayAccess object
authorNikita Popov <nikic@php.net>
Sat, 30 Nov 2013 12:05:40 +0000 (13:05 +0100)
committerNikita Popov <nikic@php.net>
Sat, 30 Nov 2013 12:08:31 +0000 (13:08 +0100)
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.

NEWS
Zend/tests/generators/bug66041.phpt [new file with mode: 0644]
Zend/zend_compile.c
Zend/zend_generators.c
Zend/zend_generators.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/NEWS b/NEWS
index 55ee92e4e6762e45f8f2ec5795847dd277747f03..008b22dc18022ab17136470c2e7608519fd6d5d2 100644 (file)
--- 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 (file)
index 0000000..d944224
--- /dev/null
@@ -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"
index 60b9e3e653c04504bc3308b7eda2d79c691cbf04..c5f3769216f0ce04f0dae6da5f74bcd8f75eaf0a 100644 (file)
@@ -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);
 }
index 0af20f4593fcb615ac2b572c9f808a2ca3065ebf..c0116332e7b592609535ea51c25e48b3486ab0de 100644 (file)
@@ -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);
 
index bc125658ee74ee28fdcebdfd0bf0f76641b73a3c..d5f61013155dc1a22f2389d792de85852e68625b 100644 (file)
@@ -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;
 
index 05557e9833628f78b7b18fe221f1e88036688c21..9db6ea19f9de699df3078106b31912ef41c81b42 100644 (file)
@@ -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. */
index ec29f9e7d8da4efb344515af3c8ed89164f9d2cc..3a0a70e9465c6fc9b097736ce69a83dc091261d8 100644 (file)
@@ -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. */