From 02dca18b9045029e75d672b8667c1411dde5ca34 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Sun, 1 Dec 2013 13:37:56 +0100 Subject: [PATCH] Fix bug #65764 I'm not exactly sure whether this is the right way to fix it. The question is whether Generator::throw() on a newborn generator (i.e. a generator that is not yet at yield expression) should first advance to the first yield and throw the exception there or whether it should instead throw the exception in the caller's context. The old behavior was to throw it at the start of the function (i.e. the very first opcode), which causes issues like the one in #65764. Effectively it's impossible to properly handle the exceptions in this case. For now I choose the variant where the generator advances to the first yield before throwing, as that's consistent with how all other methods on the Generator object currently behave. This does not necessarily match the behavior in other languages, e.g. Python would throw the exception in the caller's context. But then our send() method already has this kind of deviation, so it stays internally consistent at least. --- NEWS | 4 +++- Zend/tests/generators/throw_caught.phpt | 2 ++ Zend/tests/generators/throw_rethrow.phpt | 2 ++ Zend/zend_generators.c | 2 ++ 4 files changed, 9 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index 6afb736c6d..f4b3bf8c0c 100644 --- a/NEWS +++ b/NEWS @@ -4,8 +4,10 @@ PHP NEWS - Core: . Added validation of class names in the autoload process. (Dmitry) - . Fixed buf #66041 (list() fails to unpack yielded ArrayAccess object). + . Fixed bug #66041 (list() fails to unpack yielded ArrayAccess object). (Nikita) + . Fixed bug #65764 (generators/throw_rethrow FAIL with + ZEND_COMPILE_EXTENDED_INFO). (Nikita) - Date: . Fixed bug #66060 (Heap buffer over-read in DateInterval). (Remi) diff --git a/Zend/tests/generators/throw_caught.phpt b/Zend/tests/generators/throw_caught.phpt index 0c3f8e9b2d..c5e9d81ebc 100644 --- a/Zend/tests/generators/throw_caught.phpt +++ b/Zend/tests/generators/throw_caught.phpt @@ -4,6 +4,7 @@ Generator::throw() where the exception is caught in the generator throw(new RuntimeException('Test'))); ?> --EXPECTF-- +before yield exception 'RuntimeException' with message 'Test' in %s:%d Stack trace: #0 {main} diff --git a/Zend/tests/generators/throw_rethrow.phpt b/Zend/tests/generators/throw_rethrow.phpt index 267f5f0db8..65044ee3f3 100644 --- a/Zend/tests/generators/throw_rethrow.phpt +++ b/Zend/tests/generators/throw_rethrow.phpt @@ -4,6 +4,7 @@ Generator::throw() where the generator throws a different exception throw(new RuntimeException('throw'))); ?> --EXPECTF-- +before yield Caught: exception 'RuntimeException' with message 'throw' in %s:%d Stack trace: #0 {main} diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index bc3d6d9a18..ec9e9b89fb 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -560,6 +560,8 @@ ZEND_METHOD(Generator, throw) generator = (zend_generator *) zend_object_store_get_object(getThis() TSRMLS_CC); + zend_generator_ensure_initialized(generator TSRMLS_CC); + if (generator->execute_data) { /* Throw the exception in the context of the generator */ zend_execute_data *current_execute_data = EG(current_execute_data); -- 2.50.1