Skip to content

Commit e3eb49c

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 59958af commit e3eb49c

File tree

5 files changed

+66
-24
lines changed

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
@@ -9042,6 +9042,7 @@ void zend_compile_silence(znode *result, zend_ast *ast) /* {{{ */
90429042
{
90439043
zend_ast *expr_ast = ast->child[0];
90449044
znode silence_node;
9045+
zend_op *silence_start_op;
90459046
zend_op *silence_catch_op;
90469047
uint32_t try_catch_offset;
90479048
uint32_t virtual_catch_op_num;
@@ -9051,7 +9052,7 @@ void zend_compile_silence(znode *result, zend_ast *ast) /* {{{ */
90519052
try_catch_offset = zend_add_try_element(get_next_op_number());
90529053
CG(context).try_catch_offset = try_catch_offset;
90539054

9054-
zend_emit_op_tmp(&silence_node, ZEND_BEGIN_SILENCE, NULL, NULL);
9055+
silence_start_op = zend_emit_op_tmp(&silence_node, ZEND_BEGIN_SILENCE, NULL, NULL);
90559056

90569057
if (expr_ast->kind == ZEND_AST_VAR) {
90579058
/* For @$var we need to force a FETCH instruction, otherwise the CV access will
@@ -9078,7 +9079,8 @@ void zend_compile_silence(znode *result, zend_ast *ast) /* {{{ */
90789079
zend_ast_list *classes = zend_ast_get_list(ast->child[1]);
90799080
uint32_t opnum_catch = (uint32_t)-1;
90809081

9081-
/* Inform SILENCE_CATCH opcode that there is an exception class list */
9082+
/* Inform SILENCE_START and SILENCE_CATCH opcode that there is an exception class list */
9083+
silence_start_op->extended_value = 1;
90829084
silence_catch_op->extended_value = 2;
90839085

90849086
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
@@ -7310,6 +7310,11 @@ ZEND_VM_HANDLER(57, ZEND_BEGIN_SILENCE, ANY, ANY)
73107310

73117311
ZVAL_LONG(EX_VAR(opline->result.var), EG(error_reporting));
73127312

7313+
/* Do not suppress diagnostics when a class list is passed to @ */
7314+
if (opline->extended_value == 1) {
7315+
ZEND_VM_NEXT_OPCODE();
7316+
}
7317+
73137318
if (!E_HAS_ONLY_FATAL_ERRORS(EG(error_reporting))) {
73147319
do {
73157320
/* Do not silence fatal errors */
@@ -7357,20 +7362,15 @@ ZEND_VM_HANDLER(201, ZEND_SILENCE_CATCH, ANY, ANY)
73577362

73587363
/* Came from class list virtual catch blocks */
73597364
if (opline->extended_value == 2) {
7360-
if (EG(exception) == NULL) {
7361-
/* Free object (needed to not leak memory on @new) */
7362-
if (Z_TYPE_P(EX_VAR(opline->result.var)) == IS_OBJECT) {
7363-
//OBJ_RELEASE(Z_OBJ_P(EX_VAR(opline->result.var)));
7364-
}
7365-
7366-
/* Set value to NULL */
7367-
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
7368-
ZVAL_NULL(EX_VAR(opline->result.var));
7369-
}
7370-
} else {
7365+
if (EG(exception) != NULL) {
73717366
zend_rethrow_exception(execute_data);
73727367
HANDLE_EXCEPTION();
73737368
}
7369+
/* Result is UNDEF means an exception has been caught */
7370+
if (opline->result_type & (IS_VAR | IS_TMP_VAR)
7371+
&& Z_TYPE_P(EX_VAR(opline->result.var)) == IS_UNDEF) {
7372+
ZVAL_NULL(EX_VAR(opline->result.var));
7373+
}
73747374
} else if (EG(exception) && opline->extended_value != 2) {
73757375
ZEND_ASSERT(EG(exception)->ce);
73767376
/* 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
@@ -2842,6 +2842,11 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BEGIN_SILENCE_SPEC_HANDLER(ZEN
28422842

28432843
ZVAL_LONG(EX_VAR(opline->result.var), EG(error_reporting));
28442844

2845+
/* Do not suppress diagnostics when a class list is passed to @ */
2846+
if (opline->extended_value == 1) {
2847+
ZEND_VM_NEXT_OPCODE();
2848+
}
2849+
28452850
if (!E_HAS_ONLY_FATAL_ERRORS(EG(error_reporting))) {
28462851
do {
28472852
/* Do not silence fatal errors */
@@ -2878,20 +2883,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SILENCE_CATCH_SPEC_HANDLER(ZEN
28782883

28792884
/* Came from class list virtual catch blocks */
28802885
if (opline->extended_value == 2) {
2881-
if (EG(exception) == NULL) {
2882-
/* Free object (needed to not leak memory on @new) */
2883-
if (Z_TYPE_P(EX_VAR(opline->result.var)) == IS_OBJECT) {
2884-
//OBJ_RELEASE(Z_OBJ_P(EX_VAR(opline->result.var)));
2885-
}
2886-
2887-
/* Set value to NULL */
2888-
if (opline->result_type & (IS_VAR | IS_TMP_VAR)) {
2889-
ZVAL_NULL(EX_VAR(opline->result.var));
2890-
}
2891-
} else {
2886+
if (EG(exception) != NULL) {
28922887
zend_rethrow_exception(execute_data);
28932888
HANDLE_EXCEPTION();
28942889
}
2890+
/* Result is UNDEF means an exception has been caught */
2891+
if (opline->result_type & (IS_VAR | IS_TMP_VAR)
2892+
&& Z_TYPE_P(EX_VAR(opline->result.var)) == IS_UNDEF) {
2893+
ZVAL_NULL(EX_VAR(opline->result.var));
2894+
}
28952895
} else if (EG(exception) && opline->extended_value != 2) {
28962896
ZEND_ASSERT(EG(exception)->ce);
28972897
/* Only suppress Exception or a subclass of, and NOT Error throwable errors */

0 commit comments

Comments
 (0)