Commit 4a18c895ca7 for php.net

commit 4a18c895ca7f0511bf26b10171d9efbff5a2af8c
Author: Niels Dossche <7771979+nielsdos@users.noreply.github.com>
Date:   Mon Jun 30 09:09:55 2025 +0200

    Fix OSS-Fuzz #428053935 (#18969)

    Registering the constant may happen under another name due to
    lowercasing. This will cause the lookup to the constant to fail.
    Instead of looking it up, just change the Zend API to return a pointer
    instead.

diff --git a/UPGRADING.INTERNALS b/UPGRADING.INTERNALS
index 3b248614c37..6b5959fe030 100644
--- a/UPGRADING.INTERNALS
+++ b/UPGRADING.INTERNALS
@@ -45,6 +45,8 @@ PHP 8.5 INTERNALS UPGRADE NOTES
     properties.
   . ZEND_IS_XDIGIT() macro was removed because it was unused and its name
     did not match its actual behavior.
+  . zend_register_constant() now returns a pointer to the added constant
+    on success and NULL on failure instead of SUCCESS/FAILURE.

 ========================
 2. Build system changes
diff --git a/Zend/tests/attributes/constants/oss_fuzz_428053935.phpt b/Zend/tests/attributes/constants/oss_fuzz_428053935.phpt
new file mode 100644
index 00000000000..97747fd6194
--- /dev/null
+++ b/Zend/tests/attributes/constants/oss_fuzz_428053935.phpt
@@ -0,0 +1,19 @@
+--TEST--
+OSS-Fuzz #428053935
+--FILE--
+<?php
+namespace Foo; // Capital letter is important for the ns lookup
+#[Attr]
+const MyConst = '';
+
+$rc = new \ReflectionConstant('Foo\\MyConst');
+var_dump($rc->getAttributes());
+?>
+--EXPECTF--
+array(1) {
+  [0]=>
+  object(ReflectionAttribute)#%d (1) {
+    ["name"]=>
+    string(8) "Foo\Attr"
+  }
+}
diff --git a/Zend/zend_builtin_functions.c b/Zend/zend_builtin_functions.c
index 48e5c708972..fc3b0f57d85 100644
--- a/Zend/zend_builtin_functions.c
+++ b/Zend/zend_builtin_functions.c
@@ -592,7 +592,7 @@ ZEND_FUNCTION(define)
 	/* non persistent */
 	ZEND_CONSTANT_SET_FLAGS(&c, 0, PHP_USER_CONSTANT);
 	c.name = zend_string_copy(name);
