Skip to content

Commit 1780131

Browse files
committed
Fix infinite recursion on deprecated attribute evaluation
Fixes GH-17711
1 parent dc7b661 commit 1780131

File tree

5 files changed

+57
-8
lines changed

5 files changed

+57
-8
lines changed

Zend/tests/gh17711.phpt

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
GH-17711: Infinite recursion through deprecated class constants self-referencing through deprecation message
3+
--FILE--
4+
<?php
5+
6+
const TEST = 'Message';
7+
8+
class C {
9+
#[\Deprecated(self::C)]
10+
const C = TEST;
11+
}
12+
13+
var_dump(C::C);
14+
15+
?>
16+
--EXPECTF--
17+
Deprecated: Constant C::C is deprecated, Message in %s on line %d
18+
string(7) "Message"

Zend/zend_constants.c

+3-1
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

+15
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,21 @@
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+
if (Z_TYPE((c)->value) == IS_CONSTANT_AST) { \
36+
Z_CONSTANT_FLAGS((c)->value) |= CONST_RECURSIVE; \
37+
} \
38+
} while (0)
39+
#define CONST_UNPROTECT_RECURSION(zval) \
40+
do { \
41+
if (Z_TYPE((c)->value) == IS_CONSTANT_AST) { \
42+
Z_CONSTANT_FLAGS((c)->value) &= ~CONST_RECURSIVE; \
43+
} \
44+
} while (0)
3045

3146
#define PHP_USER_CONSTANT 0x7fffff /* a constant defined in user space */
3247

Zend/zend_vm_def.h

+3-1
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

+18-6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)