Skip to content

Commit a1ea464

Browse files
authored
gen_stub: Intern the parameter name string for named arguments in internal attributes (#14595)
This is necessary because `zend_get_attribute_object()` will use the persistent string with the parameter name as the index for a newly created non-persistent HashTable, which is not legal. As parameter names are expected to be short-ish, reasonably common terms and need to sit around in memory anyways, we might as well make them an interned string, circumstepping the issue without needing to duplicate the parameter name into a non-persistent string.
1 parent 0c3dd16 commit a1ea464

File tree

5 files changed

+107
-2
lines changed

5 files changed

+107
-2
lines changed

build/gen_stub.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3124,7 +3124,7 @@ public function generateCode(string $invocation, string $nameSuffix, array $allC
31243124
$code .= $value->initializeZval($zvalName);
31253125
$code .= "\tZVAL_COPY_VALUE(&attribute_{$escapedAttributeName}_{$nameSuffix}->args[$i].value, &$zvalName);\n";
31263126
if ($arg->name) {
3127-
$code .= "\tattribute_{$escapedAttributeName}_{$nameSuffix}->args[$i].name = zend_string_init(\"{$arg->name->name}\", sizeof(\"{$arg->name->name}\") - 1, 1);\n";
3127+
$code .= "\tattribute_{$escapedAttributeName}_{$nameSuffix}->args[$i].name = zend_string_init_interned(\"{$arg->name->name}\", sizeof(\"{$arg->name->name}\") - 1, 1);\n";
31283128
}
31293129
}
31303130
return $code;

ext/zend_test/test.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ static zend_class_entry *zend_test_attribute;
5858
static zend_class_entry *zend_test_repeatable_attribute;
5959
static zend_class_entry *zend_test_parameter_attribute;
6060
static zend_class_entry *zend_test_property_attribute;
61+
static zend_class_entry *zend_test_attribute_with_arguments;
6162
static zend_class_entry *zend_test_class_with_method_with_parameter_attribute;
6263
static zend_class_entry *zend_test_child_class_with_method_with_parameter_attribute;
6364
static zend_class_entry *zend_test_class_with_property_attribute;
@@ -575,6 +576,11 @@ static ZEND_FUNCTION(zend_test_parameter_with_attribute)
575576
RETURN_LONG(1);
576577
}
577578

579+
static ZEND_FUNCTION(zend_test_attribute_with_named_argument)
580+
{
581+
ZEND_PARSE_PARAMETERS_NONE();
582+
}
583+
578584
#ifdef ZEND_CHECK_STACK_LIMIT
579585
static ZEND_FUNCTION(zend_test_zend_call_stack_get)
580586
{
@@ -989,6 +995,19 @@ static ZEND_METHOD(ZendTestPropertyAttribute, __construct)
989995
ZVAL_STR_COPY(OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 0), parameter);
990996
}
991997

998+
static ZEND_METHOD(ZendTestAttributeWithArguments, __construct)
999+
{
1000+
zval *arg;
1001+
1002+
ZEND_PARSE_PARAMETERS_START(1, 1)
1003+
Z_PARAM_ZVAL(arg)
1004+
ZEND_PARSE_PARAMETERS_END();
1005+
1006+
zend_string *property_name = zend_string_init("arg", strlen("arg"), 0);
1007+
zend_update_property_ex(zend_test_attribute_with_arguments, Z_OBJ_P(ZEND_THIS), property_name, arg);
1008+
zend_string_release(property_name);
1009+
}
1010+
9921011
static ZEND_METHOD(ZendTestClassWithMethodWithParameterAttribute, no_override)
9931012
{
9941013
zend_string *parameter;
@@ -1217,6 +1236,9 @@ PHP_MINIT_FUNCTION(zend_test)
12171236
zend_test_property_attribute = register_class_ZendTestPropertyAttribute();
12181237
zend_mark_internal_attribute(zend_test_property_attribute);
12191238

1239+
zend_test_attribute_with_arguments = register_class_ZendTestAttributeWithArguments();
1240+
zend_mark_internal_attribute(zend_test_attribute_with_arguments);
1241+
12201242
zend_test_class_with_method_with_parameter_attribute = register_class_ZendTestClassWithMethodWithParameterAttribute();
12211243
zend_test_child_class_with_method_with_parameter_attribute = register_class_ZendTestChildClassWithMethodWithParameterAttribute(zend_test_class_with_method_with_parameter_attribute);
12221244

ext/zend_test/test.stub.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,13 @@ public function testMethod(): bool {}
104104
final class ZendTestAttribute {
105105
}
106106

107+
#[Attribute(Attribute::TARGET_ALL)]
108+
final class ZendTestAttributeWithArguments {
109+
public readonly mixed $arg;
110+
111+
public function __construct(mixed $arg) {}
112+
}
113+
107114
#[Attribute(Attribute::TARGET_ALL|Attribute::IS_REPEATABLE)]
108115
final class ZendTestRepeatableAttribute {
109116
}
@@ -243,6 +250,9 @@ function zend_test_parameter_with_attribute(
243250
string $parameter
244251
): int {}
245252

253+
#[ZendTestAttributeWithArguments(arg: "foo")]
254+
function zend_test_attribute_with_named_argument(): void {}
255+
246256
function zend_get_current_func_name(): string {}
247257

248258
function zend_call_method(object|string $obj_or_class, string $method, mixed $arg1 = UNKNOWN, mixed $arg2 = UNKNOWN): mixed {}

ext/zend_test/test_arginfo.h

Lines changed: 52 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
Verify that attributes for internal functions correctly support named arguments.
3+
--EXTENSIONS--
4+
zend_test
5+
--FILE--
6+
<?php
7+
8+
$reflection = new ReflectionFunction("zend_test_attribute_with_named_argument");
9+
$attribute = $reflection->getAttributes()[0];
10+
var_dump($attribute->getArguments());
11+
var_dump($attribute->newInstance());
12+
13+
?>
14+
--EXPECTF--
15+
array(1) {
16+
["arg"]=>
17+
string(3) "foo"
18+
}
19+
object(ZendTestAttributeWithArguments)#3 (1) {
20+
["arg"]=>
21+
string(3) "foo"
22+
}

0 commit comments

Comments
 (0)