Grokbase Groups PHP php-cvs May 2016
FAQ
Commit: 921b3251b36eb5a930eb3de3496215833d3d548f
Author: Nikita Popov <nikic@php.net> Sat, 28 May 2016 14:38:11 +0200
Parents: 79de9fa4aa9a9c68c829a5c8c5945a631e5ba38a
Branches: master

Link: http://git.php.net/?p=php-src.git;a=commitdiff;h=921b3251b36eb5a930eb3de3496215833d3d548f

Log:
Fix bug #71604

Alternatively could throw some kind of uncatchable dummy exception
into the generator. Right now just checking for NULL in two places
seems simpler.

Bugs:
https://bugs.php.net/71604

Changed paths:
   M NEWS
   A Zend/tests/try/bug71604.phpt
   A Zend/tests/try/bug71604_2.phpt
   A Zend/tests/try/bug71604_3.phpt
   M Zend/zend_vm_def.h
   M Zend/zend_vm_execute.h


Diff:
diff --git a/NEWS b/NEWS
index 0c65ee8..2330dfd 100644
--- a/NEWS
+++ b/NEWS
@@ -14,6 +14,8 @@ PHP NEWS
    . Fixed bug #62814 (It is possible to stiffen child class members visibility).
      (Nikita)
    . Fixed bug #69989 (Generators don't participate in cycle GC). (Nikita)
+ . Fixed bug #71604 (Aborted Generators continue after nested finally).
+ (Nikita)
    . Fixed bug #71572 (String offset assignment from an empty string inserts
      null byte). (Francois)
    . Fixed bug #71897 (ASCII 0x7F Delete control character permitted in
diff --git a/Zend/tests/try/bug71604.phpt b/Zend/tests/try/bug71604.phpt
new file mode 100644
index 0000000..79803b9
--- /dev/null
+++ b/Zend/tests/try/bug71604.phpt
@@ -0,0 +1,25 @@
+--TEST--
+Bug #71604: Aborted Generators continue after nested finally
+--FILE--
+<?php
+function gen() {
+ try {
+ try {
+ yield;
+ } finally {
+ print "INNER\n";
+ }
+ } catch (Exception $e) {
+ print "EX\n";
+ } finally {
+ print "OUTER\n";
+ }
+ print "NOTREACHED\n";
+}
+
+gen()->current();
+
+?>
+--EXPECT--
+INNER
+OUTER
diff --git a/Zend/tests/try/bug71604_2.phpt b/Zend/tests/try/bug71604_2.phpt
new file mode 100644
index 0000000..8736cd8
--- /dev/null
+++ b/Zend/tests/try/bug71604_2.phpt
@@ -0,0 +1,39 @@
+--TEST--
+Bug #71604: Aborted Generators continue after nested finally (2)
+--FILE--
+<?php
+
+function gen() {
+ try {
+ throw new Exception(1);
+ } finally {
+ try {
+ throw new Exception(2);
+ } finally {
+ try {
+ yield;
+ } finally {
+ }
+ }
+ }
+}
+
+try {
+ gen()->rewind();
+} catch (Exception $e) {
+ echo $e, "\n";
+}
+
+?>
+--EXPECTF--
+Exception: 1 in %s:%d
+Stack trace:
+#0 [internal function]: gen()
+#1 %s(%d): Generator->rewind()
+#2 {main}
+
+Next Exception: 2 in %s:%d
+Stack trace:
+#0 [internal function]: gen()
+#1 %s(%d): Generator->rewind()
+#2 {main}
diff --git a/Zend/tests/try/bug71604_3.phpt b/Zend/tests/try/bug71604_3.phpt
new file mode 100644
index 0000000..058c9a7
--- /dev/null
+++ b/Zend/tests/try/bug71604_3.phpt
@@ -0,0 +1,38 @@
+--TEST--
+Bug #71604: Aborted Generators continue after nested finally (3)
+--FILE--
+<?php
+
+function gen() {
+ try {
+ throw new Exception(1);
+ } finally {
+ try {
+ yield;
+ } finally {
+ try {
+ throw new Exception(2);
+ } finally {
+ }
+ }
+ }
+}
+
+try {
+ gen()->rewind();
+} catch (Exception $e) {
+ echo $e, "\n";
+}
+
+?>
+--EXPECTF--
+Exception: 1 in %s:%d
+Stack trace:
+#0 [internal function]: gen()
+#1 %s(%d): Generator->rewind()
+#2 {main}
+
+Next Exception: 2 in %s:%d
+Stack trace:
+#0 %s(%d): gen()
+#1 {main}
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index b7a044f..c8eb4cb 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -7107,6 +7107,7 @@ ZEND_VM_HANDLER(155, ZEND_BIND_TRAITS, ANY, ANY)

  ZEND_VM_HELPER(zend_dispatch_try_catch_finally_helper, ANY, ANY, uint32_t try_catch_offset, uint32_t op_num)
  {
+ /* May be NULL during generator closing (only finally blocks are executed) */
   zend_object *ex = EG(exception);

   /* Walk try/catch/finally structures upwards, performing the necessary actions */
@@ -7114,7 +7115,7 @@ ZEND_VM_HELPER(zend_dispatch_try_catch_finally_helper, ANY, ANY, uint32_t try_ca
    zend_try_catch_element *try_catch =
     &EX(func)->op_array.try_catch_array[try_catch_offset];

- if (op_num < try_catch->catch_op) {
+ if (op_num < try_catch->catch_op && ex) {
     /* Go to catch block */
     cleanup_live_vars(execute_data, op_num, try_catch->catch_op);
     ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[try_catch->catch_op]);
@@ -7134,7 +7135,11 @@ ZEND_VM_HELPER(zend_dispatch_try_catch_finally_helper, ANY, ANY, uint32_t try_ca
     /* Chain potential exception from wrapping finally block */
     zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[try_catch->finally_end].op1.var);
     if (Z_OBJ_P(fast_call)) {
- zend_exception_set_previous(ex, Z_OBJ_P(fast_call));
+ if (ex) {
+ zend_exception_set_previous(ex, Z_OBJ_P(fast_call));
+ } else {
+ EG(exception) = Z_OBJ_P(fast_call);
+ }
      ex = Z_OBJ_P(fast_call);
     }
    }
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index d190cad..2b9727a 100644
--- a/Zend/zend_vm_execute.h
+++ b/Zend/zend_vm_execute.h
@@ -1692,6 +1692,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BIND_TRAITS_SPEC_HANDLER(ZEND_

  static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_dispatch_try_catch_finally_helper_SPEC(uint32_t try_catch_offset, uint32_t op_num ZEND_OPCODE_HANDLER_ARGS_DC)
  {
+ /* May be NULL during generator closing (only finally blocks are executed) */
   zend_object *ex = EG(exception);

   /* Walk try/catch/finally structures upwards, performing the necessary actions */
@@ -1699,7 +1700,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_dispatch_try_catch_finally_hel
    zend_try_catch_element *try_catch =
     &EX(func)->op_array.try_catch_array[try_catch_offset];

- if (op_num < try_catch->catch_op) {
+ if (op_num < try_catch->catch_op && ex) {
     /* Go to catch block */
     cleanup_live_vars(execute_data, op_num, try_catch->catch_op);
     ZEND_VM_SET_OPCODE(&EX(func)->op_array.opcodes[try_catch->catch_op]);
@@ -1719,7 +1720,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_dispatch_try_catch_finally_hel
     /* Chain potential exception from wrapping finally block */
     zval *fast_call = EX_VAR(EX(func)->op_array.opcodes[try_catch->finally_end].op1.var);
     if (Z_OBJ_P(fast_call)) {
- zend_exception_set_previous(ex, Z_OBJ_P(fast_call));
+ if (ex) {
+ zend_exception_set_previous(ex, Z_OBJ_P(fast_call));
+ } else {
+ EG(exception) = Z_OBJ_P(fast_call);
+ }
      ex = Z_OBJ_P(fast_call);
     }
    }

Search Discussions

Related Discussions

Discussion Navigation
viewthread | post
Discussion Overview
groupphp-cvs @
categoriesphp
postedMay 28, '16 at 12:40p
activeMay 28, '16 at 12:40p
posts1
users1
websitephp.net

1 user in discussion

Nikita Popov: 1 post

People

Translate

site design / logo © 2019 Grokbase