Merge branch 'PHP-8.1'

This commit is contained in:
Bob Weinand 2022-03-07 22:17:35 +01:00
commit 185a14685d
8 changed files with 482 additions and 7 deletions

View file

@ -665,6 +665,22 @@ static void function_copy_ctor(zval *zv) /* {{{ */
}
func->common.arg_info = new_arg_info + 1;
}
if (old_func->common.attributes) {
zend_attribute *old_attr;
func->common.attributes = NULL;
ZEND_HASH_PACKED_FOREACH_PTR(old_func->common.attributes, old_attr) {
uint32_t i;
zend_attribute *attr;
attr = zend_add_attribute(&func->common.attributes, old_attr->name, old_attr->argc, old_attr->flags, old_attr->offset, old_attr->lineno);
for (i = 0 ; i < old_attr->argc; i++) {
ZVAL_DUP(&attr->args[i].value, &old_attr->args[i].value);
}
} ZEND_HASH_FOREACH_END();
}
}
/* }}} */

View file

@ -205,6 +205,7 @@ ZEND_API bool zend_is_attribute_repeated(HashTable *attributes, zend_attribute *
static void attr_free(zval *v)
{
zend_attribute *attr = Z_PTR_P(v);
bool persistent = attr->flags & ZEND_ATTRIBUTE_PERSISTENT;
zend_string_release(attr->name);
zend_string_release(attr->lcname);
@ -213,10 +214,14 @@ static void attr_free(zval *v)
if (attr->args[i].name) {
zend_string_release(attr->args[i].name);
}
zval_ptr_dtor(&attr->args[i].value);
if (persistent) {
zval_internal_ptr_dtor(&attr->args[i].value);
} else {
zval_ptr_dtor(&attr->args[i].value);
}
}
pefree(attr, attr->flags & ZEND_ATTRIBUTE_PERSISTENT);
pefree(attr, persistent);
}
ZEND_API zend_attribute *zend_add_attribute(HashTable **attributes, zend_string *name, uint32_t argc, uint32_t flags, uint32_t offset, uint32_t lineno)

View file

