From: Stefan Marr Date: Sun, 4 Mar 2012 18:26:11 +0000 (+0000) Subject: Fixed Bug #60717 (Order of traits in use statement can cause a fatal error) X-Git-Tag: php-5.5.0alpha1~474 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=0bb85e4b91a21635d07ee2ae504ca2a4abc0d571;p=php Fixed Bug #60717 (Order of traits in use statement can cause a fatal error) # Compatibility is now correctly checked in both directions. # Introduced helper method for the test. --- diff --git a/Zend/tests/traits/bug60717.phpt b/Zend/tests/traits/bug60717.phpt new file mode 100644 index 0000000000..bf3adb1c88 --- /dev/null +++ b/Zend/tests/traits/bug60717.phpt @@ -0,0 +1,73 @@ +--TEST-- +Bug #60717 (Order of traits in use statement can cause unexpected unresolved abstract method) +--FILE-- + --EXPECTF-- -Fatal error: Declaration of THelloB::hello() must be compatible with THelloA::hello($a) in %s on line %d \ No newline at end of file +Fatal error: Declaration of THelloA::hello($a) must be compatible with THelloB::hello() in %s on line %d \ No newline at end of file diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 4c2a740841..a7b130d8fd 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3623,6 +3623,18 @@ ZEND_API void zend_do_implement_trait(zend_class_entry *ce, zend_class_entry *tr } /* }}} */ +static zend_bool zend_traits_method_compatibility_check(zend_function *fn, zend_function *other_fn TSRMLS_DC) /* {{{ */ +{ + zend_uint fn_flags = fn->common.scope->ce_flags; + zend_uint other_flags = other_fn->common.scope->ce_flags; + + return zend_do_perform_implementation_check(fn, other_fn TSRMLS_CC) + && zend_do_perform_implementation_check(other_fn, fn TSRMLS_CC) + && ((fn_flags & ZEND_ACC_FINAL) == (other_flags & ZEND_ACC_FINAL)) /* equal final qualifier */ + && ((fn_flags & ZEND_ACC_STATIC)== (other_flags & ZEND_ACC_STATIC)); /* equal static qualifier */ +} +/* }}} */ + static int zend_traits_merge_functions(zend_function *fn TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */ { size_t current; @@ -3645,22 +3657,16 @@ static int zend_traits_merge_functions(zend_function *fn TSRMLS_DC, int num_args if (i == current) { continue; /* just skip this, cause its the table this function is applied on */ } - + if (zend_hash_quick_find(function_tables[i], hash_key->arKey, hash_key->nKeyLength, hash_key->h, (void **)&other_trait_fn) == SUCCESS) { /* if it is an abstract method, there is no collision */ if (other_trait_fn->common.fn_flags & ZEND_ACC_ABSTRACT) { /* Make sure they are compatible */ - if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) { - /* In case both are abstract, just check prototype, but need to do that in both directions */ - if ( !zend_do_perform_implementation_check(fn, other_trait_fn TSRMLS_CC) - || !zend_do_perform_implementation_check(other_trait_fn, fn TSRMLS_CC)) { - zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s", //ZEND_FN_SCOPE_NAME(fn), fn->common.function_name, //::%s() - zend_get_function_declaration(fn TSRMLS_CC), - zend_get_function_declaration(other_trait_fn TSRMLS_CC)); - } - } else { - /* otherwise, do the full check */ - do_inheritance_check_on_method(fn, other_trait_fn TSRMLS_CC); + /* In case both are abstract, just check prototype, but need to do that in both directions */ + if (!zend_traits_method_compatibility_check(fn, other_trait_fn TSRMLS_CC)) { + zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s", + zend_get_function_declaration(fn TSRMLS_CC), + zend_get_function_declaration(other_trait_fn TSRMLS_CC)); } /* we can savely free and remove it from other table */ @@ -3672,7 +3678,11 @@ static int zend_traits_merge_functions(zend_function *fn TSRMLS_DC, int num_args if (fn->common.fn_flags & ZEND_ACC_ABSTRACT) { /* Make sure they are compatible. Here, we already know other_trait_fn cannot be abstract, full check ok. */ - do_inheritance_check_on_method(other_trait_fn, fn TSRMLS_CC); + if (!zend_traits_method_compatibility_check(fn, other_trait_fn TSRMLS_CC)) { + zend_error(E_COMPILE_ERROR, "Declaration of %s must be compatible with %s", + zend_get_function_declaration(fn TSRMLS_CC), + zend_get_function_declaration(other_trait_fn TSRMLS_CC)); + } /* just mark as solved, will be added if its own trait is processed */ abstract_solved = 1;