Skip to content

Commit 59958af

Browse files
committed
Only suppres instances of Exception and not Throwable by default
1 parent 39a10dc commit 59958af

File tree

6 files changed

+74
-12
lines changed

6 files changed

+74
-12
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
Listing Error in silence throwable class list should suppress
3+
--FILE--
4+
<?php
5+
6+
function test1() {
7+
throw new Error();
8+
return true;
9+
}
10+
11+
$var = @<Error>test1();
12+
13+
var_dump($var);
14+
15+
echo "Done\n";
16+
?>
17+
--EXPECT--
18+
NULL
19+
Done

Zend/tests/silence_operator/silence_function_nested.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ function test2($a) {
1313
return test1();
1414
}
1515

16-
$var = @test2();
16+
$var = @test2(1);
1717

1818
var_dump($var);
1919

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
Suppression operator must not suppres Error type Throwable errors
3+
--FILE--
4+
<?php
5+
6+
function test1() {
7+
throw new Error();
8+
return true;
9+
}
10+
11+
$var = @test1();
12+
13+
var_dump($var);
14+
15+
echo "Done\n";
16+
?>
17+
--EXPECTF--
18+
Fatal error: Uncaught Error in %s:4
19+
Stack trace:
20+
#0 %s(8): test1()
21+
#1 {main}
22+
thrown in %s on line 4

Zend/tests/silence_operator/yield_from_silenced_non_iterable.phpt

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ function foo() {
99

1010
function generator() {
1111
yield 1;
12+
/* This emits a Error type of throwable which is not suppressed */
1213
@yield from foo();
1314
yield 2;
1415
}
@@ -19,7 +20,11 @@ foreach (generator() as $val) {
1920

2021
echo "Done\n";
2122
?>
22-
--EXPECT--
23+
--EXPECTF--
2324
int(1)
24-
int(2)
25-
Done
25+
26+
Fatal error: Uncaught Error: Can use "yield from" only with arrays and Traversables in %s:%d
27+
Stack trace:
28+
#0 %s(%d): generator()
29+
#1 {main}
30+
thrown in %s on line %d

Zend/zend_vm_def.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7355,8 +7355,6 @@ ZEND_VM_HANDLER(201, ZEND_SILENCE_CATCH, ANY, ANY)
73557355

73567356
SAVE_OPLINE();
73577357

7358-
zend_exception_restore();
7359-
73607358
/* Came from class list virtual catch blocks */
73617359
if (opline->extended_value == 2) {
73627360
if (EG(exception) == NULL) {
@@ -7374,6 +7372,13 @@ ZEND_VM_HANDLER(201, ZEND_SILENCE_CATCH, ANY, ANY)
73747372
HANDLE_EXCEPTION();
73757373
}
73767374
} else if (EG(exception) && opline->extended_value != 2) {
7375+
ZEND_ASSERT(EG(exception)->ce);
7376+
/* Only suppress Exception or a subclass of, and NOT Error throwable errors */
7377+
if (!instanceof_function(zend_ce_exception, EG(exception)->ce)) {
7378+
zend_rethrow_exception(execute_data);
7379+
HANDLE_EXCEPTION();
7380+
}
7381+
73777382
#ifdef HAVE_DTRACE
73787383
if (DTRACE_EXCEPTION_CAUGHT_ENABLED()) {
73797384
DTRACE_EXCEPTION_CAUGHT((char *)EG(exception)->ce->name);
@@ -7861,8 +7866,11 @@ ZEND_VM_HANDLER(149, ZEND_HANDLE_EXCEPTION, ANY, ANY)
78617866
}
78627867
}
78637868

7864-
/* Do not cleanup unfinished calls for SILENCE live range as it might still get executed */
7865-
if (!is_in_silence_live_range(EX(func)->op_array, throw_op_num)) {
7869+
/* Do not cleanup unfinished calls for SILENCE live range as it might still get executed
7870+
* However, this can only happen if the exception is an instance of Exception
7871+
* (Error never gets suppressed) */
7872+
if (!is_in_silence_live_range(EX(func)->op_array, throw_op_num)
7873+
|| !instanceof_function(zend_ce_exception, EG(exception)->ce)) {
78667874
cleanup_unfinished_calls(execute_data, throw_op_num);
78677875
}
78687876

Zend/zend_vm_execute.h

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2876,8 +2876,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SILENCE_CATCH_SPEC_HANDLER(ZEN
28762876

28772877
SAVE_OPLINE();
28782878

2879-
zend_exception_restore();
2880-
28812879
/* Came from class list virtual catch blocks */
28822880
if (opline->extended_value == 2) {
28832881
if (EG(exception) == NULL) {
@@ -2895,6 +2893,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SILENCE_CATCH_SPEC_HANDLER(ZEN
28952893
HANDLE_EXCEPTION();
28962894
}
28972895
} else if (EG(exception) && opline->extended_value != 2) {
2896+
ZEND_ASSERT(EG(exception)->ce);
2897+
/* Only suppress Exception or a subclass of, and NOT Error throwable errors */
2898+
if (!instanceof_function(zend_ce_exception, EG(exception)->ce)) {
2899+
zend_rethrow_exception(execute_data);
2900+
HANDLE_EXCEPTION();
2901+
}
2902+
28982903
#ifdef HAVE_DTRACE
28992904
if (DTRACE_EXCEPTION_CAUGHT_ENABLED()) {
29002905
DTRACE_EXCEPTION_CAUGHT((char *)EG(exception)->ce->name);
@@ -3136,8 +3141,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_HANDLE_EXCEPTION_SPEC_HANDLER(
31363141
}
31373142
}
31383143

3139-
/* Do not cleanup unfinished calls for SILENCE live range as it might still get executed */
3140-
if (!is_in_silence_live_range(EX(func)->op_array, throw_op_num)) {
3144+
/* Do not cleanup unfinished calls for SILENCE live range as it might still get executed
3145+
* However, this can only happen if the exception is an instance of Exception
3146+
* (Error never gets suppressed) */
3147+
if (!is_in_silence_live_range(EX(func)->op_array, throw_op_num)
3148+
|| !instanceof_function(zend_ce_exception, EG(exception)->ce)) {
31413149
cleanup_unfinished_calls(execute_data, throw_op_num);
31423150
}
31433151

0 commit comments

Comments
 (0)