Skip to content

Commit 255613f

Browse files
committed
Added support for catch without variable
1 parent ecf6392 commit 255613f

File tree

7 files changed

+168
-11
lines changed

7 files changed

+168
-11
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
Catching an exception without catch variable
3+
--FILE--
4+
<?php
5+
6+
try
7+
{
8+
throw new Exception;
9+
}
10+
catch(Exception)
11+
{
12+
echo "Caught\n";
13+
}
14+
15+
?>
16+
===DONE===
17+
--EXPECT--
18+
Caught
19+
===DONE===
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
Catching an exception without catch variable, multiple times
3+
--FILE--
4+
<?php
5+
6+
try
7+
{
8+
throw new Exception;
9+
}
10+
catch(RuntimeException)
11+
{
12+
echo "Should not be caught\n";
13+
}
14+
catch(Exception)
15+
{
16+
echo "Caught\n";
17+
}
18+
catch(Throwable)
19+
{
20+
echo "Should not be caught either\n";
21+
}
22+
23+
?>
24+
===DONE===
25+
--EXPECT--
26+
Caught
27+
===DONE===
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
Catching an exception with and without catch variable, multiple times
3+
--FILE--
4+
<?php
5+
6+
try
7+
{
8+
throw new Exception;
9+
}
10+
catch(RuntimeException $e)
11+
{
12+
echo "Should not be caught\n";
13+
}
14+
catch(Exception)
15+
{
16+
echo "Caught\n";
17+
}
18+
catch(Throwable $e)
19+
{
20+
echo "Should not be caught either\n";
21+
}
22+
23+
?>
24+
===DONE===
25+
--EXPECT--
26+
Caught
27+
===DONE===

Zend/zend_compile.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4575,7 +4575,7 @@ void zend_compile_try(zend_ast *ast) /* {{{ */
45754575
zend_ast *class_ast = catch_ast->child[0];
45764576
zend_ast *var_ast = catch_ast->child[1];
45774577
zend_ast *stmt_ast = catch_ast->child[2];
4578-
zval *var_name = zend_ast_get_zval(var_ast);
4578+
zval *var_name = var_ast ? zend_ast_get_zval(var_ast) : NULL;
45794579
zend_bool is_last_catch = (i + 1 == catches->children);
45804580

45814581
uint32_t opnum_catch;
@@ -4597,8 +4597,13 @@ void zend_compile_try(zend_ast *ast) /* {{{ */
45974597
opline->op1.constant = zend_add_class_name_literal(CG(active_op_array),
45984598
zend_resolve_class_name_ast(class_ast));
45994599

4600-
opline->op2_type = IS_CV;
4601-
opline->op2.var = lookup_cv(CG(active_op_array), zend_string_copy(Z_STR_P(var_name)));
4600+
if (var_name) {
4601+
opline->op2_type = IS_CV;
4602+
opline->op2.var = lookup_cv(CG(active_op_array), zend_string_copy(Z_STR_P(var_name)));
4603+
} else {
4604+
opline->op2_type = IS_UNUSED;
4605+
}
4606+
46024607
opline->result.num = is_last_catch;
46034608

46044609
zend_compile_stmt(stmt_ast);

Zend/zend_language_parser.y

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,8 @@ catch_list:
458458
{ $$ = zend_ast_create_list(0, ZEND_AST_CATCH_LIST); }
459459
| catch_list T_CATCH '(' name T_VARIABLE ')' '{' inner_statement_list '}'
460460
{ $$ = zend_ast_list_add($1, zend_ast_create(ZEND_AST_CATCH, $4, $5, $8)); }
461+
| catch_list T_CATCH '(' name ')' '{' inner_statement_list '}'
462+
{ $$ = zend_ast_list_add($1, zend_ast_create(ZEND_AST_CATCH, $4, NULL, $7)); }
461463
;
462464

463465
finally_statement:

Zend/zend_vm_def.h

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4121,7 +4121,7 @@ ZEND_VM_HANDLER(108, ZEND_THROW, CONST|TMP|VAR|CV, ANY)
41214121
HANDLE_EXCEPTION();
41224122
}
41234123

4124-
ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, CV, JMP_ADDR)
4124+
ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, CV|UNUSED, JMP_ADDR)
41254125
{
41264126
USE_OPLINE
41274127
zend_class_entry *ce, *catch_ce;
@@ -4160,12 +4160,21 @@ ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, CV, JMP_ADDR)
41604160
}
41614161

41624162
exception = EG(exception);
4163-
zval_ptr_dtor(EX_VAR(opline->op2.var));
4164-
ZVAL_OBJ(EX_VAR(opline->op2.var), EG(exception));
4163+
4164+
if (EXPECTED(OP2_TYPE == IS_CV)) {
4165+
zval_ptr_dtor(EX_VAR(opline->op2.var));
4166+
ZVAL_OBJ(EX_VAR(opline->op2.var), EG(exception));
4167+
}
4168+
41654169
if (UNEXPECTED(EG(exception) != exception)) {
4166-
GC_REFCOUNT(EG(exception))++;
4170+
if (EXPECTED(OP2_TYPE == IS_CV)) {
4171+
GC_REFCOUNT(EG(exception))++;
4172+
}
41674173
HANDLE_EXCEPTION();
41684174
} else {
4175+
if (UNEXPECTED(OP2_TYPE == IS_UNUSED)) {
4176+
GC_REFCOUNT(EG(exception))--;
4177+
}
41694178
EG(exception) = NULL;
41704179
ZEND_VM_NEXT_OPCODE();
41714180
}

