diff --git a/NEWS b/NEWS index a09aafc0b84..966fbf97a1c 100644 --- a/NEWS +++ b/NEWS @@ -49,6 +49,9 @@ PHP NEWS . Added get_error_handler(), get_exception_handler() functions. (Arnaud) . Fixed bug GH-15753 and GH-16198 (Bind traits before parent class). (ilutov) . Added support for casts in constant expressions. (nielsdos) + . Fixed bugs GH-17711 and GH-18022 (Infinite recursion on deprecated attribute + evaluation) and GH-18464 (Recursion protection for deprecation constants not + released on bailout). (DanielEScherzer and ilutov) - Curl: . Added curl_multi_get_handles(). (timwolla) diff --git a/Zend/tests/constants/gh18463-class-constant.phpt b/Zend/tests/constants/gh18463-class-constant.phpt new file mode 100644 index 00000000000..2af977205dc --- /dev/null +++ b/Zend/tests/constants/gh18463-class-constant.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-18463: Recursion protection should not be applied to internal class constants +--EXTENSIONS-- +zend_test +--FILE-- + +--EXPECTF-- +Constant _ZendTestClass::ZEND_TEST_DEPRECATED is deprecated in %s on line %d + +Fatal error: Cannot use "string" as a class name as it is reserved in %s(%d) : eval()'d code on line %d diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c index 28a4b7b048c..1e6ad5a69dd 100644 --- a/Zend/zend_constants.c +++ b/Zend/zend_constants.c @@ -373,9 +373,15 @@ ZEND_API zval *zend_get_class_constant_ex(zend_string *class_name, zend_string * if (UNEXPECTED(ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED)) { if ((flags & ZEND_FETCH_CLASS_SILENT) == 0 && !CONST_IS_RECURSIVE(c)) { + if (c->ce->type == ZEND_USER_CLASS) { + /* Recursion protection only applied to user constants, GH-18463 */ + CONST_PROTECT_RECURSION(c); + } CONST_PROTECT_RECURSION(c); zend_deprecated_class_constant(c, constant_name); - CONST_UNPROTECT_RECURSION(c); + if (c->ce->type == ZEND_USER_CLASS) { + CONST_UNPROTECT_RECURSION(c); + } if (EG(exception)) { goto failure; } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index ef279f5395d..95d9a44f80d 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -6156,10 +6156,15 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CO } bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED; - if (UNEXPECTED(is_constant_deprecated) && !CONST_IS_RECURSIVE(c)) { - CONST_PROTECT_RECURSION(c); + if (UNEXPECTED(is_constant_deprecated) && !CONST_IS_RECURSIVE(c)) { + if (c->ce->type == ZEND_USER_CLASS) { + /* Recursion protection only applied to user constants, GH-18463 */ + CONST_PROTECT_RECURSION(c); + } zend_deprecated_class_constant(c, constant_name); - CONST_UNPROTECT_RECURSION(c); + if (c->ce->type == ZEND_USER_CLASS) { + CONST_UNPROTECT_RECURSION(c); + } if (EG(exception)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index d55cad75d02..aa1c8e7e175 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -7669,9 +7669,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_CONS bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED; if (UNEXPECTED(is_constant_deprecated) && !CONST_IS_RECURSIVE(c)) { - CONST_PROTECT_RECURSION(c); + if (c->ce->type == ZEND_USER_CLASS) { + /* Recursion protection only applied to user constants, GH-18463 */ + CONST_PROTECT_RECURSION(c); + } zend_deprecated_class_constant(c, constant_name); - CONST_UNPROTECT_RECURSION(c); + if (c->ce->type == ZEND_USER_CLASS) { + CONST_UNPROTECT_RECURSION(c); + } if (EG(exception)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); @@ -8874,9 +8879,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_CONS bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED; if (UNEXPECTED(is_constant_deprecated) && !CONST_IS_RECURSIVE(c)) { - CONST_PROTECT_RECURSION(c); + if (c->ce->type == ZEND_USER_CLASS) { + /* Recursion protection only applied to user constants, GH-18463 */ + CONST_PROTECT_RECURSION(c); + } zend_deprecated_class_constant(c, constant_name); - CONST_UNPROTECT_RECURSION(c); + if (c->ce->type == ZEND_USER_CLASS) { + CONST_UNPROTECT_RECURSION(c); + } if (EG(exception)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); @@ -25970,9 +25980,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_ bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED; if (UNEXPECTED(is_constant_deprecated) && !CONST_IS_RECURSIVE(c)) { - CONST_PROTECT_RECURSION(c); + if (c->ce->type == ZEND_USER_CLASS) { + /* Recursion protection only applied to user constants, GH-18463 */ + CONST_PROTECT_RECURSION(c); + } zend_deprecated_class_constant(c, constant_name); - CONST_UNPROTECT_RECURSION(c); + if (c->ce->type == ZEND_USER_CLASS) { + CONST_UNPROTECT_RECURSION(c); + } if (EG(exception)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); @@ -26542,9 +26557,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_VAR_ bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED; if (UNEXPECTED(is_constant_deprecated) && !CONST_IS_RECURSIVE(c)) { - CONST_PROTECT_RECURSION(c); + if (c->ce->type == ZEND_USER_CLASS) { + /* Recursion protection only applied to user constants, GH-18463 */ + CONST_PROTECT_RECURSION(c); + } zend_deprecated_class_constant(c, constant_name); - CONST_UNPROTECT_RECURSION(c); + if (c->ce->type == ZEND_USER_CLASS) { + CONST_UNPROTECT_RECURSION(c); + } if (EG(exception)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); @@ -35385,9 +35405,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUS bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED; if (UNEXPECTED(is_constant_deprecated) && !CONST_IS_RECURSIVE(c)) { - CONST_PROTECT_RECURSION(c); + if (c->ce->type == ZEND_USER_CLASS) { + /* Recursion protection only applied to user constants, GH-18463 */ + CONST_PROTECT_RECURSION(c); + } zend_deprecated_class_constant(c, constant_name); - CONST_UNPROTECT_RECURSION(c); + if (c->ce->type == ZEND_USER_CLASS) { + CONST_UNPROTECT_RECURSION(c); + } if (EG(exception)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); @@ -35747,9 +35772,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FETCH_CLASS_CONSTANT_SPEC_UNUS bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED; if (UNEXPECTED(is_constant_deprecated) && !CONST_IS_RECURSIVE(c)) { - CONST_PROTECT_RECURSION(c); + if (c->ce->type == ZEND_USER_CLASS) { + /* Recursion protection only applied to user constants, GH-18463 */ + CONST_PROTECT_RECURSION(c); + } zend_deprecated_class_constant(c, constant_name); - CONST_UNPROTECT_RECURSION(c); + if (c->ce->type == ZEND_USER_CLASS) { + CONST_UNPROTECT_RECURSION(c); + } if (EG(exception)) { ZVAL_UNDEF(EX_VAR(opline->result.var));