Skip to content

Instantly share code, notes, and snippets.

@JoostK
Created June 24, 2013 21:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JoostK/5853743 to your computer and use it in GitHub Desktop.
Save JoostK/5853743 to your computer and use it in GitHub Desktop.
PHP Anonymous catches patch
diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c
index faef3a9..ce675b1 100644
--- a/Zend/zend_compile.c
+++ b/Zend/zend_compile.c
@@ -2848,7 +2848,7 @@ void zend_do_mark_last_catch(const znode *first_catch, const znode *last_additio
{
CG(active_op_array)->last--;
zend_do_if_end(TSRMLS_C);
- if (last_additional_catch->u.op.opline_num == -1) {
+ if (!last_additional_catch || last_additional_catch->u.op.opline_num == -1) {
CG(active_op_array)->opcodes[first_catch->u.op.opline_num].result.num = 1;
CG(active_op_array)->opcodes[first_catch->u.op.opline_num].extended_value = get_next_op_number(CG(active_op_array));
} else {
@@ -2894,12 +2894,14 @@ void zend_do_begin_catch(znode *catch_token, znode *class_name, znode *catch_var
zend_op *opline;
znode catch_class;
- if (class_name->op_type == IS_CONST &&
- ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) {
- zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC);
- catch_class = *class_name;
- } else {
- zend_error(E_COMPILE_ERROR, "Bad class name in the catch statement");
+ if (class_name) {
+ if (class_name->op_type == IS_CONST &&
+ ZEND_FETCH_CLASS_DEFAULT == zend_get_class_fetch_type(Z_STRVAL(class_name->u.constant), Z_STRLEN(class_name->u.constant))) {
+ zend_resolve_class_name(class_name, ZEND_FETCH_CLASS_GLOBAL, 1 TSRMLS_CC);
+ catch_class = *class_name;
+ } else {
+ zend_error(E_COMPILE_ERROR, "Bad class name in the catch statement");
+ }
}
catch_op_number = get_next_op_number(CG(active_op_array));
@@ -2909,11 +2911,22 @@ void zend_do_begin_catch(znode *catch_token, znode *class_name, znode *catch_var
opline = get_next_op(CG(active_op_array) TSRMLS_CC);
opline->opcode = ZEND_CATCH;
- opline->op1_type = IS_CONST;
- opline->op1.constant = zend_add_class_name_literal(CG(active_op_array), &catch_class.u.constant TSRMLS_CC);
- opline->op2_type = IS_CV;
- opline->op2.var = lookup_cv(CG(active_op_array), catch_var->u.constant.value.str.val, catch_var->u.constant.value.str.len, 0 TSRMLS_CC);
- Z_STRVAL(catch_var->u.constant) = (char*)CG(active_op_array)->vars[opline->op2.var].name;
+
+ if (class_name) {
+ opline->op1_type = IS_CONST;
+ opline->op1.constant = zend_add_class_name_literal(CG(active_op_array), &catch_class.u.constant TSRMLS_CC);
+ } else {
+ opline->op1_type = IS_UNUSED;
+ }
+
+ if (!catch_var || catch_var->op_type == IS_UNUSED) {
+ opline->op2_type = IS_UNUSED;
+ } else {
+ opline->op2_type = IS_CV;
+ opline->op2.var = lookup_cv(CG(active_op_array), catch_var->u.constant.value.str.val, catch_var->u.constant.value.str.len, 0 TSRMLS_CC);
+ Z_STRVAL(catch_var->u.constant) = (char*)CG(active_op_array)->vars[opline->op2.var].name;
+ }
+
opline->result.num = 0; /* 1 means it's the last catch in the block */
catch_token->u.op.opline_num = catch_op_number;
diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y
index 6a9a24a..3c13752 100644
--- a/Zend/zend_language_parser.y
+++ b/Zend/zend_language_parser.y
@@ -328,19 +328,31 @@ unticked_statement:
catch_statement:
/* empty */ { $$.op_type = IS_UNUSED; }
- | T_CATCH '(' { zend_initialize_try_catch_element(&$1 TSRMLS_CC); }
+ | T_CATCH '(' { zend_initialize_try_catch_element(&$1 TSRMLS_CC); }
fully_qualified_class_name { zend_do_first_catch(&$2 TSRMLS_CC); }
- T_VARIABLE ')' { zend_do_begin_catch(&$1, &$4, &$6, &$2 TSRMLS_CC); }
+ catch_variable ')' { zend_do_begin_catch(&$1, &$4, &$6, &$2 TSRMLS_CC); }
'{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
additional_catches { zend_do_mark_last_catch(&$2, &$13 TSRMLS_CC); $$ = $1;}
+ | T_CATCH { zend_initialize_try_catch_element(&$1 TSRMLS_CC); }
+ '{' { zend_do_first_catch(&$3 TSRMLS_CC); zend_do_begin_catch(&$1, NULL, NULL, &$3 TSRMLS_CC); }
+ inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
+ { zend_do_mark_last_catch(&$3, NULL TSRMLS_CC); $$ = $1;}
+;
finally_statement:
/* empty */ { $$.op_type = IS_UNUSED; }
| T_FINALLY { zend_do_finally(&$1 TSRMLS_CC); } '{' inner_statement_list '}' { $$ = $1; }
;
+catch_variable:
+ T_VARIABLE { $$ = $1; }
+ | /* empty */ { $$.op_type = IS_UNUSED; }
+;
+
additional_catches:
non_empty_additional_catches { $$ = $1; }
+ | non_empty_additional_catches anonymous_catch { $$ = $2; }
+ | anonymous_catch { $$ = $1; }
| /* empty */ { $$.u.op.opline_num = -1; }
;
@@ -350,7 +362,11 @@ non_empty_additional_catches:
;
additional_catch:
- T_CATCH '(' fully_qualified_class_name { $$.u.op.opline_num = get_next_op_number(CG(active_op_array)); } T_VARIABLE ')' { zend_do_begin_catch(&$1, &$3, &$5, NULL TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
+ T_CATCH '(' fully_qualified_class_name { $$.u.op.opline_num = get_next_op_number(CG(active_op_array)); } catch_variable ')' { zend_do_begin_catch(&$1, &$3, &$5, NULL TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
+;
+
+anonymous_catch:
+ T_CATCH { zend_do_begin_catch(&$1, NULL, NULL, NULL TSRMLS_CC); } '{' inner_statement_list '}' { zend_do_end_catch(&$1 TSRMLS_CC); }
;
unset_variables:
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -2986,7 +2986,7 @@ ZEND_VM_HANDLER(108, ZEND_THROW, CONST|TMP|VAR|CV, ANY)
HANDLE_EXCEPTION();
}
-ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, CV)
+ZEND_VM_HANDLER(107, ZEND_CATCH, CONST|UNUSED, CV|UNUSED)
{
USE_OPLINE
zend_class_entry *ce, *catch_ce;
@@ -2999,44 +2999,51 @@ ZEND_VM_HANDLER(107, ZEND_CATCH, CONST, CV)
ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->extended_value]);
ZEND_VM_CONTINUE(); /* CHECK_ME */
}
- if (CACHED_PTR(opline->op1.literal->cache_slot)) {
- catch_ce = CACHED_PTR(opline->op1.literal->cache_slot);
- } else {
- catch_ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC);
- CACHE_PTR(opline->op1.literal->cache_slot, catch_ce);
- }
- ce = Z_OBJCE_P(EG(exception));
+ if (OP1_TYPE != IS_UNUSED) {
+ if (CACHED_PTR(opline->op1.literal->cache_slot)) {
+ catch_ce = CACHED_PTR(opline->op1.literal->cache_slot);
+ } else {
+ catch_ce = zend_fetch_class_by_name(Z_STRVAL_P(opline->op1.zv), Z_STRLEN_P(opline->op1.zv), opline->op1.literal + 1, ZEND_FETCH_CLASS_NO_AUTOLOAD TSRMLS_CC);
+
+ CACHE_PTR(opline->op1.literal->cache_slot, catch_ce);
+ }
+ ce = Z_OBJCE_P(EG(exception));
#ifdef HAVE_DTRACE
- if (DTRACE_EXCEPTION_CAUGHT_ENABLED()) {
- DTRACE_EXCEPTION_CAUGHT(ce->name);
- }
+ if (DTRACE_EXCEPTION_CAUGHT_ENABLED()) {
+ DTRACE_EXCEPTION_CAUGHT(ce->name);
+ }
#endif /* HAVE_DTRACE */
- if (ce != catch_ce) {
- if (!instanceof_function(ce, catch_ce TSRMLS_CC)) {
- if (opline->result.num) {
- zend_throw_exception_internal(NULL TSRMLS_CC);
- HANDLE_EXCEPTION();
+ if (ce != catch_ce) {
+ if (!instanceof_function(ce, catch_ce TSRMLS_CC)) {
+ if (opline->result.num) {
+ zend_throw_exception_internal(NULL TSRMLS_CC);
+ HANDLE_EXCEPTION();
+ }
+ ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->extended_value]);
+ ZEND_VM_CONTINUE(); /* CHECK_ME */
}
- ZEND_VM_SET_OPCODE(&EX(op_array)->opcodes[opline->extended_value]);
- ZEND_VM_CONTINUE(); /* CHECK_ME */
}
}
exception = EG(exception);
- if (!EG(active_symbol_table)) {
- if (EX_CV(opline->op2.var)) {
- zval_ptr_dtor(EX_CV(opline->op2.var));
+
+ if (OP2_TYPE != IS_UNUSED) {
+ if (!EG(active_symbol_table)) {
+ if (EX_CV(opline->op2.var)) {
+ zval_ptr_dtor(EX_CV(opline->op2.var));
+ }
+ EX_CV(opline->op2.var) = (zval**)EX_CV_NUM(execute_data, EX(op_array)->last_var + opline->op2.var);
+ *EX_CV(opline->op2.var) = EG(exception);
+ } else {
+ zend_compiled_variable *cv = &CV_DEF_OF(opline->op2.var);
+ zend_hash_quick_update(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value,
+ &EG(exception), sizeof(zval *), (void**)&EX_CV(opline->op2.var));
}
- EX_CV(opline->op2.var) = (zval**)EX_CV_NUM(execute_data, EX(op_array)->last_var + opline->op2.var);
- *EX_CV(opline->op2.var) = EG(exception);
- } else {
- zend_compiled_variable *cv = &CV_DEF_OF(opline->op2.var);
- zend_hash_quick_update(EG(active_symbol_table), cv->name, cv->name_len+1, cv->hash_value,
- &EG(exception), sizeof(zval *), (void**)&EX_CV(opline->op2.var));
}
+
if (UNEXPECTED(EG(exception) != exception)) {
Z_ADDREF_P(EG(exception));
HANDLE_EXCEPTION();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment