From bbd9732f838b5c1425df4f46823c7c69ed7b6cd0 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Wed, 30 Apr 2025 20:52:56 +0200 Subject: [PATCH 1/2] Revert "Fix infinite recursion on deprecated attribute evaluation" This reverts commit 272f7f75e2d4ff25d4dc00b0102c39fdb4f9c573. Reverts GH-17712 for the PHP-8.4 branch. This will be reapplied later with a fix for GH-18463 (GH-18464). --- .../deprecated/class_constants/gh17711.phpt | 28 ------------------- Zend/zend_API.c | 2 +- Zend/zend_compile.c | 4 --- Zend/zend_constants.c | 4 +-- Zend/zend_constants.h | 11 -------- Zend/zend_vm_def.h | 4 +-- Zend/zend_vm_execute.h | 24 ++++------------ ext/opcache/ZendAccelerator.c | 5 ---- 8 files changed, 9 insertions(+), 73 deletions(-) delete mode 100644 Zend/tests/attributes/deprecated/class_constants/gh17711.phpt diff --git a/Zend/tests/attributes/deprecated/class_constants/gh17711.phpt b/Zend/tests/attributes/deprecated/class_constants/gh17711.phpt deleted file mode 100644 index abec209343ab3..0000000000000 --- a/Zend/tests/attributes/deprecated/class_constants/gh17711.phpt +++ /dev/null @@ -1,28 +0,0 @@ ---TEST-- -GH-17711: Infinite recursion through deprecated class constants self-referencing through deprecation message ---FILE-- - ---EXPECTF-- -Deprecated: Constant C::C is deprecated, Message in %s on line %d -string(7) "Message" - -Deprecated: Constant D::C is deprecated, test in %s on line %d -string(4) "test" diff --git a/Zend/zend_API.c b/Zend/zend_API.c index 6e254561d3745..5aac3c1f7d77c 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -1439,7 +1439,7 @@ ZEND_API HashTable *zend_separate_class_constants_table(zend_class_entry *class_ ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&class_type->constants_table, key, c) { if (c->ce == class_type) { - if (Z_TYPE(c->value) == IS_CONSTANT_AST || (ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED)) { + if (Z_TYPE(c->value) == IS_CONSTANT_AST) { new_c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant)); memcpy(new_c, c, sizeof(zend_class_constant)); c = new_c; diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index 195c65d504374..832dedc421042 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -8822,10 +8822,6 @@ static void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_as if (deprecated) { ZEND_CLASS_CONST_FLAGS(c) |= ZEND_ACC_DEPRECATED; - /* For deprecated constants, we need to flag the zval for recursion - * detection. Make sure the zval is separated out of shm. */ - ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS; - ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED; } } } diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c index 2145cb1915354..d453b8bb73717 100644 --- a/Zend/zend_constants.c +++ b/Zend/zend_constants.c @@ -353,10 +353,8 @@ 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)) { - CONST_PROTECT_RECURSION(c); + if ((flags & ZEND_FETCH_CLASS_SILENT) == 0) { zend_deprecated_class_constant(c, constant_name); - CONST_UNPROTECT_RECURSION(c); if (EG(exception)) { goto failure; } diff --git a/Zend/zend_constants.h b/Zend/zend_constants.h index bd759c2891500..6f0710c0ce63e 100644 --- a/Zend/zend_constants.h +++ b/Zend/zend_constants.h @@ -27,17 +27,6 @@ #define CONST_NO_FILE_CACHE (1<<1) /* Can't be saved in file cache */ #define CONST_DEPRECATED (1<<2) /* Deprecated */ #define CONST_OWNED (1<<3) /* constant should be destroyed together with class */ -#define CONST_RECURSIVE (1<<4) /* Recursion protection for constant evaluation */ - -#define CONST_IS_RECURSIVE(c) (Z_CONSTANT_FLAGS((c)->value) & CONST_RECURSIVE) -#define CONST_PROTECT_RECURSION(c) \ - do { \ - Z_CONSTANT_FLAGS((c)->value) |= CONST_RECURSIVE; \ - } while (0) -#define CONST_UNPROTECT_RECURSION(c) \ - do { \ - Z_CONSTANT_FLAGS((c)->value) &= ~CONST_RECURSIVE; \ - } while (0) #define PHP_USER_CONSTANT 0x7fffff /* a constant defined in user space */ diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 37e0e0fb43d95..a4fa8063a5bd4 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -6094,10 +6094,8 @@ 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)) { zend_deprecated_class_constant(c, constant_name); - 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 dadc57d13f278..a8bf9da828593 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -7615,10 +7615,8 @@ 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 (UNEXPECTED(is_constant_deprecated)) { zend_deprecated_class_constant(c, constant_name); - CONST_UNPROTECT_RECURSION(c); if (EG(exception)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); @@ -8777,10 +8775,8 @@ 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 (UNEXPECTED(is_constant_deprecated)) { zend_deprecated_class_constant(c, constant_name); - CONST_UNPROTECT_RECURSION(c); if (EG(exception)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); @@ -25878,10 +25874,8 @@ 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 (UNEXPECTED(is_constant_deprecated)) { zend_deprecated_class_constant(c, constant_name); - CONST_UNPROTECT_RECURSION(c); if (EG(exception)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); @@ -26449,10 +26443,8 @@ 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 (UNEXPECTED(is_constant_deprecated)) { zend_deprecated_class_constant(c, constant_name); - CONST_UNPROTECT_RECURSION(c); if (EG(exception)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); @@ -35290,10 +35282,8 @@ 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 (UNEXPECTED(is_constant_deprecated)) { zend_deprecated_class_constant(c, constant_name); - CONST_UNPROTECT_RECURSION(c); if (EG(exception)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); @@ -35651,10 +35641,8 @@ 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 (UNEXPECTED(is_constant_deprecated)) { zend_deprecated_class_constant(c, constant_name); - CONST_UNPROTECT_RECURSION(c); if (EG(exception)) { ZVAL_UNDEF(EX_VAR(opline->result.var)); diff --git a/ext/opcache/ZendAccelerator.c b/ext/opcache/ZendAccelerator.c index f71f43b330ffa..459449d85f23c 100644 --- a/ext/opcache/ZendAccelerator.c +++ b/ext/opcache/ZendAccelerator.c @@ -3800,11 +3800,6 @@ static bool preload_try_resolve_constants(zend_class_entry *ce) ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) { val = &c->value; if (Z_TYPE_P(val) == IS_CONSTANT_AST) { - /* For deprecated constants, we need to flag the zval for recursion - * detection. Make sure the zval is separated out of shm. */ - if (ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED) { - ok = false; - } if (EXPECTED(zend_update_class_constant(c, key, c->ce) == SUCCESS)) { was_changed = changed = true; } else { From bda0939bd2e52fcac94a299110716b6804d7f31b Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Wed, 30 Apr 2025 22:38:12 +0200 Subject: [PATCH 2/2] [skip ci] Remove NEWS entry for reverted fix --- NEWS | 2 -- 1 file changed, 2 deletions(-) diff --git a/NEWS b/NEWS index efb76ac127a60..104a053697439 100644 --- a/NEWS +++ b/NEWS @@ -3,8 +3,6 @@ PHP NEWS ?? ??? ????, PHP 8.4.7 - Core: - . Fixed bug GH-17711 and GH-18022 (Infinite recursion on deprecated attribute - evaluation). (ilutov) . Fixed bug GH-18038 (Lazy proxy calls magic methods twice). (Arnaud) . Fixed bug GH-18209 (Use-after-free in extract() with EXTR_REFS). (ilutov) . Fixed bug GH-18268 (Segfault in array_walk() on object with added property