Skip to content

Commit 1292037

Browse files
committed
Fix stale EG(opline_before_exception) pointer through eval
Fixes GH-20183 Closes GH-20184
1 parent 8761c4e commit 1292037

File tree

5 files changed

+73
-3
lines changed

5 files changed

+73
-3
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ PHP NEWS
99
. Fixed bug GH-19844 (Don't bail when closing resources on shutdown). (ilutov)
1010
. Fixed bug GH-20177 (Accessing overridden private property in
1111
get_object_vars() triggers assertion error). (ilutov)
12+
. Fixed bug GH-20183 (Stale EG(opline_before_exception) pointer through eval).
13+
(ilutov)
1214

1315
- DOM:
1416
. Partially fixed bug GH-16317 (DOM classes do not allow

Zend/tests/gh20183_001.phpt

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
--TEST--
2+
GH-20183: Stale EG(opline_before_exception) pointer through eval
3+
--CREDITS--
4+
Viet Hoang Luu (@vi3tL0u1s)
5+
--FILE--
6+
<?php
7+
8+
class A {
9+
function __destruct() {
10+
eval('try { throw new Error(); } catch (Error $e) {}');
11+
debug_print_backtrace();
12+
}
13+
}
14+
15+
B::$b = new A;
16+
17+
?>
18+
--EXPECTF--
19+
#0 %s(10): A->__destruct()
20+
21+
Fatal error: Uncaught Error: Class "B" not found in %s:10
22+
Stack trace:
23+
#0 {main}
24+
thrown in %s on line 10

Zend/tests/gh20183_002.phpt

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
--TEST--
2+
GH-20183: Stale EG(opline_before_exception) pointer through eval
3+
--CREDITS--
4+
Arnaud Le Blanc <lbarnaud@php.net>
5+
--FILE--
6+
<?php
7+
8+
function gen() {
9+
try {
10+
yield 1;
11+
} finally {
12+
eval('try { throw new Error(); } catch (Error) {}');
13+
debug_print_backtrace();
14+
}
15+
}
16+
17+
class A {
18+
private $gen;
19+
function __construct() {
20+
$this->gen = gen();
21+
$this->gen->rewind();
22+
}
23+
}
24+
25+
B::$a = new A();
26+
27+
?>
28+
--EXPECTF--
29+
#0 %s(20): gen()
30+
31+
Fatal error: Uncaught Error: Class "B" not found in %s:20
32+
Stack trace:
33+
#0 {main}
34+
thrown in %s on line 20

Zend/zend_generators.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -317,9 +317,16 @@ static void zend_generator_dtor_storage(zend_object *object) /* {{{ */
317317
ZEND_CALL_VAR(ex, ex->func->op_array.opcodes[try_catch->finally_end].op1.var);
318318

319319
zend_generator_cleanup_unfinished_execution(generator, ex, try_catch->finally_op);
320-
zend_object *old_exception = EG(exception);
321-
const zend_op *old_opline_before_exception = EG(opline_before_exception);
322-
EG(exception) = NULL;
320+
321+
zend_object *old_exception = NULL;
322+
const zend_op *old_opline_before_exception = NULL;
323+
if (EG(exception)) {
324+
EG(current_execute_data)->opline = EG(opline_before_exception);
325+
old_exception = EG(exception);
326+
old_opline_before_exception = EG(opline_before_exception);
327+
EG(exception) = NULL;
328+
}
329+
323330
Z_OBJ_P(fast_call) = NULL;
324331
Z_OPLINE_NUM_P(fast_call) = (uint32_t)-1;
325332

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

330337
if (old_exception) {
338+
EG(current_execute_data)->opline = EG(exception_op);
331339
EG(opline_before_exception) = old_opline_before_exception;
332340
if (EG(exception)) {
333341
zend_exception_set_previous(EG(exception), old_exception);

Zend/zend_objects.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,7 @@ ZEND_API void zend_objects_destroy_object(zend_object *object)
164164
&& ZEND_USER_CODE(EG(current_execute_data)->func->common.type)) {
165165
zend_rethrow_exception(EG(current_execute_data));
166166
}
167+
EG(current_execute_data)->opline = EG(opline_before_exception);
167168
old_exception = EG(exception);
168169
old_opline_before_exception = EG(opline_before_exception);
169170
EG(exception) = NULL;
@@ -173,6 +174,7 @@ ZEND_API void zend_objects_destroy_object(zend_object *object)
173174
zend_call_known_instance_method_with_0_params(destructor, object, NULL);
174175

175176
if (old_exception) {
177+
EG(current_execute_data)->opline = EG(exception_op);
176178
EG(opline_before_exception) = old_opline_before_exception;
177179
if (EG(exception)) {
178180
zend_exception_set_previous(EG(exception), old_exception);

0 commit comments

Comments
 (0)