summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikic@php.net>2016-05-28 13:13:11 +0200
committerNikita Popov <nikic@php.net>2016-05-28 13:21:05 +0200
commit4746e5efcb135051e003294f4721792139779fd0 (patch)
treec4b6513e32327f680a596a85ababf71cd63af156
parentd29bd582a8cc28e9288b441e269d98f4f28da77d (diff)
downloadphp-git-4746e5efcb135051e003294f4721792139779fd0.tar.gz
Forbid "yield from" in force closed generators
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.
-rw-r--r--Zend/tests/generators/yield_from_force_closed.phpt37
-rw-r--r--Zend/zend_vm_def.h6
-rw-r--r--Zend/zend_vm_execute.h24
3 files changed, 67 insertions, 0 deletions
diff --git a/Zend/tests/generators/yield_from_force_closed.phpt b/Zend/tests/generators/yield_from_force_closed.phpt
new file mode 100644
index 0000000000..87fcd2e8ed
--- /dev/null
+++ b/Zend/tests/generators/yield_from_force_closed.phpt
@@ -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}
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index cbb986b028..ce7c6faea2 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -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)) {
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index d9d58e02ab..aba8081585 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -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)) {