From 754061caf6ec38ddd05f8fb9de4b789a05ffba88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Mon, 30 Sep 2024 08:59:47 +0200 Subject: [PATCH 1/3] reflection: Fix the return value of ReflectionFunction::{getNamespaceName,inNamespace}() for closures Fixes GH-16122 --- NEWS | 4 ++++ Zend/tests/closure_067.phpt | 12 +++++++++++- Zend/tests/closure_068.phpt | 16 +++++++++++++++- ext/reflection/php_reflection.c | 21 ++++++++++++++------- 4 files changed, 44 insertions(+), 9 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..737d64bccde97 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -3584,9 +3584,13 @@ ZEND_METHOD(ReflectionFunctionAbstract, inNamespace) GET_REFLECTION_OBJECT_PTR(fptr); - zend_string *name = fptr->common.function_name; - const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)); - RETURN_BOOL(backslash); + if ((fptr->common.fn_flags & (ZEND_ACC_CLOSURE | ZEND_ACC_FAKE_CLOSURE)) != ZEND_ACC_CLOSURE) { + zend_string *name = fptr->common.function_name; + const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)); + RETURN_BOOL(backslash); + } + + RETURN_FALSE; } /* }}} */ @@ -3602,11 +3606,14 @@ ZEND_METHOD(ReflectionFunctionAbstract, getNamespaceName) GET_REFLECTION_OBJECT_PTR(fptr); - zend_string *name = fptr->common.function_name; - const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)); - if (backslash) { - RETURN_STRINGL(ZSTR_VAL(name), backslash - ZSTR_VAL(name)); + if ((fptr->common.fn_flags & (ZEND_ACC_CLOSURE | ZEND_ACC_FAKE_CLOSURE)) != ZEND_ACC_CLOSURE) { + zend_string *name = fptr->common.function_name; + const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)); + if (backslash) { + RETURN_STRINGL(ZSTR_VAL(name), backslash - ZSTR_VAL(name)); + } } + RETURN_EMPTY_STRING(); } /* }}} */ From 4420604e37f9195d699b99979d384e4b673c9e1a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Mon, 30 Sep 2024 15:54:12 +0200 Subject: [PATCH 2/3] reflection: Clean up implementation of `ReflectionFunctionAbstract::inNamespace()` --- ext/reflection/php_reflection.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 737d64bccde97..44abe0cb9a6c5 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -3584,13 +3584,13 @@ ZEND_METHOD(ReflectionFunctionAbstract, inNamespace) GET_REFLECTION_OBJECT_PTR(fptr); - if ((fptr->common.fn_flags & (ZEND_ACC_CLOSURE | ZEND_ACC_FAKE_CLOSURE)) != ZEND_ACC_CLOSURE) { - zend_string *name = fptr->common.function_name; - const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)); - RETURN_BOOL(backslash); + if ((fptr->common.fn_flags & (ZEND_ACC_CLOSURE | ZEND_ACC_FAKE_CLOSURE)) == ZEND_ACC_CLOSURE) { + RETURN_FALSE; } - RETURN_FALSE; + zend_string *name = fptr->common.function_name; + const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)); + RETURN_BOOL(backslash); } /* }}} */ From 61163f5500ad2b45d8527b01b93d975f36c8d353 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tim=20D=C3=BCsterhus?= Date: Mon, 30 Sep 2024 15:55:22 +0200 Subject: [PATCH 3/3] reflection: Clean up implementation of `ReflectionFunctionAbstract::getNamespaceName()` --- ext/reflection/php_reflection.c | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/ext/reflection/php_reflection.c b/ext/reflection/php_reflection.c index 44abe0cb9a6c5..64418bfd513b9 100644 --- a/ext/reflection/php_reflection.c +++ b/ext/reflection/php_reflection.c @@ -3606,14 +3606,15 @@ ZEND_METHOD(ReflectionFunctionAbstract, getNamespaceName) GET_REFLECTION_OBJECT_PTR(fptr); - if ((fptr->common.fn_flags & (ZEND_ACC_CLOSURE | ZEND_ACC_FAKE_CLOSURE)) != ZEND_ACC_CLOSURE) { - zend_string *name = fptr->common.function_name; - const char *backslash = zend_memrchr(ZSTR_VAL(name), '\\', ZSTR_LEN(name)); - if (backslash) { - RETURN_STRINGL(ZSTR_VAL(name), backslash - ZSTR_VAL(name)); - } + 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) { + RETURN_STRINGL(ZSTR_VAL(name), backslash - ZSTR_VAL(name)); + } RETURN_EMPTY_STRING(); } /* }}} */