@ -156,6 +156,11 @@ ZEND_API void zend_function_dtor(zval *zv)
/* For methods this will be called explicitly. */
if (!function->common.scope) {
zend_free_internal_arg_info(&function->internal_function);
if (function->common.attributes) {
zend_hash_release(function->common.attributes);
function->common.attributes = NULL;
}
}
if (!(function->common.fn_flags & ZEND_ACC_ARENA_ALLOCATED)) {
@ -433,11 +438,17 @@ ZEND_API void destroy_zend_class(zval *zv)
zend_hash_destroy(&ce->properties_info);
zend_string_release_ex(ce->name, 1);
/* TODO: eliminate this loop for classes without functions with arg_info */
/* TODO: eliminate this loop for classes without functions with arg_info / attributes */
ZEND_HASH_MAP_FOREACH_PTR(&ce->function_table, fn) {
if ((fn->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS)) &&
fn->common.scope == ce) {
zend_free_internal_arg_info(&fn->internal_function);
if (fn->common.scope == ce) {
if (fn->common.fn_flags & (ZEND_ACC_HAS_RETURN_TYPE|ZEND_ACC_HAS_TYPE_HINTS)) {
zend_free_internal_arg_info(&fn->internal_function);
}
if (fn->common.attributes) {
zend_hash_release(fn->common.attributes);
fn->common.attributes = NULL;
}
}
} ZEND_HASH_FOREACH_END();

View file

@ -37,6 +37,9 @@ static zend_class_entry *zend_test_class;
static zend_class_entry *zend_test_child_class;
static zend_class_entry *zend_test_trait;
static zend_class_entry *zend_test_attribute;
static zend_class_entry *zend_test_parameter_attribute;
static zend_class_entry *zend_test_class_with_method_with_parameter_attribute;
static zend_class_entry *zend_test_child_class_with_method_with_parameter_attribute;
static zend_class_entry *zend_test_ns_foo_class;
static zend_class_entry *zend_test_ns2_foo_class;
static zend_class_entry *zend_test_ns2_ns_foo_class;
@ -313,6 +316,17 @@ static ZEND_FUNCTION(namespaced_func)
RETURN_TRUE;
}
static ZEND_FUNCTION(zend_test_parameter_with_attribute)
{
zend_string *parameter;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(parameter)
ZEND_PARSE_PARAMETERS_END();
RETURN_LONG(1);
}
static zend_object *zend_test_class_new(zend_class_entry *class_type)
{
zend_object *obj = zend_objects_new(class_type);
@ -425,6 +439,50 @@ static ZEND_METHOD(ZendTestNS2_ZendSubNS_Foo, method)
ZEND_PARSE_PARAMETERS_NONE();
}
static ZEND_METHOD(ZendTestParameterAttribute, __construct)
{
zend_string *parameter;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(parameter)
ZEND_PARSE_PARAMETERS_END();
ZVAL_STR_COPY(OBJ_PROP_NUM(Z_OBJ_P(ZEND_THIS), 0), parameter);
}
static ZEND_METHOD(ZendTestClassWithMethodWithParameterAttribute, no_override)
{
zend_string *parameter;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(parameter)
ZEND_PARSE_PARAMETERS_END();
RETURN_LONG(2);
}
static ZEND_METHOD(ZendTestClassWithMethodWithParameterAttribute, override)
{
zend_string *parameter;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(parameter)
ZEND_PARSE_PARAMETERS_END();
RETURN_LONG(3);
}
static ZEND_METHOD(ZendTestChildClassWithMethodWithParameterAttribute, override)
{
zend_string *parameter;
ZEND_PARSE_PARAMETERS_START(1, 1)
Z_PARAM_STR(parameter)
ZEND_PARSE_PARAMETERS_END();
RETURN_LONG(4);
}
PHP_INI_BEGIN()
STD_PHP_INI_BOOLEAN("zend_test.replace_zend_execute_ex", "0", PHP_INI_SYSTEM, OnUpdateBool, replace_zend_execute_ex, zend_zend_test_globals, zend_test_globals)
STD_PHP_INI_BOOLEAN("zend_test.register_passes", "0", PHP_INI_SYSTEM, OnUpdateBool, register_passes, zend_zend_test_globals, zend_test_globals)
@ -460,6 +518,61 @@ PHP_MINIT_FUNCTION(zend_test)
attr->validator = zend_attribute_validate_zendtestattribute;
}
zend_test_parameter_attribute = register_class_ZendTestParameterAttribute();
zend_internal_attribute_register(zend_test_parameter_attribute, ZEND_ATTRIBUTE_TARGET_PARAMETER);
{
zend_attribute *attr;
attr = zend_add_parameter_attribute(
zend_hash_str_find_ptr(CG(function_table), "zend_test_parameter_with_attribute", sizeof("zend_test_parameter_with_attribute") - 1),
0,
zend_test_parameter_attribute->name,
1
);
ZVAL_PSTRING(&attr->args[0].value, "value1");
}
zend_test_class_with_method_with_parameter_attribute = register_class_ZendTestClassWithMethodWithParameterAttribute();
{
zend_attribute *attr;
attr = zend_add_parameter_attribute(
zend_hash_str_find_ptr(&zend_test_class_with_method_with_parameter_attribute->function_table, "no_override", sizeof("no_override") - 1),
0,
zend_test_parameter_attribute->name,
1
);
ZVAL_PSTRING(&attr->args[0].value, "value2");
attr = zend_add_parameter_attribute(
zend_hash_str_find_ptr(&zend_test_class_with_method_with_parameter_attribute->function_table, "override", sizeof("override") - 1),
0,
zend_test_parameter_attribute->name,
1
);
ZVAL_PSTRING(&attr->args[0].value, "value3");
}
zend_test_child_class_with_method_with_parameter_attribute = register_class_ZendTestChildClassWithMethodWithParameterAttribute(zend_test_class_with_method_with_parameter_attribute);
{
zend_attribute *attr;
attr = zend_add_parameter_attribute(
zend_hash_str_find_ptr(&zend_test_child_class_with_method_with_parameter_attribute->function_table, "override", sizeof("override") - 1),
0,
zend_test_parameter_attribute->name,
1
);
ZVAL_PSTRING(&attr->args[0].value, "value4");
}
zend_test_ns_foo_class = register_class_ZendTestNS_Foo();
zend_test_ns2_foo_class = register_class_ZendTestNS2_Foo();
zend_test_ns2_ns_foo_class = register_class_ZendTestNS2_ZendSubNS_Foo();

View file

@ -45,6 +45,21 @@ namespace {
}
final class ZendTestParameterAttribute {
public string $parameter;
public function __construct(string $parameter) {}
}
class ZendTestClassWithMethodWithParameterAttribute {
final public function no_override(string $parameter): int {}
public function override(string $parameter): int {}
}
class ZendTestChildClassWithMethodWithParameterAttribute extends ZendTestClassWithMethodWithParameterAttribute {
public function override(string $parameter): int {}
}
enum ZendTestUnitEnum {
case Foo;
case Bar;
@ -92,6 +107,8 @@ namespace {
function zend_weakmap_dump(): array {}
function zend_get_unit_enum(): ZendTestUnitEnum {}
function zend_test_parameter_with_attribute(#[ZendTestParameterAttribute] string $parameter): int {}
}
namespace ZendTestNS {

View file

@ -1,5 +1,5 @@
/* This is a generated file, edit the .stub.php file instead.
* Stub hash: 7326163f8ce5340c12e74af72d47a8926eb39786 */
* Stub hash: af5d698b35753ac9f852688644d6844ba0914b2b */
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_array_return, 0, 0, IS_ARRAY, 0)
ZEND_END_ARG_INFO()
@ -71,6 +71,10 @@ ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_zend_get_unit_enum, 0, 0, ZendTestUnitEnum, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_zend_test_parameter_with_attribute, 0, 1, IS_LONG, 0)
ZEND_ARG_TYPE_INFO(0, parameter, IS_STRING, 0)
ZEND_END_ARG_INFO()
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_ZendTestNS2_ZendSubNS_namespaced_func, 0, 0, _IS_BOOL, 0)
ZEND_END_ARG_INFO()
@ -91,6 +95,16 @@ ZEND_END_ARG_INFO()
#define arginfo_class__ZendTestTrait_testMethod arginfo_ZendTestNS2_ZendSubNS_namespaced_func
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_ZendTestParameterAttribute___construct, 0, 0, 1)
ZEND_ARG_TYPE_INFO(0, parameter, IS_STRING, 0)
ZEND_END_ARG_INFO()
#define arginfo_class_ZendTestClassWithMethodWithParameterAttribute_no_override arginfo_zend_test_parameter_with_attribute
#define arginfo_class_ZendTestClassWithMethodWithParameterAttribute_override arginfo_zend_test_parameter_with_attribute
#define arginfo_class_ZendTestChildClassWithMethodWithParameterAttribute_override arginfo_zend_test_parameter_with_attribute
#define arginfo_class_ZendTestNS_Foo_method arginfo_zend_test_void_return
#define arginfo_class_ZendTestNS2_Foo_method arginfo_zend_test_void_return
@ -116,6 +130,7 @@ static ZEND_FUNCTION(zend_weakmap_attach);
static ZEND_FUNCTION(zend_weakmap_remove);
static ZEND_FUNCTION(zend_weakmap_dump);
static ZEND_FUNCTION(zend_get_unit_enum);
static ZEND_FUNCTION(zend_test_parameter_with_attribute);
static ZEND_FUNCTION(namespaced_func);
static ZEND_METHOD(_ZendTestClass, is_object);
static ZEND_METHOD(_ZendTestClass, __toString);
@ -123,6 +138,10 @@ static ZEND_METHOD(_ZendTestClass, returnsStatic);
static ZEND_METHOD(_ZendTestClass, returnsThrowable);
static ZEND_METHOD(_ZendTestChildClass, returnsThrowable);
static ZEND_METHOD(_ZendTestTrait, testMethod);
static ZEND_METHOD(ZendTestParameterAttribute, __construct);
static ZEND_METHOD(ZendTestClassWithMethodWithParameterAttribute, no_override);
static ZEND_METHOD(ZendTestClassWithMethodWithParameterAttribute, override);
static ZEND_METHOD(ZendTestChildClassWithMethodWithParameterAttribute, override);
static ZEND_METHOD(ZendTestNS_Foo, method);
static ZEND_METHOD(ZendTestNS2_Foo, method);
static ZEND_METHOD(ZendTestNS2_ZendSubNS_Foo, method);
@ -147,6 +166,7 @@ static const zend_function_entry ext_functions[] = {
ZEND_FE(zend_weakmap_remove, arginfo_zend_weakmap_remove)
ZEND_FE(zend_weakmap_dump, arginfo_zend_weakmap_dump)
ZEND_FE(zend_get_unit_enum, arginfo_zend_get_unit_enum)
ZEND_FE(zend_test_parameter_with_attribute, arginfo_zend_test_parameter_with_attribute)
ZEND_NS_FE("ZendTestNS2\\ZendSubNS", namespaced_func, arginfo_ZendTestNS2_ZendSubNS_namespaced_func)
ZEND_FE_END
};
@ -183,6 +203,25 @@ static const zend_function_entry class_ZendTestAttribute_methods[] = {
};
static const zend_function_entry class_ZendTestParameterAttribute_methods[] = {
ZEND_ME(ZendTestParameterAttribute, __construct, arginfo_class_ZendTestParameterAttribute___construct, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
static const zend_function_entry class_ZendTestClassWithMethodWithParameterAttribute_methods[] = {
ZEND_ME(ZendTestClassWithMethodWithParameterAttribute, no_override, arginfo_class_ZendTestClassWithMethodWithParameterAttribute_no_override, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
ZEND_ME(ZendTestClassWithMethodWithParameterAttribute, override, arginfo_class_ZendTestClassWithMethodWithParameterAttribute_override, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
static const zend_function_entry class_ZendTestChildClassWithMethodWithParameterAttribute_methods[] = {
ZEND_ME(ZendTestChildClassWithMethodWithParameterAttribute, override, arginfo_class_ZendTestChildClassWithMethodWithParameterAttribute_override, ZEND_ACC_PUBLIC)
ZEND_FE_END
};
static const zend_function_entry class_ZendTestUnitEnum_methods[] = {
ZEND_FE_END
};
@ -314,6 +353,43 @@ static zend_class_entry *register_class_ZendTestAttribute(void)
return class_entry;
}
static zend_class_entry *register_class_ZendTestParameterAttribute(void)
{
zend_class_entry ce, *class_entry;
INIT_CLASS_ENTRY(ce, "ZendTestParameterAttribute", class_ZendTestParameterAttribute_methods);
class_entry = zend_register_internal_class_ex(&ce, NULL);
class_entry->ce_flags |= ZEND_ACC_FINAL;
zval property_parameter_default_value;
ZVAL_UNDEF(&property_parameter_default_value);
zend_string *property_parameter_name = zend_string_init("parameter", sizeof("parameter") - 1, 1);
zend_declare_typed_property(class_entry, property_parameter_name, &property_parameter_default_value, ZEND_ACC_PUBLIC, NULL, (zend_type) ZEND_TYPE_INIT_MASK(MAY_BE_STRING));
zend_string_release(property_parameter_name);
return class_entry;
}
static zend_class_entry *register_class_ZendTestClassWithMethodWithParameterAttribute(void)
{
zend_class_entry ce, *class_entry;
INIT_CLASS_ENTRY(ce, "ZendTestClassWithMethodWithParameterAttribute", class_ZendTestClassWithMethodWithParameterAttribute_methods);
class_entry = zend_register_internal_class_ex(&ce, NULL);
return class_entry;
}
static zend_class_entry *register_class_ZendTestChildClassWithMethodWithParameterAttribute(zend_class_entry *class_entry_ZendTestClassWithMethodWithParameterAttribute)
{
zend_class_entry ce, *class_entry;
INIT_CLASS_ENTRY(ce, "ZendTestChildClassWithMethodWithParameterAttribute", class_ZendTestChildClassWithMethodWithParameterAttribute_methods);
class_entry = zend_register_internal_class_ex(&ce, class_entry_ZendTestClassWithMethodWithParameterAttribute);
return class_entry;
}
static zend_class_entry *register_class_ZendTestUnitEnum(void)
{
zend_class_entry *class_entry = zend_register_internal_enum("ZendTestUnitEnum", IS_UNDEF, class_ZendTestUnitEnum_methods);

View file

@ -0,0 +1,169 @@
--TEST--
Verify that parameter attributes for native functions correctly support arguments.
--EXTENSIONS--
zend_test
--FILE--
<?php
$reflection = new ReflectionFunction("zend_test_parameter_with_attribute");
$attribute = $reflection->getParameters()[0]->getAttributes()[0];
var_dump($attribute->getArguments());
var_dump($attribute->newInstance());
$reflection = new ReflectionMethod("ZendTestClassWithMethodWithParameterAttribute", "no_override");
$attribute = $reflection->getParameters()[0]->getAttributes()[0];
var_dump($attribute->getArguments());
var_dump($attribute->newInstance());
$reflection = new ReflectionMethod("ZendTestClassWithMethodWithParameterAttribute", "override");
$attribute = $reflection->getParameters()[0]->getAttributes()[0];
var_dump($attribute->getArguments());
var_dump($attribute->newInstance());
$reflection = new ReflectionMethod("ZendTestChildClassWithMethodWithParameterAttribute", "no_override");
$attribute = $reflection->getParameters()[0]->getAttributes()[0];
var_dump($attribute->getArguments());
var_dump($attribute->newInstance());
$reflection = new ReflectionMethod("ZendTestChildClassWithMethodWithParameterAttribute", "override");
$attribute = $reflection->getParameters()[0]->getAttributes()[0];
var_dump($attribute->getArguments());
var_dump($attribute->newInstance());
class ChildClassWithNoAttribute extends ZendTestClassWithMethodWithParameterAttribute {
public function override(string $parameter): int
{
return 5;
}
}
$reflection = new ReflectionMethod("ChildClassWithNoAttribute", "no_override");
$attribute = $reflection->getParameters()[0]->getAttributes()[0];
var_dump($attribute->getArguments());
var_dump($attribute->newInstance());
$reflection = new ReflectionMethod("ChildClassWithNoAttribute", "override");
var_dump(count($reflection->getParameters()[0]->getAttributes()));
class ChildClassWithSameAttribute extends ZendTestClassWithMethodWithParameterAttribute {
public function override(#[ZendTestParameterAttribute("value5")] string $parameter): int
{
return 6;
}
}
$reflection = new ReflectionMethod("ChildClassWithSameAttribute", "no_override");
$attribute = $reflection->getParameters()[0]->getAttributes()[0];
var_dump($attribute->getArguments());
var_dump($attribute->newInstance());
$reflection = new ReflectionMethod("ChildClassWithSameAttribute", "override");
$attribute = $reflection->getParameters()[0]->getAttributes()[0];
var_dump($attribute->getArguments());
var_dump($attribute->newInstance());
#[\Attribute(\Attribute::TARGET_PARAMETER)]
class SomeAttribute {
public function __construct(public string $someParam) { }
}
class ChildClassWithDifferentAttribute extends ZendTestClassWithMethodWithParameterAttribute {
public function override(#[SomeAttribute("value6")] string $parameter): int
{
return 7;
}
}
$reflection = new ReflectionMethod("ChildClassWithDifferentAttribute", "no_override");
$attribute = $reflection->getParameters()[0]->getAttributes()[0];
var_dump($attribute->getArguments());
var_dump($attribute->newInstance());
$reflection = new ReflectionMethod("ChildClassWithDifferentAttribute", "override");
$attribute = $reflection->getParameters()[0]->getAttributes()[0];
var_dump($attribute->getArguments());
var_dump($attribute->newInstance());
?>
--EXPECTF--
array(1) {
[0]=>
string(6) "value1"
}
object(ZendTestParameterAttribute)#%d (1) {
["parameter"]=>
string(6) "value1"
}
array(1) {
[0]=>
string(6) "value2"
}
object(ZendTestParameterAttribute)#%d (1) {
["parameter"]=>
string(6) "value2"
}
array(1) {
[0]=>
string(6) "value3"
}
object(ZendTestParameterAttribute)#%d (1) {
["parameter"]=>
string(6) "value3"
}
array(1) {
[0]=>
string(6) "value2"
}
object(ZendTestParameterAttribute)#%d (1) {
["parameter"]=>
string(6) "value2"
}
array(1) {
[0]=>
string(6) "value4"
}
object(ZendTestParameterAttribute)#%d (1) {
["parameter"]=>
string(6) "value4"
}
array(1) {
[0]=>
string(6) "value2"
}
object(ZendTestParameterAttribute)#%d (1) {
["parameter"]=>
string(6) "value2"
}
int(0)
array(1) {
[0]=>
string(6) "value2"
}
object(ZendTestParameterAttribute)#%d (1) {
["parameter"]=>
string(6) "value2"
}
array(1) {
[0]=>
string(6) "value5"
}
object(ZendTestParameterAttribute)#%d (1) {
["parameter"]=>
string(6) "value5"
}
array(1) {
[0]=>
string(6) "value2"
}
object(ZendTestParameterAttribute)#%d (1) {
["parameter"]=>
string(6) "value2"
}
array(1) {
[0]=>
string(6) "value6"
}
object(SomeAttribute)#%d (1) {
["someParam"]=>
string(6) "value6"
}

