Skip to content

Commit

Permalink
Fix infinite recursion on deprecated attribute evaluation
Browse files Browse the repository at this point in the history
Fixes GH-17711
  • Loading branch information
iluuu1994 committed Feb 6, 2025
1 parent dc7b661 commit 1780131
Show file tree
Hide file tree
Showing 5 changed files with 57 additions and 8 deletions.
18 changes: 18 additions & 0 deletions Zend/tests/gh17711.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
GH-17711: Infinite recursion through deprecated class constants self-referencing through deprecation message
--FILE--
<?php

const TEST = 'Message';

class C {
#[\Deprecated(self::C)]
const C = TEST;
}

var_dump(C::C);

?>
--EXPECTF--
Deprecated: Constant C::C is deprecated, Message in %s on line %d
string(7) "Message"
4 changes: 3 additions & 1 deletion Zend/zend_constants.c
Original file line number Diff line number Diff line change
Expand Up @@ -353,8 +353,10 @@ 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) {
if ((flags & ZEND_FETCH_CLASS_SILENT) == 0 && !CONST_IS_RECURSIVE(c)) {
CONST_PROTECT_RECURSION(c);
zend_deprecated_class_constant(c, constant_name);
CONST_UNPROTECT_RECURSION(c);
if (EG(exception)) {
goto failure;
}
Expand Down
15 changes: 15 additions & 0 deletions Zend/zend_constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,21 @@
#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 { \
if (Z_TYPE((c)->value) == IS_CONSTANT_AST) { \
Z_CONSTANT_FLAGS((c)->value) |= CONST_RECURSIVE; \
} \
} while (0)
#define CONST_UNPROTECT_RECURSION(zval) \
do { \
if (Z_TYPE((c)->value) == IS_CONSTANT_AST) { \
Z_CONSTANT_FLAGS((c)->value) &= ~CONST_RECURSIVE; \
} \
} while (0)

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

Expand Down
4 changes: 3 additions & 1 deletion Zend/zend_vm_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -6094,8 +6094,10 @@ 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)) {
if (UNEXPECTED(is_constant_deprecated) && !CONST_IS_RECURSIVE(c)) {
CONST_PROTECT_RECURSION(c);
zend_deprecated_class_constant(c, constant_name);
CONST_UNPROTECT_RECURSION(c);

if (EG(exception)) {
ZVAL_UNDEF(EX_VAR(opline->result.var));
Expand Down
24 changes: 18 additions & 6 deletions Zend/zend_vm_execute.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 1780131

Please sign in to comment.