From a1cc0918085cb880ed1eadb971108612dac09fd0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Mon, 30 Sep 2024 16:33:46 +0200 Subject: [PATCH] reflection: Fix the return value of ReflectionFunction::{getNamespaceName,inNamespace}() for closures (#16129) * reflection: Fix the return value of ReflectionFunction::{getNamespaceName,inNamespace}() for closures Fixes GH-16122 * reflection: Clean up implementation of `ReflectionFunctionAbstract::inNamespace()` * reflection: Clean up implementation of `ReflectionFunctionAbstract::getNamespaceName()` --- NEWS | 4 ++++ Zend/tests/closure_067.phpt | 12 +++++++++++- Zend/tests/closure_068.phpt | 16 +++++++++++++++- ext/reflection/php_reflection.c | 8 ++++++++ 4 files changed, 38 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index b565d9f73d77a..225988ad69316 100644 --- a/NEWS +++ b/NEWS @@ -37,6 +37,10 @@ PHP NEWS . Fixed bug GH-16009 (Segmentation fault with frameless functions and undefined CVs). (nielsdos) +- Reflection: + . Fixed bug GH-16122 (The return value of ReflectionFunction::getNamespaceName() + and ReflectionFunction::inNamespace() for closures is incorrect). (timwolla) + - SAPI: . Fixed bug GHSA-9pqp-7h25-4f32 (Erroneous parsing of multipart form data). (CVE-2024-8925) (Arnaud) diff --git a/Zend/tests/closure_067.phpt b/Zend/tests/closure_067.phpt index 2738959509d7a..b535f009bf89d 100644 --- a/Zend/tests/closure_067.phpt +++ b/Zend/tests/closure_067.phpt @@ -1,5 +1,5 @@ --TEST-- -ReflectionFunction::getShortName() returns the full name for closures defined in namespaces. +ReflectionFunction::get{Short,Namespace}Name() and inNamespace() return the correct data for closures defined in namespaces. --FILE-- baz(); $r = new \ReflectionFunction($c); +// Closures are not inside of a namespace, thus the short name is the full name. var_dump($r->getShortName()); +// The namespace is empty. +var_dump($r->getNamespaceName()); +// The function is not inside of a namespace. +var_dump($r->inNamespace()); +// And the namespace name + the short name together must be the full name. +var_dump($r->getNamespaceName() . ($r->inNamespace() ? '\\' : '') . $r->getShortName() === $r->getName()); ?> --EXPECT-- string(26) "{closure:Foo\Bar::baz():6}" +string(0) "" +bool(false) +bool(true) diff --git a/Zend/tests/closure_068.phpt b/Zend/tests/closure_068.phpt index 977d3946770ab..8ef50e0914b61 100644 --- a/Zend/tests/closure_068.phpt +++ b/Zend/tests/closure_068.phpt @@ -1,5 +1,5 @@ --TEST-- -ReflectionFunction::getShortName() returns the short name for first class callables defined in namespaces. +ReflectionFunction::get{Short,Namespace}Name() and inNamespace() return the correct data for first class callables defined in namespaces. --FILE-- getShortName()); +var_dump($r->getNamespaceName()); +var_dump($r->inNamespace()); +var_dump($r->getNamespaceName() . ($r->inNamespace() ? '\\' : '') . $r->getShortName() === $r->getName()); + +var_dump($r->getShortName() === $r2->getShortName()); +var_dump($r->getNamespaceName() === $r2->getNamespaceName()); +var_dump($r->inNamespace() === $r2->inNamespace()); ?> --EXPECT-- string(3) "foo" +string(3) "Foo" +bool(true) +bool(true) +bool(true) +bool(true) +bool(true) diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index cfe62938cf1db..64418bfd513b9 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -3584,6 +3584,10 @@ ZEND_METHOD(ReflectionFunctionAbstract, inNamespace) GET_REFLECTION_OBJECT_PTR(fptr); + if ((fptr->common.fn_flags & (ZEND_ACC_CLOSURE | ZEND_ACC_FAKE_CLOSURE)) == ZEND_ACC_CLOSURE) { + RETURN_FALSE; + } + zend_string *name = fptr->common.function_name; const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)); RETURN_BOOL(backslash); @@ -3602,6 +3606,10 @@ ZEND_METHOD(ReflectionFunctionAbstract, getNamespaceName) GET_REFLECTION_OBJECT_PTR(fptr); + if ((fptr->common.fn_flags & (ZEND_ACC_CLOSURE | ZEND_ACC_FAKE_CLOSURE)) == ZEND_ACC_CLOSURE) { + RETURN_EMPTY_STRING(); + } + zend_string *name = fptr->common.function_name; const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)); if (backslash) {