]> granicus.if.org Git - php/commitdiff
Forbid "yield from" in force closed generators
authorNikita Popov <nikic@php.net>
Sat, 28 May 2016 11:13:11 +0000 (13:13 +0200)
committerNikita Popov <nikic@php.net>
Sat, 28 May 2016 11:21:05 +0000 (13:21 +0200)
Same check we do for "yield", was missed when "yield from" was
added. We could make this more granular by only forbidding to
actually yield values and still allow something like "yield from []",
but this does not seem worthwhile.

Zend/tests/generators/yield_from_force_closed.phpt [new file with mode: 0644]
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/Zend/tests/generators/yield_from_force_closed.phpt b/Zend/tests/generators/yield_from_force_closed.phpt
new file mode 100644 (file)
index 0000000..87fcd2e
--- /dev/null
@@ -0,0 +1,37 @@
+--TEST--
+Cannot "yield from" from force closed generator
+--FILE--
+<?php
+
+function gen1() {
+    echo "gen1\n";
+    yield 1;
+}
+
+function gen2() {
+    try {
+        echo "try\n";
+        yield from gen1();
+    } finally {
+        echo "finally\n";
+        yield from gen1();
+    }
+}
+
+try {
+    $gen = gen2();
+    $gen->rewind();
+    unset($gen);
+} catch (Error $e) {
+    echo $e, "\n";
+}
+
+?>
+--EXPECTF--
+try
+gen1
+finally
+Error: Cannot use "yield from" in a force-closed generator in %s:%d
+Stack trace:
+#0 %s(%d): gen2()
+#1 {main}
index cbb986b0284f32e958dc6742f2a1bb3afadd74e9..ce7c6faea246d88fa5572a7c7de34a892d45e255 100644 (file)
@@ -7442,6 +7442,12 @@ ZEND_VM_HANDLER(142, ZEND_YIELD_FROM, CONST|TMP|VAR|CV, ANY)
        SAVE_OPLINE();
        val = GET_OP1_ZVAL_PTR_DEREF(BP_VAR_R);
 
+       if (UNEXPECTED(generator->flags & ZEND_GENERATOR_FORCED_CLOSE)) {
+               zend_throw_error(NULL, "Cannot use \"yield from\" in a force-closed generator");
+               FREE_OP1();
+               HANDLE_EXCEPTION();
+       }
+
        if (Z_TYPE_P(val) == IS_ARRAY) {
                ZVAL_COPY_VALUE(&generator->values, val);
                if (OP1_TYPE != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(val)) {
index d9d58e02ab4564cf7e52a5d41014e92365b34397..aba8081585b1f7b41d088c08924f671088dbe014 100644 (file)
@@ -4106,6 +4106,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_FROM_SPEC_CONST_HANDLER(
        SAVE_OPLINE();
        val = EX_CONSTANT(opline->op1);
 
+       if (UNEXPECTED(generator->flags & ZEND_GENERATOR_FORCED_CLOSE)) {
+               zend_throw_error(NULL, "Cannot use \"yield from\" in a force-closed generator");
+
+               HANDLE_EXCEPTION();
+       }
+
        if (Z_TYPE_P(val) == IS_ARRAY) {
                ZVAL_COPY_VALUE(&generator->values, val);
                if (IS_CONST != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(val)) {
@@ -12502,6 +12508,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_FROM_SPEC_TMP_HANDLER(ZE
        SAVE_OPLINE();
        val = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1);
 
+       if (UNEXPECTED(generator->flags & ZEND_GENERATOR_FORCED_CLOSE)) {
+               zend_throw_error(NULL, "Cannot use \"yield from\" in a force-closed generator");
+               zval_ptr_dtor_nogc(free_op1);
+               HANDLE_EXCEPTION();
+       }
+
        if (Z_TYPE_P(val) == IS_ARRAY) {
                ZVAL_COPY_VALUE(&generator->values, val);
                if (IS_TMP_VAR != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(val)) {
@@ -16320,6 +16332,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_FROM_SPEC_VAR_HANDLER(ZE
        SAVE_OPLINE();
        val = _get_zval_ptr_var_deref(opline->op1.var, execute_data, &free_op1);
 
+       if (UNEXPECTED(generator->flags & ZEND_GENERATOR_FORCED_CLOSE)) {
+               zend_throw_error(NULL, "Cannot use \"yield from\" in a force-closed generator");
+               zval_ptr_dtor_nogc(free_op1);
+               HANDLE_EXCEPTION();
+       }
+
        if (Z_TYPE_P(val) == IS_ARRAY) {
                ZVAL_COPY_VALUE(&generator->values, val);
                if (IS_VAR != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(val)) {
@@ -29759,6 +29777,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_YIELD_FROM_SPEC_CV_HANDLER(ZEN
        SAVE_OPLINE();
        val = _get_zval_ptr_cv_deref_BP_VAR_R(execute_data, opline->op1.var);
 
+       if (UNEXPECTED(generator->flags & ZEND_GENERATOR_FORCED_CLOSE)) {
+               zend_throw_error(NULL, "Cannot use \"yield from\" in a force-closed generator");
+
+               HANDLE_EXCEPTION();
+       }
+
        if (Z_TYPE_P(val) == IS_ARRAY) {
                ZVAL_COPY_VALUE(&generator->values, val);
                if (IS_CV != IS_TMP_VAR && Z_OPT_REFCOUNTED_P(val)) {