Skip to content

Commit

Permalink
Added support for catch without variable
Browse files Browse the repository at this point in the history
  • Loading branch information
Majkl578 committed Apr 21, 2016
1 parent ecf6392 commit 255613f
Show file tree
Hide file tree
Showing 7 changed files with 168 additions and 11 deletions.
19 changes: 19 additions & 0 deletions Zend/tests/try/catch_no_var_001.phpt
@@ -0,0 +1,19 @@
--TEST--
Catching an exception without catch variable
--FILE--
<?php

try
{
throw new Exception;
}
catch(Exception)
{
echo "Caught\n";
}

?>
===DONE===
--EXPECT--
Caught
===DONE===
27 changes: 27 additions & 0 deletions Zend/tests/try/catch_no_var_002.phpt
@@ -0,0 +1,27 @@
--TEST--
Catching an exception without catch variable, multiple times
--FILE--
<?php

try
{
throw new Exception;
}
catch(RuntimeException)
{
echo "Should not be caught\n";
}
catch(Exception)
{
echo "Caught\n";
}
catch(Throwable)
{
echo "Should not be caught either\n";
}

?>
===DONE===
--EXPECT--
Caught
===DONE===
27 changes: 27 additions & 0 deletions Zend/tests/try/catch_no_var_003.phpt
@@ -0,0 +1,27 @@
--TEST--
Catching an exception with and without catch variable, multiple times
--FILE--
<?php

try
{
throw new Exception;
}
catch(RuntimeException $e)
{
echo "Should not be caught\n";
}
catch(Exception)
{
echo "Caught\n";
}
catch(Throwable $e)
{
echo "Should not be caught either\n";
}

?>
===DONE===
--EXPECT--
Caught
===DONE===
11 changes: 8 additions & 3 deletions Zend/zend_compile.c
Expand Up @@ -4575,7 +4575,7 @@ void zend_compile_try(zend_ast *ast) /* {{{ */
zend_ast *class_ast = catch_ast->child[0];
zend_ast *var_ast = catch_ast->child[1];
zend_ast *stmt_ast = catch_ast->child[2];
zval *var_name = zend_ast_get_zval(var_ast);
zval *var_name = var_ast ? zend_ast_get_zval(var_ast) : NULL;
zend_bool is_last_catch = (i + 1 == catches->children);

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

opline->op2_type = IS_CV;
opline->op2.var = lookup_cv(CG(active_op_array), zend_string_copy(Z_STR_P(var_name)));
if (var_name) {
opline->op2_type = IS_CV;
opline->op2.var = lookup_cv(CG(active_op_array), zend_string_copy(Z_STR_P(var_name)));
} else {
opline->op2_type = IS_UNUSED;
}

opline->result.num = is_last_catch;

zend_compile_stmt(stmt_ast);
Expand Down
2 changes: 2 additions & 0 deletions Zend/zend_language_parser.y
Expand Up @@ -458,6 +458,8 @@ catch_list:
{ $$ = zend_ast_create_list(0, ZEND_AST_CATCH_LIST); }
| catch_list T_CATCH '(' name T_VARIABLE ')' '{' inner_statement_list '}'
{ $$ = zend_ast_list_add($1, zend_ast_create(ZEND_AST_CATCH, $4, $5, $8)); }
| catch_list T_CATCH '(' name ')' '{' inner_statement_list '}'
{ $$ = zend_ast_list_add($1, zend_ast_create(ZEND_AST_CATCH, $4, NULL, $7)); }
;

finally_statement:
Expand Down
17 changes: 13 additions & 4 deletions Zend/zend_vm_def.h
Expand Up @@ -4121,7 +4121,7 @@ ZEND_VM_HANDLER(108, ZEND_THROW, CONST|TMP|VAR|CV, ANY)
HANDLE_EXCEPTION();
}

ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, CV, JMP_ADDR)
ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, CV|UNUSED, JMP_ADDR)
{
USE_OPLINE
zend_class_entry *ce, *catch_ce;
Expand Down Expand Up @@ -4160,12 +4160,21 @@ ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, CV, JMP_ADDR)
}

exception = EG(exception);
zval_ptr_dtor(EX_VAR(opline->op2.var));
ZVAL_OBJ(EX_VAR(opline->op2.var), EG(exception));

