Skip to content

Commit fdc8a29

Browse files
committed
Do not suppress diagnostics when a class list is passed to silence
Also fixes a bug where any return value from @<class> would be NULL
1 parent eb714c2 commit fdc8a29

5 files changed

+66
-24
lines changed
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--TEST--
2+
Diagnostics should still be emitted if a class list is passed to @, userland
3+
--FILE--
4+
<?php
5+
6+
function test() {
7+
trigger_error('Diagnostic message', E_USER_NOTICE);
8+
return true;
9+
}
10+
11+
$var = @<Exception>test();
12+
13+
var_dump($var);
14+
15+
echo "Done\n";
16+
?>
17+
--EXPECTF--
18+
Notice: Diagnostic message in %s on line %d
19+
bool(true)
20+
Done
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--TEST--
2+
Diagnostics should still be emitted if a class list is passed to @, internal
3+
--FILE--
4+
<?php
5+
6+
function test() {
7+
$r = $a + 1;
8+
return $r;
9+
}
10+
11+
$var = @<Exception>test();
12+
13+
var_dump($var);
14+
15+
echo "Done\n";
16+
?>
17+
--EXPECTF--
18+
Warning: Undefined variable $a in %s on line %d
19+
int(1)
20+
Done

Zend/zend_compile.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8917,6 +8917,7 @@ void zend_compile_silence(znode *result, zend_ast *ast) /* {{{ */
89178917
{
89188918
zend_ast *expr_ast = ast->child[0];
89198919
znode silence_node;
8920+
zend_op *silence_start_op;
89208921
zend_op *silence_catch_op;
89218922
uint32_t try_catch_offset;
89228923
uint32_t virtual_catch_op_num;
@@ -8926,7 +8927,7 @@ void zend_compile_silence(znode *result, zend_ast *ast) /* {{{ */
89268927
try_catch_offset = zend_add_try_element(get_next_op_number());
89278928
CG(context).try_catch_offset = try_catch_offset;
89288929

8929-
zend_emit_op_tmp(&silence_node, ZEND_BEGIN_SILENCE, NULL, NULL);
8930+
silence_start_op = zend_emit_op_tmp(&silence_node, ZEND_BEGIN_SILENCE, NULL, NULL);
89308931

89318932
if (expr_ast->kind == ZEND_AST_VAR) {
89328933
/* For @$var we need to force a FETCH instruction, otherwise the CV access will
@@ -8953,7 +8954,8 @@ void zend_compile_silence(znode *result, zend_ast *ast) /* {{{ */
89538954
zend_ast_list *classes = zend_ast_get_list(ast->child[1]);
89548955
uint32_t opnum_catch = (uint32_t)-1;
89558956

8956-
/* Inform SILENCE_CATCH opcode that there is an exception class list */
8957+
/* Inform SILENCE_START and SILENCE_CATCH opcode that there is an exception class list */
8958+
silence_start_op->extended_value = 1;
89578959
silence_catch_op->extended_value = 2;
89588960

89598961
ZEND_ASSERT(classes->children > 0 && "Should have at least one class");

Zend/zend_vm_def.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7275,6 +7275,11 @@ ZEND_VM_HANDLER(57, ZEND_BEGIN_SILENCE, ANY, ANY)
72757275

72767276
ZVAL_LONG(EX_VAR(opline->result.var), EG(error_reporting));
72777277

7278+
/* Do not suppress diagnostics when a class list is passed to @ */
7279+
if (opline->extended_value == 1) {
7280+
ZEND_VM_NEXT_OPCODE();
7281+
}
7282+
72787283
if (!E_HAS_ONLY_FATAL_ERRORS(EG(error_reporting))) {
72797284
do {
72807285
/* Do not silence fatal errors */
@@ -7322,20 +7327,15 @@ ZEND_VM_HANDLER(201, ZEND_SILENCE_CATCH, ANY, ANY)
73227327

73237328
/* Came from class list virtual catch blocks */
73247329
if (opline->extended_value == 2) {
7325-
if (EG(exception) == NULL) {
7326-
/* Free object (needed to not leak memory on @new) */
7327-
if (Z_TYPE_P(EX_VAR(opline->result.var)) == IS_OBJECT) {
7328-
//OBJ_RELEASE(Z_OBJ_P(EX_VAR(opline->result.var)));
7329-
}
7330-
7331-
/* Set value to NULL */
7332-
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
7333-
ZVAL_NULL(EX_VAR(opline->result.var));
7334-
}
7335-
} else {
7330+
if (EG(exception) != NULL) {
73367331
zend_rethrow_exception(execute_data);
73377332
HANDLE_EXCEPTION();
73387333
}
7334+
/* Result is UNDEF means an exception has been caught */
7335+
if (opline->result_type & (IS_VAR | IS_TMP_VAR)
7336+
&& Z_TYPE_P(EX_VAR(opline->result.var)) == IS_UNDEF) {
7337+
ZVAL_NULL(EX_VAR(opline->result.var));
7338+
}
73397339
} else if (EG(exception) && opline->extended_value != 2) {
73407340
ZEND_ASSERT(EG(exception)->ce);
73417341
/* Only suppress Exception or a subclass of, and NOT Error throwable errors */

Zend/zend_vm_execute.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2724,6 +2724,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BEGIN_SILENCE_SPEC_HANDLER(ZEN
27242724

27252725
ZVAL_LONG(EX_VAR(opline->result.var), EG(error_reporting));
27262726

2727+
/* Do not suppress diagnostics when a class list is passed to @ */
2728+
if (opline->extended_value == 1) {
2729+
ZEND_VM_NEXT_OPCODE();
2730+
}
2731+
27272732
if (!E_HAS_ONLY_FATAL_ERRORS(EG(error_reporting))) {
27282733
do {
27292734
/* Do not silence fatal errors */
@@ -2760,20 +2765,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SILENCE_CATCH_SPEC_HANDLER(ZEN
27602765

27612766
/* Came from class list virtual catch blocks */
27622767
if (opline->extended_value == 2) {
2763-
if (EG(exception) == NULL) {
2764-
/* Free object (needed to not leak memory on @new) */
2765-
if (Z_TYPE_P(EX_VAR(opline->result.var)) == IS_OBJECT) {
2766-
//OBJ_RELEASE(Z_OBJ_P(EX_VAR(opline->result.var)));
2767-
}
2768-
2769-
/* Set value to NULL */
2770-
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
2771-
ZVAL_NULL(EX_VAR(opline->result.var));
2772-
}
2773-
} else {
2768+
if (EG(exception) != NULL) {
27742769
zend_rethrow_exception(execute_data);
27752770
HANDLE_EXCEPTION();
27762771
}
2772+
/* Result is UNDEF means an exception has been caught */
2773+
if (opline->result_type & (IS_VAR | IS_TMP_VAR)
2774+
&& Z_TYPE_P(EX_VAR(opline->result.var)) == IS_UNDEF) {
2775+
ZVAL_NULL(EX_VAR(opline->result.var));
2776+
}
27772777
} else if (EG(exception) && opline->extended_value != 2) {
27782778
ZEND_ASSERT(EG(exception)->ce);
27792779
/* Only suppress Exception or a subclass of, and NOT Error throwable errors */

0 commit comments

Comments
 (0)