-	if (zend_register_constant(&c) == SUCCESS) {
+	if (zend_register_constant(&c) != NULL) {
 		RETURN_TRUE;
 	} else {
 		RETURN_FALSE;
diff --git a/Zend/zend_constants.c b/Zend/zend_constants.c
index ffad8315ae4..db37b9cf768 100644
--- a/Zend/zend_constants.c
+++ b/Zend/zend_constants.c
@@ -505,11 +505,11 @@ static void* zend_hash_add_constant(HashTable *ht, zend_string *key, zend_consta
 	return ret;
 }

-ZEND_API zend_result zend_register_constant(zend_constant *c)
+ZEND_API zend_constant *zend_register_constant(zend_constant *c)
 {
 	zend_string *lowercase_name = NULL;
 	zend_string *name;
-	zend_result ret = SUCCESS;
+	zend_constant *ret = NULL;
 	bool persistent = (ZEND_CONSTANT_FLAGS(c) & CONST_PERSISTENT) != 0;

 #if 0
@@ -539,7 +539,7 @@ ZEND_API zend_result zend_register_constant(zend_constant *c)
 	/* Check if the user is trying to define any special constant */
 	if (zend_string_equals_literal(name, "__COMPILER_HALT_OFFSET__")
 		|| (!persistent && zend_get_special_const(ZSTR_VAL(name), ZSTR_LEN(name)))
-		|| zend_hash_add_constant(EG(zend_constants), name, c) == NULL
+		|| (ret = zend_hash_add_constant(EG(zend_constants), name, c)) == NULL
 	) {
 		zend_error(E_WARNING, "Constant %s already defined", ZSTR_VAL(name));
 		zend_string_release(c->name);
@@ -550,7 +550,6 @@ ZEND_API zend_result zend_register_constant(zend_constant *c)
 		if (!persistent) {
 			zval_ptr_dtor_nogc(&c->value);
 		}
-		ret = FAILURE;
 	}
 	if (lowercase_name) {
 		zend_string_release(lowercase_name);
diff --git a/Zend/zend_constants.h b/Zend/zend_constants.h
index 3912215d807..69ea1d9021a 100644
--- a/Zend/zend_constants.h
+++ b/Zend/zend_constants.h
@@ -97,7 +97,7 @@ ZEND_API void zend_register_long_constant(const char *name, size_t name_len, zen
 ZEND_API void zend_register_double_constant(const char *name, size_t name_len, double dval, int flags, int module_number);
 ZEND_API void zend_register_string_constant(const char *name, size_t name_len, const char *strval, int flags, int module_number);
 ZEND_API void zend_register_stringl_constant(const char *name, size_t name_len, const char *strval, size_t strlen, int flags, int module_number);
-ZEND_API zend_result zend_register_constant(zend_constant *c);
+ZEND_API zend_constant *zend_register_constant(zend_constant *c);
 void zend_constant_add_attributes(zend_constant *c, HashTable *attributes);
 #ifdef ZTS
 void zend_copy_constants(HashTable *target, HashTable *source);
diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h
index be7bc8b37b7..51aaf635b3b 100644
--- a/Zend/zend_vm_def.h
+++ b/Zend/zend_vm_def.h
@@ -8261,7 +8261,7 @@ ZEND_VM_HANDLER(143, ZEND_DECLARE_CONST, CONST, CONST)
 	ZEND_CONSTANT_SET_FLAGS(&c, 0, PHP_USER_CONSTANT);
 	c.name = zend_string_copy(Z_STR_P(name));

-	if (zend_register_constant(&c) == FAILURE) {
+	if (zend_register_constant(&c) == NULL) {
 	}

 	FREE_OP1();
@@ -8274,7 +8274,7 @@ ZEND_VM_HANDLER(210, ZEND_DECLARE_ATTRIBUTED_CONST, CONST, CONST)
 	USE_OPLINE
 	zval *name;
 	zval *val;
-	zend_constant c;
+	zend_constant c, *registered;

 	SAVE_OPLINE();
 	name  = GET_OP1_ZVAL_PTR(BP_VAR_R);
@@ -8293,7 +8293,8 @@ ZEND_VM_HANDLER(210, ZEND_DECLARE_ATTRIBUTED_CONST, CONST, CONST)
 	ZEND_CONSTANT_SET_FLAGS(&c, 0, PHP_USER_CONSTANT);
 	c.name = zend_string_copy(Z_STR_P(name));

-	if (zend_register_constant(&c) == FAILURE) {
+	registered = zend_register_constant(&c);
+	if (registered == NULL) {
 		FREE_OP1();
 		FREE_OP2();
 		/* two opcodes used, second one is the data with attributes */
@@ -8301,9 +8302,7 @@ ZEND_VM_HANDLER(210, ZEND_DECLARE_ATTRIBUTED_CONST, CONST, CONST)
 	}

 	HashTable *attributes = Z_PTR_P(GET_OP_DATA_ZVAL_PTR(BP_VAR_R));
-	zend_constant *registered = zend_get_constant_ptr(c.name);
 	ZEND_ASSERT(attributes != NULL);
-	ZEND_ASSERT(registered != NULL);
 	zend_constant_add_attributes(registered, attributes);

 	FREE_OP1();
diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h
index 3a13f4244d3..f29c6b47261 100644
Binary files a/Zend/zend_vm_execute.h and b/Zend/zend_vm_execute.h differ