if (EXPECTED(OP2_TYPE == IS_CV)) {
zval_ptr_dtor(EX_VAR(opline->op2.var));
ZVAL_OBJ(EX_VAR(opline->op2.var), EG(exception));
}

if (UNEXPECTED(EG(exception) != exception)) {
GC_REFCOUNT(EG(exception))++;
if (EXPECTED(OP2_TYPE == IS_CV)) {
GC_REFCOUNT(EG(exception))++;
}
HANDLE_EXCEPTION();
} else {
if (UNEXPECTED(OP2_TYPE == IS_UNUSED)) {
GC_REFCOUNT(EG(exception))--;
}
EG(exception) = NULL;
ZEND_VM_NEXT_OPCODE();
}
Expand Down
76 changes: 72 additions & 4 deletions Zend/zend_vm_execute.h
Expand Up @@ -7430,6 +7430,65 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_VERIFY_RETURN_TYPE_SPEC_CONST_
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
}

static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CATCH_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
zend_class_entry *ce, *catch_ce;
zend_object *exception;

SAVE_OPLINE();
/* Check whether an exception has been thrown, if not, jump over code */
zend_exception_restore();
if (EG(exception) == NULL) {
ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
ZEND_VM_CONTINUE();
}
catch_ce = CACHED_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)));
if (UNEXPECTED(catch_ce == NULL)) {
catch_ce = zend_fetch_class_by_name(Z_STR_P(EX_CONSTANT(opline->op1)), EX_CONSTANT(opline->op1) + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD);

CACHE_PTR(Z_CACHE_SLOT_P(EX_CONSTANT(opline->op1)), catch_ce);
}
ce = EG(exception)->ce;

#ifdef HAVE_DTRACE
if (DTRACE_EXCEPTION_CAUGHT_ENABLED()) {
DTRACE_EXCEPTION_CAUGHT((char *)ce->name);
}
#endif /* HAVE_DTRACE */

if (ce != catch_ce) {
if (!catch_ce || !instanceof_function(ce, catch_ce)) {
if (opline->result.num) {
zend_throw_exception_internal(NULL);
HANDLE_EXCEPTION();
}
ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value);
ZEND_VM_CONTINUE();
}
}

exception = EG(exception);

if (EXPECTED(IS_UNUSED == IS_CV)) {
zval_ptr_dtor(EX_VAR(opline->op2.var));
ZVAL_OBJ(EX_VAR(opline->op2.var), EG(exception));
}

if (UNEXPECTED(EG(exception) != exception)) {
if (EXPECTED(IS_UNUSED == IS_CV)) {
GC_REFCOUNT(EG(exception))++;
}
HANDLE_EXCEPTION();
} else {
if (UNEXPECTED(IS_UNUSED == IS_UNUSED)) {
GC_REFCOUNT(EG(exception))--;
}
EG(exception) = NULL;
ZEND_VM_NEXT_OPCODE();
}
}

static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ADD_ARRAY_ELEMENT_SPEC_CONST_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS)
{
USE_OPLINE
Expand Down Expand Up @@ -9315,12 +9374,21 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CATCH_SPEC_CONST_CV_HANDLER(ZE
}

exception = EG(exception);
zval_ptr_dtor(EX_VAR(opline->op2.var));
ZVAL_OBJ(EX_VAR(opline->op2.var), EG(exception));

if (EXPECTED(IS_CV == IS_CV)) {
zval_ptr_dtor(EX_VAR(opline->op2.var));
ZVAL_OBJ(EX_VAR(opline->op2.var), EG(exception));
}

if (UNEXPECTED(EG(exception) != exception)) {
GC_REFCOUNT(EG(exception))++;
if (EXPECTED(IS_CV == IS_CV)) {
GC_REFCOUNT(EG(exception))++;
}
HANDLE_EXCEPTION();
} else {
if (UNEXPECTED(IS_CV == IS_UNUSED)) {
GC_REFCOUNT(EG(exception))--;
}
EG(exception) = NULL;
ZEND_VM_NEXT_OPCODE();
}
Expand Down Expand Up @@ -57749,7 +57817,7 @@ void zend_init_opcodes_handlers(void)
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
ZEND_CATCH_SPEC_CONST_UNUSED_HANDLER,
ZEND_CATCH_SPEC_CONST_CV_HANDLER,
ZEND_NULL_HANDLER,
ZEND_NULL_HANDLER,
Expand Down

0 comments on commit 255613f

Please sign in to comment.