View file

@ -0,0 +1,68 @@
--TEST--
Verify that parameter attributes for native functions do not leak.
--EXTENSIONS--
zend_test
--FILE--
<?php
var_dump(zend_test_parameter_with_attribute("foo"));
$o = new ZendTestClassWithMethodWithParameterAttribute();
var_dump($o->no_override("foo"));
var_dump($o->override("foo"));
$o = new ZendTestChildClassWithMethodWithParameterAttribute();
var_dump($o->no_override("foo"));
var_dump($o->override("foo"));
class ChildClassWithNoAttribute extends ZendTestClassWithMethodWithParameterAttribute {
public function override(string $parameter): int
{
return 5;
}
}
$o = new ChildClassWithNoAttribute();
var_dump($o->no_override("foo"));
var_dump($o->override("foo"));
class ChildClassWithSameAttribute extends ZendTestClassWithMethodWithParameterAttribute {
public function override(#[ZendTestParameterAttribute] string $parameter): int
{
return 6;
}
}
$o = new ChildClassWithSameAttribute();
var_dump($o->no_override("foo"));
var_dump($o->override("foo"));
#[\Attribute(\Attribute::TARGET_PARAMETER)]
class SomeAttribute {
}
class ChildClassWithDifferentAttribute extends ZendTestClassWithMethodWithParameterAttribute {
public function override(#[SomeAttribute] string $parameter): int
{
return 7;
}
}
$o = new ChildClassWithDifferentAttribute();
var_dump($o->no_override("foo"));
var_dump($o->override("foo"));
?>
--EXPECT--
int(1)
int(2)
int(3)
int(2)
int(4)
int(2)
int(5)
int(2)
int(6)
int(2)
int(7)