From 5cdefd07cdcdb43b856bfdd48860ca161057732d Mon Sep 17 00:00:00 2001 From: Marcus Boerger Date: Wed, 7 Jun 2006 09:21:06 +0000 Subject: [PATCH] - MFH Fix issue with interfaces being inherited multiple times --- Zend/zend_API.c | 14 ++----------- Zend/zend_compile.c | 48 +++++++++++++++++++++++++++++++++++---------- Zend/zend_vm_def.h | 2 -- 3 files changed, 40 insertions(+), 24 deletions(-) diff --git a/Zend/zend_API.c b/Zend/zend_API.c index b32b9eb47d..31faa25e7a 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1970,24 +1970,14 @@ ZEND_API zend_class_entry *zend_register_internal_class_ex(zend_class_entry *cla ZEND_API void zend_class_implements(zend_class_entry *class_entry TSRMLS_DC, int num_interfaces, ...) { zend_class_entry *interface_entry; - int ce_num = class_entry->num_interfaces, impl_num; va_list interface_list; va_start(interface_list, num_interfaces); - if (class_entry->type & ZEND_INTERNAL_CLASS) { - class_entry->interfaces = realloc(class_entry->interfaces, sizeof(zend_class_entry*) * (class_entry->num_interfaces+num_interfaces)); - } else { - class_entry->interfaces = erealloc(class_entry->interfaces, sizeof(zend_class_entry*) * (class_entry->num_interfaces+num_interfaces)); - } - while (num_interfaces--) { interface_entry = va_arg(interface_list, zend_class_entry *); - class_entry->interfaces[class_entry->num_interfaces++] = interface_entry; - } - impl_num = class_entry->num_interfaces; - while(ce_num < impl_num) { - zend_do_implement_interface(class_entry, class_entry->interfaces[ce_num++] TSRMLS_CC); + zend_do_implement_interface(class_entry, interface_entry TSRMLS_CC); } + va_end(interface_list); } diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index ce64719f13..117e5e3d7f 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -2247,11 +2247,38 @@ static zend_bool do_inherit_constant_check(HashTable *child_constants_table, zva ZEND_API void zend_do_implement_interface(zend_class_entry *ce, zend_class_entry *iface TSRMLS_DC) { - zend_hash_merge_ex(&ce->constants_table, &iface->constants_table, (copy_ctor_func_t) zval_add_ref, sizeof(zval *), (merge_checker_func_t) do_inherit_constant_check, iface); - zend_hash_merge_ex(&ce->function_table, &iface->function_table, (copy_ctor_func_t) do_inherit_method, sizeof(zend_function), (merge_checker_func_t) do_inherit_method_check, ce); - - do_implement_interface(ce, iface TSRMLS_CC); - zend_do_inherit_interfaces(ce, iface TSRMLS_CC); + zend_uint i, ignore = 0; + zend_uint current_iface_num = ce->num_interfaces; + zend_uint parent_iface_num = ce->parent ? ce->parent->num_interfaces : 0; + + for (i = 0; i < ce->num_interfaces; i++) { + if (ce->interfaces[i] == NULL) { + memmove(ce->interfaces + i, ce->interfaces + i + 1, sizeof(zend_class_entry*) * (--ce->num_interfaces - i)); + i--; + } else if (ce->interfaces[i] == iface) { + if (i < parent_iface_num) { + ignore = 1; + } else { + zend_error(E_COMPILE_ERROR, "Class %s cannot implement previously implemented interface %s", ce->name, iface->name); + } + } + } + if (!ignore) { + if (ce->num_interfaces >= current_iface_num) { + if (ce->type == ZEND_INTERNAL_CLASS) { + ce->interfaces = (zend_class_entry **) realloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num)); + } else { + ce->interfaces = (zend_class_entry **) erealloc(ce->interfaces, sizeof(zend_class_entry *) * (++current_iface_num)); + } + } + ce->interfaces[ce->num_interfaces++] = iface; + + zend_hash_merge_ex(&ce->constants_table, &iface->constants_table, (copy_ctor_func_t) zval_add_ref, sizeof(zval *), (merge_checker_func_t) do_inherit_constant_check, iface); + zend_hash_merge_ex(&ce->function_table, &iface->function_table, (copy_ctor_func_t) do_inherit_method, sizeof(zend_function), (merge_checker_func_t) do_inherit_method_check, ce); + + do_implement_interface(ce, iface TSRMLS_CC); + zend_do_inherit_interfaces(ce, iface TSRMLS_CC); + } } @@ -2812,11 +2839,6 @@ void zend_do_end_class_declaration(znode *class_token, znode *parent_token TSRML ce->line_end = zend_get_compiled_lineno(TSRMLS_C); - /* Inherit interfaces */ - if (ce->num_interfaces > 0) { - ce->interfaces = (zend_class_entry **) emalloc(sizeof(zend_class_entry *)*ce->num_interfaces); - memset(ce->interfaces, 0, sizeof(zend_class_entry *)*ce->num_interfaces); - } if (!(ce->ce_flags & (ZEND_ACC_INTERFACE|ZEND_ACC_EXPLICIT_ABSTRACT_CLASS)) && ((parent_token->op_type != IS_UNUSED) || (ce->num_interfaces > 0))) { zend_verify_abstract_class(ce TSRMLS_CC); @@ -2824,6 +2846,12 @@ void zend_do_end_class_declaration(znode *class_token, znode *parent_token TSRML do_verify_abstract_class(TSRMLS_C); } } + /* Inherit interfaces; reset number to zero, we need it for above check and + * will restore it during actual implementation. */ + if (ce->num_interfaces > 0) { + ce->interfaces = NULL; + ce->num_interfaces = 0; + } CG(active_class_entry) = NULL; } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 5295320de9..fe07011bf0 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -3627,8 +3627,6 @@ ZEND_VM_HANDLER(144, ZEND_ADD_INTERFACE, ANY, ANY) zend_error_noreturn(E_ERROR, "%s cannot implement %s - it is not an interface", ce->name, iface->name); } - ce->interfaces[opline->extended_value] = iface; - zend_do_implement_interface(ce, iface TSRMLS_CC); ZEND_VM_NEXT_OPCODE(); -- 2.40.0