Zend/zend_vm_execute.h

Lines changed: 72 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7430,6 +7430,65 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CONST_
74307430
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
74317431
}
74327432

7433+
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CATCH_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
7434+
{
7435+
USE_OPLINE
7436+
zend_class_entry *ce, *catch_ce;
7437+
zend_object *exception;
7438+
7439+
SAVE_OPLINE();
7440+
/* Check whether an exception has been thrown, if not, jump over code */
7441+
zend_exception_restore();
7442+
if (EG(exception) == NULL) {
7443+
ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
7444+
ZEND_VM_CONTINUE();
7445+
}
7446+
catch_ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)));
7447+
if (UNEXPECTED(catch_ce == NULL)) {
7448+
catch_ce = zend_fetch_class_by_name(Z_STR_P(EX_CONSTANT(opline->op1)), EX_CONSTANT(opline->op1) + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD);
7449+
7450+
CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)), catch_ce);
7451+
}
7452+
ce = EG(exception)->ce;
7453+
7454+
#ifdef HAVE_DTRACE
7455+
if (DTRACE_EXCEPTION_CAUGHT_ENABLED()) {
7456+
DTRACE_EXCEPTION_CAUGHT((char *)ce->name);
7457+
}
7458+
#endif /* HAVE_DTRACE */
7459+
7460+
if (ce != catch_ce) {
7461+
if (!catch_ce || !instanceof_function(ce, catch_ce)) {
7462+
if (opline->result.num) {
7463+
zend_throw_exception_internal(NULL);
7464+
HANDLE_EXCEPTION();
7465+
}
7466+
ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
7467+
ZEND_VM_CONTINUE();
7468+
}
7469+
}
7470+
7471+
exception = EG(exception);
7472+
7473+
if (EXPECTED(IS_UNUSED == IS_CV)) {
7474+
zval_ptr_dtor(EX_VAR(opline->op2.var));
7475+
ZVAL_OBJ(EX_VAR(opline->op2.var), EG(exception));
7476+
}
7477+
7478+
if (UNEXPECTED(EG(exception) != exception)) {
7479+
if (EXPECTED(IS_UNUSED == IS_CV)) {
7480+
GC_REFCOUNT(EG(exception))++;
7481+
}
7482+
HANDLE_EXCEPTION();
7483+
} else {
7484+
if (UNEXPECTED(IS_UNUSED == IS_UNUSED)) {
7485+
GC_REFCOUNT(EG(exception))--;
7486+
}
7487+
EG(exception) = NULL;
7488+
ZEND_VM_NEXT_OPCODE();
7489+
}
7490+
}
7491+
74337492
static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
74347493
{
74357494
USE_OPLINE
@@ -9315,12 +9374,21 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CATCH_SPEC_CONST_CV_HANDLER(ZE
93159374
}
93169375

93179376
exception = EG(exception);
9318-
zval_ptr_dtor(EX_VAR(opline->op2.var));
9319-
ZVAL_OBJ(EX_VAR(opline->op2.var), EG(exception));
9377+
9378+
if (EXPECTED(IS_CV == IS_CV)) {
9379+
zval_ptr_dtor(EX_VAR(opline->op2.var));
9380+
ZVAL_OBJ(EX_VAR(opline->op2.var), EG(exception));
9381+
}
9382+
93209383
if (UNEXPECTED(EG(exception) != exception)) {
9321-
GC_REFCOUNT(EG(exception))++;
9384+
if (EXPECTED(IS_CV == IS_CV)) {
9385+
GC_REFCOUNT(EG(exception))++;
9386+
}
93229387
HANDLE_EXCEPTION();
93239388
} else {
9389+
if (UNEXPECTED(IS_CV == IS_UNUSED)) {
9390+
GC_REFCOUNT(EG(exception))--;
9391+
}
93249392
EG(exception) = NULL;
93259393
ZEND_VM_NEXT_OPCODE();
93269394
}
@@ -57749,7 +57817,7 @@ void zend_init_opcodes_handlers(void)
5774957817
ZEND_NULL_HANDLER,
5775057818
ZEND_NULL_HANDLER,
5775157819
ZEND_NULL_HANDLER,
57752-
ZEND_NULL_HANDLER,
57820+
ZEND_CATCH_SPEC_CONST_UNUSED_HANDLER,
5775357821
ZEND_CATCH_SPEC_CONST_CV_HANDLER,
5775457822
ZEND_NULL_HANDLER,
5775557823
ZEND_NULL_HANDLER,

0 commit comments

Comments
 (0)