Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 272f7f7

Browse files
Fix infinite recursion on deprecated attribute evaluation
Fixes GH-17711 Fixes GH-18022 Closes GH-17712
1 parent 5ea386d commit 272f7f7

File tree

9 files changed

+76
-9
lines changed

9 files changed

+76
-9
lines changed

‎NEWS‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.4.7
44

5+
- Core:
6+
. Fixed bug GH-17711 and GH-18022 (Infinite recursion on deprecated attribute
7+
evaluation). (ilutov)
58

69
27 Mar 2025, PHP 8.4.6RC1
710

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
GH-17711: Infinite recursion through deprecated class constants self-referencing through deprecation message
3+
--FILE--
4+
<?php
5+
6+
class C {
7+
#[\Deprecated(self::C)]
8+
const C = TEST;
9+
}
10+
11+
const TEST = 'Message';
12+
var_dump(C::C);
13+
14+
class D {
15+
#[\Deprecated(Alias::C)]
16+
const C = 'test';
17+
}
18+
19+
class_alias('D', 'Alias');
20+
var_dump(D::C);
21+
22+
?>
23+
--EXPECTF--
24+
Deprecated: Constant C::C is deprecated, Message in %s on line %d
25+
string(7) "Message"
26+
27+
Deprecated: Constant D::C is deprecated, test in %s on line %d
28+
string(4) "test"

‎Zend/zend_API.c‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1439,7 +1439,7 @@ ZEND_API HashTable *zend_separate_class_constants_table(zend_class_entry *class_
14391439

14401440
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&class_type->constants_table, key, c) {
14411441
if (c->ce == class_type) {
1442-
if (Z_TYPE(c->value) == IS_CONSTANT_AST) {
1442+
if (Z_TYPE(c->value) == IS_CONSTANT_AST|| (ZEND_CLASS_CONST_FLAGS(c) &ZEND_ACC_DEPRECATED)) {
14431443
new_c = zend_arena_alloc(&CG(arena), sizeof(zend_class_constant));
14441444
memcpy(new_c, c, sizeof(zend_class_constant));
14451445
c = new_c;

‎Zend/zend_compile.c‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8822,6 +8822,10 @@ static void zend_compile_class_const_decl(zend_ast *ast, uint32_t flags, zend_as
88228822

88238823
if (deprecated) {
88248824
ZEND_CLASS_CONST_FLAGS(c) |= ZEND_ACC_DEPRECATED;
8825+
/* For deprecated constants, we need to flag the zval for recursion
8826+
* detection. Make sure the zval is separated out of shm. */
8827+
ce->ce_flags |= ZEND_ACC_HAS_AST_CONSTANTS;
8828+
ce->ce_flags &= ~ZEND_ACC_CONSTANTS_UPDATED;
88258829
}
88268830
}
88278831
}

‎Zend/zend_constants.c‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,8 +353,10 @@ ZEND_API zval *zend_get_class_constant_ex(zend_string *class_name, zend_string *
353353
}
354354

355355
if (UNEXPECTED(ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED)) {
356-
if ((flags & ZEND_FETCH_CLASS_SILENT) == 0) {
356+
if ((flags & ZEND_FETCH_CLASS_SILENT) == 0 && !CONST_IS_RECURSIVE(c)) {
357+
CONST_PROTECT_RECURSION(c);
357358
zend_deprecated_class_constant(c, constant_name);
359+
CONST_UNPROTECT_RECURSION(c);
358360
if (EG(exception)) {
359361
goto failure;
360362
}

‎Zend/zend_constants.h‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,17 @@
2727
#define CONST_NO_FILE_CACHE (1<<1) /* Can't be saved in file cache */
2828
#define CONST_DEPRECATED (1<<2) /* Deprecated */
2929
#define CONST_OWNED (1<<3) /* constant should be destroyed together with class */
30+
#define CONST_RECURSIVE (1<<4) /* Recursion protection for constant evaluation */
31+
32+
#define CONST_IS_RECURSIVE(c) (Z_CONSTANT_FLAGS((c)->value) & CONST_RECURSIVE)
33+
#define CONST_PROTECT_RECURSION(c) \
34+
do { \
35+
Z_CONSTANT_FLAGS((c)->value) |= CONST_RECURSIVE; \
36+
} while (0)
37+
#define CONST_UNPROTECT_RECURSION(c) \
38+
do { \
39+
Z_CONSTANT_FLAGS((c)->value) &= ~CONST_RECURSIVE; \
40+
} while (0)
3041

3142
#define PHP_USER_CONSTANT 0x7fffff /* a constant defined in user space */
3243

‎Zend/zend_vm_def.h‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6094,8 +6094,10 @@ ZEND_VM_HANDLER(181, ZEND_FETCH_CLASS_CONSTANT, VAR|CONST|UNUSED|CLASS_FETCH, CO
60946094
}
60956095

60966096
bool is_constant_deprecated = ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED;
6097-
if (UNEXPECTED(is_constant_deprecated)) {
6097+
if (UNEXPECTED(is_constant_deprecated) && !CONST_IS_RECURSIVE(c)) {
6098+
CONST_PROTECT_RECURSION(c);
60986099
zend_deprecated_class_constant(c, constant_name);
6100+
CONST_UNPROTECT_RECURSION(c);
60996101

61006102
if (EG(exception)) {
61016103
ZVAL_UNDEF(EX_VAR(opline->result.var));

‎Zend/zend_vm_execute.h‎

Lines changed: 18 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎ext/opcache/ZendAccelerator.c‎

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3800,6 +3800,11 @@ static bool preload_try_resolve_constants(zend_class_entry *ce)
38003800
ZEND_HASH_MAP_FOREACH_STR_KEY_PTR(&ce->constants_table, key, c) {
38013801
val = &c->value;
38023802
if (Z_TYPE_P(val) == IS_CONSTANT_AST) {
3803+
/* For deprecated constants, we need to flag the zval for recursion
3804+
* detection. Make sure the zval is separated out of shm. */
3805+
if (ZEND_CLASS_CONST_FLAGS(c) & ZEND_ACC_DEPRECATED) {
3806+
ok = false;
3807+
}
38033808
if (EXPECTED(zend_update_class_constant(c, key, c->ce) == SUCCESS)) {
38043809
was_changed = changed = true;
38053810
} else {

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /