gron Sun, 04 Mar 2012 18:26:11 +0000 Revision: http://svn.php.net/viewvc?view=revision&revision=323891
Log: 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. Bug: https://bugs.php.net/60717 (Assigned) Order of traits in use statement can cause a fatal error Changed paths: U php/php-src/branches/PHP_5_4/NEWS A php/php-src/branches/PHP_5_4/Zend/tests/traits/bug60717.phpt U php/php-src/branches/PHP_5_4/Zend/tests/traits/bugs/abstract-methods06.phpt U php/php-src/branches/PHP_5_4/Zend/zend_compile.c A php/php-src/trunk/Zend/tests/traits/bug60717.phpt U php/php-src/trunk/Zend/tests/traits/bugs/abstract-methods06.phpt U php/php-src/trunk/Zend/zend_compile.c
Modified: php/php-src/branches/PHP_5_4/NEWS =================================================================== --- php/php-src/branches/PHP_5_4/NEWS 2012-03-04 17:21:16 UTC (rev 323890) +++ php/php-src/branches/PHP_5_4/NEWS 2012-03-04 18:26:11 UTC (rev 323891) @@ -14,6 +14,8 @@ - Core: . Fixed bug #60573 (type hinting with "self" keyword causes weird errors). (Laruence) + . Fixed bug #60717 (Order of traits in use statement can cause a fatal + error). (Stefan) . Fixed bug #60801 (strpbrk() mishandles NUL byte). (Adam) . Fixed bug #60978 (exit code incorrect). (Laruence) . Fixed bug #61000 (Exceeding max nesting level doesn't delete numerical Added: php/php-src/branches/PHP_5_4/Zend/tests/traits/bug60717.phpt =================================================================== --- php/php-src/branches/PHP_5_4/Zend/tests/traits/bug60717.phpt (rev 0) +++ php/php-src/branches/PHP_5_4/Zend/tests/traits/bug60717.phpt 2012-03-04 18:26:11 UTC (rev 323891) @@ -0,0 +1,73 @@ +--TEST-- +Bug #60717 (Order of traits in use statement can cause unexpected unresolved abstract method) +--FILE-- +<?php + +namespace HTML +{ + interface Helper + { + function text($text); + function attributes(array $attributes = null); + function textArea(array $attributes = null, $value); + } + + trait TextUTF8 + { + function text($text) {} + } + + trait TextArea + { + function textArea(array $attributes = null, $value) {} + abstract function attributes(array $attributes = null); + abstract function text($text); + } + + trait HTMLAttributes + { + function attributes(array $attributes = null) { } + abstract function text($text); + } + + class HTMLHelper implements Helper + { + use TextArea, HTMLAttributes, TextUTF8; + } + + class HTMLHelper2 implements Helper + { + use TextArea, TextUTF8, HTMLAttributes; + } + + class HTMLHelper3 implements Helper + { + use HTMLAttributes, TextArea, TextUTF8; + } + + class HTMLHelper4 implements Helper + { + use HTMLAttributes, TextUTF8, TextArea; + } + + class HTMLHelper5 implements Helper + { + use TextUTF8, TextArea, HTMLAttributes; + } + + class HTMLHelper6 implements Helper + { + use TextUTF8, HTMLAttributes, TextArea; + } + + $o = new HTMLHelper; + $o = new HTMLHelper2; + $o = new HTMLHelper3; + $o = new HTMLHelper4; + $o = new HTMLHelper5; + $o = new HTMLHelper6; + echo 'Done'; +} + +--EXPECT-- +Done Modified: php/php-src/branches/PHP_5_4/Zend/tests/traits/bugs/abstract-methods06.phpt =================================================================== --- php/php-src/branches/PHP_5_4/Zend/tests/traits/bugs/abstract-methods06.phpt 2012-03-04 17:21:16 UTC (rev 323890) +++ php/php-src/branches/PHP_5_4/Zend/tests/traits/bugs/abstract-methods06.phpt 2012-03-04 18:26:11 UTC (rev 323891) @@ -23,4 +23,4 @@ ?> --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 Modified: php/php-src/branches/PHP_5_4/Zend/zend_compile.c =================================================================== --- php/php-src/branches/PHP_5_4/Zend/zend_compile.c 2012-03-04 17:21:16 UTC (rev 323890) +++ php/php-src/branches/PHP_5_4/Zend/zend_compile.c 2012-03-04 18:26:11 UTC (rev 323891) @@ -3623,6 +3623,18 @@ } /* }}} */ +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 @@ 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 @@ 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; Added: php/php-src/trunk/Zend/tests/traits/bug60717.phpt =================================================================== --- php/php-src/trunk/Zend/tests/traits/bug60717.phpt (rev 0) +++ php/php-src/trunk/Zend/tests/traits/bug60717.phpt 2012-03-04 18:26:11 UTC (rev 323891) @@ -0,0 +1,73 @@ +--TEST-- +Bug #60717 (Order of traits in use statement can cause unexpected unresolved abstract method) +--FILE-- +<?php + +namespace HTML +{ + interface Helper + { + function text($text); + function attributes(array $attributes = null); + function textArea(array $attributes = null, $value); + } + + trait TextUTF8 + { + function text($text) {} + } + + trait TextArea + { + function textArea(array $attributes = null, $value) {} + abstract function attributes(array $attributes = null); + abstract function text($text); + } + + trait HTMLAttributes + { + function attributes(array $attributes = null) { } + abstract function text($text); + } + + class HTMLHelper implements Helper + { + use TextArea, HTMLAttributes, TextUTF8; + } + + class HTMLHelper2 implements Helper + { + use TextArea, TextUTF8, HTMLAttributes; + } + + class HTMLHelper3 implements Helper + { + use HTMLAttributes, TextArea, TextUTF8; + } + + class HTMLHelper4 implements Helper + { + use HTMLAttributes, TextUTF8, TextArea; + } + + class HTMLHelper5 implements Helper + { + use TextUTF8, TextArea, HTMLAttributes; + } + + class HTMLHelper6 implements Helper + { + use TextUTF8, HTMLAttributes, TextArea; + } + + $o = new HTMLHelper; + $o = new HTMLHelper2; + $o = new HTMLHelper3; + $o = new HTMLHelper4; + $o = new HTMLHelper5; + $o = new HTMLHelper6; + echo 'Done'; +} + +--EXPECT-- +Done Modified: php/php-src/trunk/Zend/tests/traits/bugs/abstract-methods06.phpt =================================================================== --- php/php-src/trunk/Zend/tests/traits/bugs/abstract-methods06.phpt 2012-03-04 17:21:16 UTC (rev 323890) +++ php/php-src/trunk/Zend/tests/traits/bugs/abstract-methods06.phpt 2012-03-04 18:26:11 UTC (rev 323891) @@ -23,4 +23,4 @@ ?> --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 Modified: php/php-src/trunk/Zend/zend_compile.c =================================================================== --- php/php-src/trunk/Zend/zend_compile.c 2012-03-04 17:21:16 UTC (rev 323890) +++ php/php-src/trunk/Zend/zend_compile.c 2012-03-04 18:26:11 UTC (rev 323891) @@ -3623,6 +3623,18 @@ } /* }}} */ +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 @@ 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 @@ 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;
-- PHP CVS Mailing List (http://www.php.net/) To unsubscribe, visit: http://www.php.net/unsub.php