From 013412a40664c1f87449f09be379f0f78422af18 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 6 Jun 2024 16:50:03 +0100 Subject: [PATCH 1/5] Add test file --- ext/zend_test/test.c | 13 +++++ ext/zend_test/test.stub.php | 2 + ext/zend_test/test_arginfo.h | 7 ++- .../tests/gen_stub_test_return_by_ref.phpt | 53 +++++++++++++++++++ 4 files changed, 74 insertions(+), 1 deletion(-) create mode 100644 ext/zend_test/tests/gen_stub_test_return_by_ref.phpt diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 331ef5105fa9d..29eb0833fa134 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -1045,6 +1045,19 @@ static ZEND_METHOD(_ZendTestClass, takesUnionType) RETURN_NULL(); } +static ZEND_METHOD(_ZendTestClass, returnByRefIntProp) +{ + ZEND_PARSE_PARAMETERS_NONE(); + + zend_object *obj = Z_OBJ_P(ZEND_THIS); + zend_string *name = zend_string_init("intProp", strlen("intProp"), false); + zval *int_prop = obj->handlers->get_property_ptr_ptr(obj, name, BP_VAR_W, NULL); + zend_string_release_ex(name, false); + + //ZVAL_MAKE_REF(int_prop, int_prop); + RETURN_COPY(int_prop); +} + // Returns a newly allocated DNF type `Iterator|(Traversable&Countable)`. // // We need to generate it "manually" because gen_stubs.php does not support codegen for DNF types ATM. diff --git a/ext/zend_test/test.stub.php b/ext/zend_test/test.stub.php index 5c1bed2847822..d614868334e61 100644 --- a/ext/zend_test/test.stub.php +++ b/ext/zend_test/test.stub.php @@ -65,6 +65,8 @@ public function returnsThrowable(): Throwable {} static public function variadicTest(string|Iterator ...$elements) : static {} public function takesUnionType(stdclass|Iterator $arg): void {} + + public function &returnByRefIntProp(): int {} } class _ZendTestMagicCall diff --git a/ext/zend_test/test_arginfo.h b/ext/zend_test/test_arginfo.h index 32229d9d9d323..4b37215d30bb4 100644 --- a/ext/zend_test/test_arginfo.h +++ b/ext/zend_test/test_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 53027610adee7e1c675b1c1b38886100ce4e63ef */ + * Stub hash: 9f38fdbb3b987bccaa873bd005559ce52b96b0dd */ ZEND_STATIC_ASSERT(PHP_VERSION_ID >= 80000, "test_arginfo.h only supports PHP version ID 80000 or newer, " "but it is included on an older PHP version"); @@ -187,6 +187,9 @@ ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class__ZendTestClass_takesUnionT ZEND_ARG_OBJ_TYPE_MASK(0, arg, stdclass|Iterator, 0, NULL) ZEND_END_ARG_INFO() +ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class__ZendTestClass_returnByRefIntProp, 1, 0, IS_LONG, 0) +ZEND_END_ARG_INFO() + ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class__ZendTestMagicCall___call, 0, 2, IS_MIXED, 0) ZEND_ARG_TYPE_INFO(0, name, IS_STRING, 0) ZEND_ARG_TYPE_INFO(0, args, IS_ARRAY, 0) @@ -287,6 +290,7 @@ static ZEND_METHOD(_ZendTestClass, returnsStatic); static ZEND_METHOD(_ZendTestClass, returnsThrowable); static ZEND_METHOD(_ZendTestClass, variadicTest); static ZEND_METHOD(_ZendTestClass, takesUnionType); +static ZEND_METHOD(_ZendTestClass, returnByRefIntProp); static ZEND_METHOD(_ZendTestMagicCall, __call); static ZEND_METHOD(_ZendTestChildClass, returnsThrowable); static ZEND_METHOD(ZendAttributeTest, testMethod); @@ -426,6 +430,7 @@ static const zend_function_entry class__ZendTestClass_methods[] = { ZEND_ME(_ZendTestClass, returnsThrowable, arginfo_class__ZendTestClass_returnsThrowable, ZEND_ACC_PUBLIC) ZEND_ME(_ZendTestClass, variadicTest, arginfo_class__ZendTestClass_variadicTest, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) ZEND_ME(_ZendTestClass, takesUnionType, arginfo_class__ZendTestClass_takesUnionType, ZEND_ACC_PUBLIC) + ZEND_ME(_ZendTestClass, returnByRefIntProp, arginfo_class__ZendTestClass_returnByRefIntProp, ZEND_ACC_PUBLIC) ZEND_FE_END }; diff --git a/ext/zend_test/tests/gen_stub_test_return_by_ref.phpt b/ext/zend_test/tests/gen_stub_test_return_by_ref.phpt new file mode 100644 index 0000000000000..26f3150e7cbc8 --- /dev/null +++ b/ext/zend_test/tests/gen_stub_test_return_by_ref.phpt @@ -0,0 +1,53 @@ +--TEST-- +gen_stub.php: Test that return by ref flag is set +--XFAIL-- +Does not work currently +--EXTENSIONS-- +zend_test +--FILE-- +returnsReference()); + +$o = new _ZendTestClass(); +var_dump($o); +$i = $o->returnByRefIntProp(); +var_dump($i); +$i = 24; +var_dump($i); +var_dump($o); + +?> +--EXPECT-- +bool(true) +object(_ZendTestClass)#2 (3) { + ["intProp"]=> + int(123) + ["classProp"]=> + NULL + ["classUnionProp"]=> + NULL + ["classIntersectionProp"]=> + uninitialized(Traversable&Countable) + ["readonlyProp"]=> + uninitialized(int) + ["dnfProperty"]=> + uninitialized(Iterator|(Traversable&Countable)) +} +int(123) +int(24) +object(_ZendTestClass)#2 (3) { + ["intProp"]=> + int(24) + ["classProp"]=> + NULL + ["classUnionProp"]=> + NULL + ["classIntersectionProp"]=> + uninitialized(Traversable&Countable) + ["readonlyProp"]=> + uninitialized(int) + ["dnfProperty"]=> + uninitialized(Iterator|(Traversable&Countable)) +} From 49f20ae2e6b249daa9e9c5be34a36452e19cd892 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Fri, 31 May 2024 20:57:43 +0100 Subject: [PATCH 2/5] gen_stub: Add return by reference flag --- build/gen_stub.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/build/gen_stub.php b/build/gen_stub.php index bc81b033f14b0..cce02f9231c83 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -1583,6 +1583,10 @@ private function getArginfoFlagsByPhpVersions(): array $flags[] = "ZEND_ACC_DEPRECATED"; } + if ($this->return->byRef) { + $flags[] = "ZEND_ACC_RETURN_REFERENCE"; + } + $php82AndAboveFlags = $flags; if ($this->isMethod() === false && $this->supportsCompileTimeEval) { $php82AndAboveFlags[] = "ZEND_ACC_COMPILE_TIME_EVAL"; From c4898ea59c5431a5548dbe0c7125f50a541df84d Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 6 Jun 2024 16:52:40 +0100 Subject: [PATCH 3/5] Revert "gen_stub: Add return by reference flag" The flag is already set in reality This reverts commit 1d4d8841749793dfed845f880ff4a59bac72d04e. --- build/gen_stub.php | 4 ---- 1 file changed, 4 deletions(-) diff --git a/build/gen_stub.php b/build/gen_stub.php index cce02f9231c83..bc81b033f14b0 100755 --- a/build/gen_stub.php +++ b/build/gen_stub.php @@ -1583,10 +1583,6 @@ private function getArginfoFlagsByPhpVersions(): array $flags[] = "ZEND_ACC_DEPRECATED"; } - if ($this->return->byRef) { - $flags[] = "ZEND_ACC_RETURN_REFERENCE"; - } - $php82AndAboveFlags = $flags; if ($this->isMethod() === false && $this->supportsCompileTimeEval) { $php82AndAboveFlags[] = "ZEND_ACC_COMPILE_TIME_EVAL"; From 65e32f2fb8adc11dd597b2139d7a8f9a5c7c3755 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 6 Jun 2024 17:08:16 +0100 Subject: [PATCH 4/5] [skip ci] IDK How one is meant to implement a reference return --- ext/zend_test/test.c | 25 +++++++++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 29eb0833fa134..7ba9abd193673 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -1054,8 +1054,29 @@ static ZEND_METHOD(_ZendTestClass, returnByRefIntProp) zval *int_prop = obj->handlers->get_property_ptr_ptr(obj, name, BP_VAR_W, NULL); zend_string_release_ex(name, false); - //ZVAL_MAKE_REF(int_prop, int_prop); - RETURN_COPY(int_prop); + ZEND_ASSERT(int_prop); + ZEND_ASSERT(!Z_ISERROR_P(int_prop)); + + /* Copied from zend_assign_to_variable_reference() */ + zend_reference *ref; + + if (EXPECTED(!Z_ISREF_P(int_prop))) { + ZVAL_NEW_REF(int_prop, int_prop); + } + //else if (UNEXPECTED(return_value == int_prop)) { + // return; + //} + + ref = Z_REF_P(int_prop); + GC_ADDREF(ref); + if (Z_REFCOUNTED_P(return_value)) { + zend_refcounted *garbage = NULL; + garbage = Z_COUNTED_P(return_value); + if (garbage) { + GC_DTOR(garbage); + } + } + ZVAL_REF(return_value, ref); } // Returns a newly allocated DNF type `Iterator|(Traversable&Countable)`. From 09d83d9d4aa1575c32bf2763d46f4695886107e7 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Thu, 6 Jun 2024 21:19:47 +0100 Subject: [PATCH 5/5] [ci skip] Fix issues --- ext/zend_test/test.c | 26 +++++-------------- .../tests/gen_stub_test_return_by_ref.phpt | 6 ++--- 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/ext/zend_test/test.c b/ext/zend_test/test.c index 7ba9abd193673..c779f0351ea8a 100644 --- a/ext/zend_test/test.c +++ b/ext/zend_test/test.c @@ -1057,26 +1057,14 @@ static ZEND_METHOD(_ZendTestClass, returnByRefIntProp) ZEND_ASSERT(int_prop); ZEND_ASSERT(!Z_ISERROR_P(int_prop)); - /* Copied from zend_assign_to_variable_reference() */ - zend_reference *ref; - - if (EXPECTED(!Z_ISREF_P(int_prop))) { - ZVAL_NEW_REF(int_prop, int_prop); - } - //else if (UNEXPECTED(return_value == int_prop)) { - // return; - //} - - ref = Z_REF_P(int_prop); - GC_ADDREF(ref); - if (Z_REFCOUNTED_P(return_value)) { - zend_refcounted *garbage = NULL; - garbage = Z_COUNTED_P(return_value); - if (garbage) { - GC_DTOR(garbage); - } + if (!Z_ISREF_P(int_prop)) { + zend_property_info *prop_info = zend_get_property_info_for_slot(obj, int_prop); + ZEND_ASSERT(ZEND_TYPE_IS_SET(prop_info->type)); + ZVAL_MAKE_REF(int_prop); + ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(int_prop), prop_info); } - ZVAL_REF(return_value, ref); + + ZVAL_COPY(return_value, int_prop); } // Returns a newly allocated DNF type `Iterator|(Traversable&Countable)`. diff --git a/ext/zend_test/tests/gen_stub_test_return_by_ref.phpt b/ext/zend_test/tests/gen_stub_test_return_by_ref.phpt index 26f3150e7cbc8..a035ac390f373 100644 --- a/ext/zend_test/tests/gen_stub_test_return_by_ref.phpt +++ b/ext/zend_test/tests/gen_stub_test_return_by_ref.phpt @@ -1,7 +1,5 @@ --TEST-- gen_stub.php: Test that return by ref flag is set ---XFAIL-- -Does not work currently --EXTENSIONS-- zend_test --FILE-- @@ -12,7 +10,7 @@ var_dump($reflectionMethod->returnsReference()); $o = new _ZendTestClass(); var_dump($o); -$i = $o->returnByRefIntProp(); +$i =& $o->returnByRefIntProp(); var_dump($i); $i = 24; var_dump($i); @@ -39,7 +37,7 @@ int(123) int(24) object(_ZendTestClass)#2 (3) { ["intProp"]=> - int(24) + &int(24) ["classProp"]=> NULL ["classUnionProp"]=>