Commit 1da01f076b7 for php.net
commit 1da01f076b75539e8f02b6494b29f6a3c752110e
Merge: 0dc8a54f629 fc6b78ea2a0
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date: Fri Jul 31 11:51:25 2026 -0400
Merge branch 'PHP-8.5'
* PHP-8.5:
Free previous state when re-calling Reflection*::__construct()
Master additionally stores the reflected closure in intern->obj for the
invoke() identity check, so the merge releases the previous object before
overwriting it and clears the slot when re-constructing onto a named
method.
diff --cc ext/reflection/php_reflection.c
index 6682346a5b0,fa94cb9a849..42ab6dcd8ae
--- a/ext/reflection/php_reflection.c
+++ b/ext/reflection/php_reflection.c
@@@ -3239,14 -3402,12 +3239,18 @@@ static void instantiate_reflection_meth
&& memcmp(lcname, ZEND_INVOKE_FUNC_NAME, sizeof(ZEND_INVOKE_FUNC_NAME)-1) == 0
&& (mptr = zend_get_closure_invoke_method(orig_obj)) != NULL)
{
- /* do nothing, mptr already set */
+ /* Store the original closure object so we can validate it in invoke/invokeArgs.
+ * Each closure has a unique __invoke signature, so we must reject different closures. */
++ zval_ptr_dtor(&intern->obj);
+ ZVAL_OBJ_COPY(&intern->obj, orig_obj);
} else if ((mptr = zend_hash_str_find_ptr(&ce->function_table, lcname, method_name_len)) == NULL) {
efree(lcname);
zend_throw_exception_ex(reflection_exception_ptr, 0,
"Method %s::%s() does not exist", ZSTR_VAL(ce->name), method_name);
RETURN_THROWS();
++ } else {
++ zval_ptr_dtor(&intern->obj);
++ ZVAL_UNDEF(&intern->obj);
}
efree(lcname);