diff --git a/Zend/tests/anon/bug-71678-closure.phpt b/Zend/tests/anon/bug-71678-closure.phpt new file mode 100755 index 0000000000000..daefe169a33a7 --- /dev/null +++ b/Zend/tests/anon/bug-71678-closure.phpt @@ -0,0 +1,51 @@ +--TEST-- +Bug #71678 class() extends self/parent/static inside closures +--FILE-- +bindTo($ext, $ext)(); +var_dump($parent, get_parent_class(get_class($parent))); + +$self= Test::newSelf()->bindTo($ext, $ext)(); +var_dump($self, get_parent_class(get_class($self))); + +$self= Test::newStatic()->bindTo($ext, $ext)(); +var_dump($self, get_parent_class(get_class($self))); +--EXPECTF-- +object(class@%s)#%d (0) { +} +string(4) "Test" +object(class@%s)#%d (0) { +} +string(9) "Extension" +object(class@%s)#%d (0) { +} +string(9) "Extension" \ No newline at end of file diff --git a/Zend/tests/anon/bug-71678-trait.phpt b/Zend/tests/anon/bug-71678-trait.phpt new file mode 100755 index 0000000000000..243c2263888bd --- /dev/null +++ b/Zend/tests/anon/bug-71678-trait.phpt @@ -0,0 +1,54 @@ +--TEST-- +Bug #71678 class() extends self/parent/static inside traits +--FILE-- + +--EXPECTF-- +Fatal error: Cannot use 'static' as class name as it is reserved in %s on line %d diff --git a/Zend/tests/lsb_006.phpt b/Zend/tests/lsb_006.phpt deleted file mode 100644 index 84cd22a99572d..0000000000000 --- a/Zend/tests/lsb_006.phpt +++ /dev/null @@ -1,13 +0,0 @@ ---TEST-- -ZE2 Late Static Binding ensuring extending 'static' is not allowed ---FILE-- - -==DONE== ---EXPECTF-- -Parse error: %s error,%sexpecting %s in %s on line %d - diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 7cf00a0ebe099..9884a399a0c2f 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -1974,7 +1974,8 @@ static void zend_find_live_range(zend_op *opline, zend_uchar type, uint32_t var) def->opcode == ZEND_DECLARE_INHERITED_CLASS || def->opcode == ZEND_DECLARE_INHERITED_CLASS_DELAYED || def->opcode == ZEND_DECLARE_ANON_CLASS || - def->opcode == ZEND_DECLARE_ANON_INHERITED_CLASS) { + def->opcode == ZEND_DECLARE_ANON_INHERITED_CLASS || + def->opcode == ZEND_DECLARE_ANON_NEW_CLASS) { /* classes don't have to be destroyed */ break; } else if (def->opcode == ZEND_FAST_CALL) { @@ -5571,6 +5572,7 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */ zend_string *name, *lcname, *import_name = NULL; zend_class_entry *ce = zend_arena_alloc(&CG(arena), sizeof(zend_class_entry)); zend_op *opline; + uint32_t opcode; znode declare_node, extends_node; zend_class_entry *original_ce = CG(active_class_entry); @@ -5602,9 +5604,11 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */ } name = zend_new_interned_string(name); + opcode = ZEND_DECLARE_CLASS; } else { name = zend_generate_anon_class_name(decl->lex_pos); lcname = zend_string_tolower(name); + opcode = ZEND_DECLARE_ANON_CLASS; } lcname = zend_new_interned_string(lcname); @@ -5628,7 +5632,17 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */ } if (extends_ast) { - if (!zend_is_const_default_class_ref(extends_ast)) { + uint32_t fetch_type = zend_get_class_fetch_type_ast(extends_ast); + + if (decl->flags & ZEND_ACC_ANON_CLASS) { + if (ZEND_FETCH_CLASS_STATIC == fetch_type) { + opcode = ZEND_DECLARE_ANON_NEW_CLASS; + } else { + opcode = ZEND_DECLARE_ANON_INHERITED_CLASS; + } + } else if (ZEND_FETCH_CLASS_DEFAULT == fetch_type) { + opcode = ZEND_DECLARE_INHERITED_CLASS; + } else { zend_string *extends_name = zend_ast_get_str(extends_ast); zend_error_noreturn(E_COMPILE_ERROR, "Cannot use '%s' as class name as it is reserved", ZSTR_VAL(extends_name)); @@ -5639,6 +5653,11 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */ opline = get_next_op(CG(active_op_array)); zend_make_var_result(&declare_node, opline); + opline->opcode = opcode; + + if (extends_ast) { + SET_NODE(opline->op2, &extends_node); + } GET_NODE(&FC(implementing_class), opline->result); @@ -5646,24 +5665,10 @@ void zend_compile_class_decl(zend_ast *ast) /* {{{ */ LITERAL_STR(opline->op1, lcname); if (decl->flags & ZEND_ACC_ANON_CLASS) { - if (extends_ast) { - opline->opcode = ZEND_DECLARE_ANON_INHERITED_CLASS; - SET_NODE(opline->op2, &extends_node); - } else { - opline->opcode = ZEND_DECLARE_ANON_CLASS; - } - zend_hash_update_ptr(CG(class_table), lcname, ce); } else { zend_string *key; - if (extends_ast) { - opline->opcode = ZEND_DECLARE_INHERITED_CLASS; - SET_NODE(opline->op2, &extends_node); - } else { - opline->opcode = ZEND_DECLARE_CLASS; - } - key = zend_build_runtime_definition_key(lcname, decl->lex_pos); /* RTD key is placed after lcname literal in op1 */ zend_add_literal_string(CG(active_op_array), &key); diff --git a/Zend/zend_language_parser.y b/Zend/zend_language_parser.y index fd45f6275a1ac..92a8a59ab7c23 100644 --- a/Zend/zend_language_parser.y +++ b/Zend/zend_language_parser.y @@ -522,7 +522,7 @@ interface_declaration_statement: extends_from: /* empty */ { $$ = NULL; } - | T_EXTENDS name { $$ = $2; } + | T_EXTENDS class_name { $$ = $2; } ; interface_extends_list: diff --git a/Zend/zend_opcode.c b/Zend/zend_opcode.c index ab67a88272102..4afcf6fc027fa 100644 --- a/Zend/zend_opcode.c +++ b/Zend/zend_opcode.c @@ -687,6 +687,7 @@ ZEND_API int pass_two(zend_op_array *op_array) break; case ZEND_DECLARE_ANON_CLASS: case ZEND_DECLARE_ANON_INHERITED_CLASS: + case ZEND_DECLARE_ANON_NEW_CLASS: case ZEND_CATCH: case ZEND_FE_FETCH_R: case ZEND_FE_FETCH_RW: diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index de67318bed16c..3530aa3f94d39 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -7118,6 +7118,46 @@ ZEND_VM_HANDLER(172, ZEND_DECLARE_ANON_INHERITED_CLASS, ANY, VAR, JMP_ADDR) ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +ZEND_VM_HANDLER(184, ZEND_DECLARE_ANON_NEW_CLASS, ANY, VAR, JMP_ADDR) +{ + zend_class_entry *ce, *parent_ce, *result_ce; + zend_string *name, *lc_name; + size_t name_length; + USE_OPLINE + + SAVE_OPLINE(); + + ce = zend_hash_find_ptr(EG(class_table), Z_STR_P(EX_CONSTANT(opline->op1))); + parent_ce = Z_CE_P(EX_VAR(opline->op2.var)); + + /* Create unique name by appending what `static` resolved to */ + name_length = ZSTR_LEN(ce->name) + ZSTR_LEN(parent_ce->name); + name = zend_string_alloc(name_length, 1); + memcpy(ZSTR_VAL(name), ZSTR_VAL(ce->name), ZSTR_LEN(ce->name)); + memcpy(ZSTR_VAL(name) + ZSTR_LEN(ce->name), ZSTR_VAL(parent_ce->name), ZSTR_LEN(parent_ce->name)); + + lc_name = zend_string_tolower(name); + result_ce = zend_hash_find_ptr(EG(class_table), lc_name); + if (NULL == result_ce) { + + /* Copy class */ + result_ce = malloc(sizeof(zend_class_entry)); + *result_ce = *ce; + result_ce->name = zend_string_copy(name); + + zend_do_inheritance(result_ce, parent_ce); + zend_hash_add_ptr(EG(class_table), lc_name, result_ce); + } + + zend_string_release(name); + zend_string_release(lc_name); + + Z_CE_P(EX_VAR(opline->result.var)) = result_ce; + ZEND_ASSERT(result_ce != NULL); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + ZEND_VM_HANDLER(141, ZEND_DECLARE_FUNCTION, ANY, ANY) { USE_OPLINE diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 40d75a7d2704c..cbc3bd84d9451 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -2645,6 +2645,46 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_ANON_INHERITED_CLASS_S ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_DECLARE_ANON_NEW_CLASS_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + zend_class_entry *ce, *parent_ce, *result_ce; + zend_string *name, *lc_name; + size_t name_length; + USE_OPLINE + + SAVE_OPLINE(); + + ce = zend_hash_find_ptr(EG(class_table), Z_STR_P(EX_CONSTANT(opline->op1))); + parent_ce = Z_CE_P(EX_VAR(opline->op2.var)); + + /* Create unique name by appending what `static` resolved to */ + name_length = ZSTR_LEN(ce->name) + ZSTR_LEN(parent_ce->name); + name = zend_string_alloc(name_length, 1); + memcpy(ZSTR_VAL(name), ZSTR_VAL(ce->name), ZSTR_LEN(ce->name)); + memcpy(ZSTR_VAL(name) + ZSTR_LEN(ce->name), ZSTR_VAL(parent_ce->name), ZSTR_LEN(parent_ce->name)); + + lc_name = zend_string_tolower(name); + result_ce = zend_hash_find_ptr(EG(class_table), lc_name); + if (NULL == result_ce) { + + /* Copy class */ + result_ce = malloc(sizeof(zend_class_entry)); + *result_ce = *ce; + result_ce->name = zend_string_copy(name); + + zend_do_inheritance(result_ce, parent_ce); + zend_hash_add_ptr(EG(class_table), lc_name, result_ce); + } + + zend_string_release(name); + zend_string_release(lc_name); + + Z_CE_P(EX_VAR(opline->result.var)) = result_ce; + ZEND_ASSERT(result_ce != NULL); + + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_SPEC_UNUSED_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -57139,6 +57179,11 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, + ZEND_DECLARE_ANON_NEW_CLASS_SPEC_VAR_HANDLER, + ZEND_NULL_HANDLER, + ZEND_NULL_HANDLER, ZEND_NULL_HANDLER }; static const uint32_t specs[] = { @@ -57183,7 +57228,7 @@ void zend_init_opcodes_handlers(void) 776 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_RETVAL, 826 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 851 | SPEC_RULE_OP1, - 2920, + 2925, 856, 857 | SPEC_RULE_OP1, 862 | SPEC_RULE_OP1, @@ -57191,9 +57236,9 @@ void zend_init_opcodes_handlers(void) 872 | SPEC_RULE_OP1, 877 | SPEC_RULE_OP1, 882 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 2920, - 2920, - 2920, + 2925, + 2925, + 2925, 907 | SPEC_RULE_OP1, 912 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 937 | SPEC_RULE_OP1 | SPEC_RULE_OP2, @@ -57242,7 +57287,7 @@ void zend_init_opcodes_handlers(void) 1646 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 1671 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 1696 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 2920, + 2925, 1721, 1722, 1723, @@ -57326,7 +57371,8 @@ void zend_init_opcodes_handlers(void) 2845 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 2870 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 2895 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 2920 + 2920 | SPEC_RULE_OP2, + 2925 }; zend_opcode_handlers = labels; zend_spec_handlers = specs; diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index 37ba8d411ba34..a47ea5ea06377 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -21,7 +21,7 @@ #include #include -static const char *zend_vm_opcodes_names[184] = { +static const char *zend_vm_opcodes_names[185] = { "ZEND_NOP", "ZEND_ADD", "ZEND_SUB", @@ -206,9 +206,10 @@ static const char *zend_vm_opcodes_names[184] = { "ZEND_FETCH_CLASS_CONSTANT", "ZEND_BIND_LEXICAL", "ZEND_BIND_STATIC", + "ZEND_DECLARE_ANON_NEW_CLASS", }; -static uint32_t zend_vm_opcodes_flags[184] = { +static uint32_t zend_vm_opcodes_flags[185] = { 0x00000000, 0x00000707, 0x00000707, @@ -393,6 +394,7 @@ static uint32_t zend_vm_opcodes_flags[184] = { 0x00000373, 0x00100101, 0x00100301, + 0x03000100, }; ZEND_API const char* zend_get_opcode_name(zend_uchar opcode) { diff --git a/Zend/zend_vm_opcodes.h b/Zend/zend_vm_opcodes.h index 768dbb87c884e..0e43d0cc6c0ba 100644 --- a/Zend/zend_vm_opcodes.h +++ b/Zend/zend_vm_opcodes.h @@ -246,7 +246,8 @@ END_EXTERN_C() #define ZEND_FETCH_CLASS_CONSTANT 181 #define ZEND_BIND_LEXICAL 182 #define ZEND_BIND_STATIC 183 +#define ZEND_DECLARE_ANON_NEW_CLASS 184 -#define ZEND_VM_LAST_OPCODE 183 +#define ZEND_VM_LAST_OPCODE 184 #endif