Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions Zend/tests/gh20183_001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
GH-20183: Stale EG(opline_before_exception) pointer through eval
--FILE--
<?php

class A {
function __destruct() {
eval('try { throw new Error(); } catch (Error $e) {}');
debug_print_backtrace();
}
}

B::$b = new A;

?>
--EXPECTF--
#0 %s(10): A->__destruct()

Fatal error: Uncaught Error: Class "B" not found in %s:10
Stack trace:
#0 {main}
thrown in %s on line 10
34 changes: 34 additions & 0 deletions Zend/tests/gh20183_002.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
--TEST--
GH-20183: Stale EG(opline_before_exception) pointer through eval
--CREDITS--
Arnaud Le Blanc <[email protected]>
--FILE--
<?php

function gen() {
try {
yield 1;
} finally {
eval('try { throw new Error(); } catch (Error) {}');
debug_print_backtrace();
}
}

class A {
private $gen;
function __construct() {
$this->gen = gen();
$this->gen->rewind();
}
}

B::$a = new A();

?>
--EXPECTF--
#0 %s(20): gen()

Fatal error: Uncaught Error: Class "B" not found in %s:20
Stack trace:
#0 {main}
thrown in %s on line 20
14 changes: 11 additions & 3 deletions Zend/zend_generators.c
Original file line number Diff line number Diff line change
Expand Up @@ -317,9 +317,16 @@ static void zend_generator_dtor_storage(zend_object *object) /* {{{ */
ZEND_CALL_VAR(ex, ex->func->op_array.opcodes[try_catch->finally_end].op1.var);

zend_generator_cleanup_unfinished_execution(generator, ex, try_catch->finally_op);
zend_object *old_exception = EG(exception);
const zend_op *old_opline_before_exception = EG(opline_before_exception);
EG(exception) = NULL;

zend_object *old_exception = NULL;
const zend_op *old_opline_before_exception = NULL;
if (EG(exception)) {
EG(current_execute_data)->opline = EG(opline_before_exception);
old_exception = EG(exception);
old_opline_before_exception = EG(opline_before_exception);
EG(exception) = NULL;
}

Z_OBJ_P(fast_call) = NULL;
Z_OPLINE_NUM_P(fast_call) = (uint32_t)-1;

Expand All @@ -328,6 +335,7 @@ static void zend_generator_dtor_storage(zend_object *object) /* {{{ */
zend_generator_resume(generator);

if (old_exception) {
EG(current_execute_data)->opline = EG(exception_op);
EG(opline_before_exception) = old_opline_before_exception;
if (EG(exception)) {
zend_exception_set_previous(EG(exception), old_exception);
Expand Down
2 changes: 2 additions & 0 deletions Zend/zend_objects.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ ZEND_API void zend_objects_destroy_object(zend_object *object)
&& ZEND_USER_CODE(EG(current_execute_data)->func->common.type)) {
zend_rethrow_exception(EG(current_execute_data));
}
EG(current_execute_data)->opline = EG(opline_before_exception);
old_exception = EG(exception);
old_opline_before_exception = EG(opline_before_exception);
EG(exception) = NULL;
Expand All @@ -173,6 +174,7 @@ ZEND_API void zend_objects_destroy_object(zend_object *object)
zend_call_known_instance_method_with_0_params(destructor, object, NULL);

if (old_exception) {
EG(current_execute_data)->opline = EG(exception_op);
EG(opline_before_exception) = old_opline_before_exception;
if (EG(exception)) {
zend_exception_set_previous(EG(exception), old_exception);
Expand Down
Loading