Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions Zend/tests/property_hooks/gh25264.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
--TEST--
GH-25264: Implementing an interface must not modify inherited property hooks
--FILE--
<?php

class P {
public $prop { get => 1; }
}

class Q {
public $prop { get => 2; set {} }
}

interface I {
public $prop { get; set; }
}

interface J {
public $prop { get; }
}

abstract class A extends P implements I {}

class B extends Q implements I {}

abstract class C implements J, I {}

class D implements J {
public $prop { get => 3; }
}

var_dump((new ReflectionProperty(P::class, 'prop'))->hasHook(PropertyHookType::Set));
var_dump((new ReflectionProperty(J::class, 'prop'))->hasHook(PropertyHookType::Set));
var_dump((new ReflectionProperty(A::class, 'prop'))->hasHook(PropertyHookType::Set));

$p = new P;
try {
$p->prop = 4;
} catch (Error $e) {
echo $e::class, "\n";
}

var_dump((new B)->prop);
var_dump((new D)->prop);

?>
--EXPECT--
bool(false)
bool(false)
bool(true)
Error
int(2)
int(3)
40 changes: 38 additions & 2 deletions Zend/zend_inheritance.c
Original file line number Diff line number Diff line change
Expand Up @@ -1347,12 +1347,36 @@ static bool property_has_operation(zend_property_info *prop_info, zend_property_
|| (prop_info->hooks && prop_info->hooks[kind]);
}

static zend_property_info *separate_property_info(const zend_property_info *prop_info, zend_class_entry *ce)
{
zend_property_info *new_prop_info = zend_arena_alloc(&CG(arena), sizeof(zend_property_info));
memcpy(new_prop_info, prop_info, sizeof(zend_property_info));
new_prop_info->ce = ce;
zend_string_addref(new_prop_info->name);
if (new_prop_info->doc_comment) {
zend_string_addref(new_prop_info->doc_comment);
}
if (new_prop_info->attributes && !(GC_FLAGS(new_prop_info->attributes) & IS_ARRAY_IMMUTABLE)) {
GC_ADDREF(new_prop_info->attributes);
}
zend_type_copy_ctor(&new_prop_info->type, /* use_arena */ true, /* persistent */ false);
if (new_prop_info->hooks) {
new_prop_info->hooks = zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE);
for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
zend_function *hook = prop_info->hooks[i];
new_prop_info->hooks[i] = hook ? zend_duplicate_function(hook, ce) : NULL;
}
}
return new_prop_info;
}

static void inherit_property_hook(
zend_class_entry *ce,
zend_property_info *parent_info,
zend_property_info *child_info,
zval *child_zv,
zend_property_hook_kind kind
) {
zend_property_info *child_info = Z_PTR_P(child_zv);
zend_function *parent = parent_info->hooks ? parent_info->hooks[kind] : NULL;
zend_function *child = child_info->hooks ? child_info->hooks[kind] : NULL;

Expand All @@ -1374,6 +1398,10 @@ static void inherit_property_hook(
}
ce->ce_flags |= ZEND_ACC_IMPLICIT_ABSTRACT_CLASS;
}
if (child_info->ce != ce) {
child_info = separate_property_info(child_info, ce);
Z_PTR_P(child_zv) = child_info;
}
if (!child_info->hooks) {
ce->num_hooked_props++;
child_info->hooks = zend_arena_alloc(&CG(arena), ZEND_PROPERTY_HOOK_STRUCT_SIZE);
Expand All @@ -1383,6 +1411,13 @@ static void inherit_property_hook(
return;
}

if (child->common.scope != ce) {
do_inheritance_check_on_method(
child, child->common.scope, parent, parent->common.scope, ce, /* child */ NULL,
ZEND_INHERITANCE_CHECK_PROTO | ZEND_INHERITANCE_CHECK_VISIBILITY);
return;
}

child->common.prototype = parent->common.prototype ? parent->common.prototype : parent;

uint32_t parent_flags = parent->common.fn_flags;
Expand Down Expand Up @@ -1522,8 +1557,9 @@ static void do_inherit_property(zend_property_info *parent_info, zend_string *ke

if (parent_info->hooks || child_info->hooks) {
for (uint32_t i = 0; i < ZEND_PROPERTY_HOOK_COUNT; i++) {
inherit_property_hook(ce, parent_info, child_info, i);
inherit_property_hook(ce, parent_info, child, i);
}
child_info = Z_PTR_P(child);
}

prop_variance variance = prop_get_variance(parent_info);
Expand Down
Loading