Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .github/actions/freebsd/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ runs:
- name: FreeBSD
uses: vmactions/freebsd-vm@v1
with:
release: '13.3'
release: '13.5'
usesh: true
copyback: false
# Temporarily disable sqlite, as FreeBSD ships it with disabled double quotes. We'll need to fix our tests.
Expand Down
4 changes: 4 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,10 @@ PHP NEWS
. Add support for CURLINFO_CONN_ID in curl_getinfo() (thecaliskan)
. Add support for CURLINFO_QUEUE_TIME_T in curl_getinfo() (thecaliskan)

- Reflection:
. Fixed bug GH-19187 (ReflectionNamedType::getName() prints nullable type when
retrieved from ReflectionProperty::getSettableType()). (ilutov)

- Session:
. Fixed GH-19197: build broken with ZEND_STRL usage with memcpy
when implemented as macro. (David Carlier)
Expand Down
24 changes: 24 additions & 0 deletions Zend/tests/asymmetric_visibility/gh19044.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
--TEST--
GH-19044: Protected properties must be scoped according to their prototype (protected(set) on non-hooked property)
--FILE--
<?php

class P {
public mixed $foo { get => 42; }
}

class C1 extends P {
public protected(set) mixed $foo = 1;
}

class C2 extends P {
public protected(set) mixed $foo;

static function foo($c) { return $c->foo += 1; }
}

var_dump(C2::foo(new C1));

?>
--EXPECT--
int(43)
32 changes: 32 additions & 0 deletions Zend/tests/gh18581.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
--TEST--
GH-18581: Coerce numeric string keys from iterators when argument unpacking
--FILE--
<?php

function g() {
yield '100' => 'first';
yield '101' => 'second';
yield '102' => 'third';
yield 'named' => 'fourth';
}

function test($x = null, $y = null, ...$z) {
var_dump($x, $y, $z);
var_dump($z[0]);
var_dump($z['named']);
}

test(...g());

?>
--EXPECT--
string(5) "first"
string(6) "second"
array(2) {
[0]=>
string(5) "third"
["named"]=>
string(6) "fourth"
}
string(5) "third"
string(6) "fourth"
26 changes: 26 additions & 0 deletions Zend/tests/gh19044.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--TEST--
GH-19044: Protected properties must be scoped according to their prototype
--FILE--
<?php

abstract class P {
protected $foo;
}

class C1 extends P {
protected $foo = 1;
}

class C2 extends P {
protected $foo = 2;

static function foo($c) { return $c->foo; }
}

var_dump(C2::foo(new C2));
var_dump(C2::foo(new C1));

?>
--EXPECT--
int(2)
int(1)
26 changes: 26 additions & 0 deletions Zend/tests/property_hooks/gh19044-1.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--TEST--
GH-19044: Protected properties must be scoped according to their prototype (common ancestor has a protected setter)
--FILE--
<?php

abstract class P {
abstract public mixed $foo { get; }
}

class C1 extends P {
public protected(set) mixed $foo { get => 1; set {} }
}

class GrandC1 extends C1 {
public protected(set) mixed $foo { get => 2; set {} }
}

class C2 extends C1 {
static function foo($c) { return $c->foo += 1; }
}

var_dump(C2::foo(new GrandC1));

?>
--EXPECT--
int(3)
26 changes: 26 additions & 0 deletions Zend/tests/property_hooks/gh19044-2.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--TEST--
GH-19044: Protected properties must be scoped according to their prototype (common ancestor does not have a setter)
--FILE--
<?php

abstract class P {
abstract public mixed $foo { get; }
}

class C1 extends P {
public mixed $foo { get => 1; }
}

class GrandC1 extends C1 {
public protected(set) mixed $foo { get => 2; set {} }
}

class C2 extends C1 {
static function foo($c) { return $c->foo += 1; }
}

var_dump(C2::foo(new GrandC1));

?>
--EXPECT--
int(3)
24 changes: 24 additions & 0 deletions Zend/tests/property_hooks/gh19044-3.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
--TEST--
GH-19044: Protected properties must be scoped according to their prototype (abstract parent defining visibility only takes precedence)
--FILE--
<?php

abstract class P {
abstract protected(set) mixed $foo { get; set; }
}

class C1 extends P {
public protected(set) mixed $foo { get => 2; set {} }
}

class C2 extends P {
public mixed $foo = 1;

static function foo($c) { return $c->foo += 1; }
}

var_dump(C2::foo(new C1));

?>
--EXPECT--
int(3)
28 changes: 28 additions & 0 deletions Zend/tests/property_hooks/gh19044-4.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
--TEST--
GH-19044: Protected properties must be scoped according to their prototype (abstract parent sets protected(set) with not having grandparent a setter - both inherit from parent)
--FILE--
<?php

abstract class GP {
abstract mixed $foo { get; }
}

abstract class P extends GP {
abstract protected(set) mixed $foo { get; set; }
}

class C1 extends P {
public protected(set) mixed $foo { get => 2; set {} }
}

class C2 extends P {
public mixed $foo = 1;

static function foo($c) { return $c->foo += 1; }
}

var_dump(C2::foo(new C1));

?>
--EXPECT--
int(3)
28 changes: 28 additions & 0 deletions Zend/tests/property_hooks/gh19044-5.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
--TEST--
GH-19044: Protected properties must be scoped according to their prototype (abstract parent sets protected(set) with not having grandparent a setter - one inherits from grandparent)
--FILE--
<?php

abstract class GP {
abstract mixed $foo { get; }
}

abstract class P extends GP {
abstract protected(set) mixed $foo { get; set; }
}

class C1 extends P {
public protected(set) mixed $foo { get => 2; set {} }
}

class C2 extends GP {
public mixed $foo = 1;

static function foo($c) { return $c->foo += 1; }
}

var_dump(C2::foo(new C1));

?>
--EXPECT--
int(3)
28 changes: 28 additions & 0 deletions Zend/tests/property_hooks/gh19044-6.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
--TEST--
GH-19044: Protected properties must be scoped according to their prototype (abstract parent has implicit set hook)
--FILE--
<?php

abstract class GP {
public abstract mixed $foo { get; }
}

class P extends GP {
public protected(set) mixed $foo { get => $this->foo; }
}

class C1 extends P {
public protected(set) mixed $foo = 1;
}

class C2 extends P {
public protected(set) mixed $foo;

static function foo($c) { return $c->foo += 1; }
}

var_dump(C2::foo(new C1));

?>
--EXPECT--
int(2)
26 changes: 26 additions & 0 deletions Zend/tests/property_hooks/gh19044-8.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--TEST--
GH-19044: Protected properties must be scoped according to their prototype (hooks variation)
--FILE--
<?php

abstract class P {
abstract protected $foo { get; }
}

class C1 extends P {
protected $foo = 1;
}

class C2 extends P {
protected $foo = 2;

static function foo($c) { return $c->foo; }
}

var_dump(C2::foo(new C2));
var_dump(C2::foo(new C1));

?>
--EXPECT--
int(2)
int(1)
10 changes: 5 additions & 5 deletions Zend/zend_object_handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,7 @@ static zend_always_inline bool is_derived_class(const zend_class_entry *child_cl
static zend_never_inline int is_protected_compatible_scope(const zend_class_entry *ce, const zend_class_entry *scope) /* {{{ */
{
return scope &&
(is_derived_class(ce, scope) || is_derived_class(scope, ce));
(ce == scope || is_derived_class(ce, scope) || is_derived_class(scope, ce));
}
/* }}} */

Expand Down Expand Up @@ -422,7 +422,7 @@ static zend_always_inline uintptr_t zend_get_property_offset(zend_class_entry *c
}
} else {
ZEND_ASSERT(flags & ZEND_ACC_PROTECTED);
if (UNEXPECTED(!is_protected_compatible_scope(property_info->ce, scope))) {
if (UNEXPECTED(!is_protected_compatible_scope(property_info->prototype->ce, scope))) {
goto wrong;
}
}
Expand Down Expand Up @@ -517,7 +517,7 @@ ZEND_API zend_property_info *zend_get_property_info(const zend_class_entry *ce,
}
} else {
ZEND_ASSERT(flags & ZEND_ACC_PROTECTED);
if (UNEXPECTED(!is_protected_compatible_scope(property_info->ce, scope))) {
if (UNEXPECTED(!is_protected_compatible_scope(property_info->prototype->ce, scope))) {
goto wrong;
}
}
Expand Down Expand Up @@ -588,7 +588,7 @@ ZEND_API bool ZEND_FASTCALL zend_asymmetric_property_has_set_access(const zend_p
return true;
}
return EXPECTED((prop_info->flags & ZEND_ACC_PROTECTED_SET)
&& is_protected_compatible_scope(prop_info->ce, scope));
&& is_protected_compatible_scope(prop_info->prototype->ce, scope));
}

static void zend_property_guard_dtor(zval *el) /* {{{ */ {
Expand Down Expand Up @@ -2033,7 +2033,7 @@ ZEND_API zval *zend_std_get_static_property_with_info(zend_class_entry *ce, zend
const zend_class_entry *scope = get_fake_or_executed_scope();
if (property_info->ce != scope) {
if (UNEXPECTED(property_info->flags & ZEND_ACC_PRIVATE)
|| UNEXPECTED(!is_protected_compatible_scope(property_info->ce, scope))) {
|| UNEXPECTED(!is_protected_compatible_scope(property_info->prototype->ce, scope))) {
if (type != BP_VAR_IS) {
zend_bad_property_access(property_info, ce, property_name);
}
Expand Down
5 changes: 5 additions & 0 deletions Zend/zend_vm_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -5392,6 +5392,11 @@ ZEND_VM_C_LABEL(send_again):
}

name = Z_STR_P(&key);

zend_ulong tmp;
if (ZEND_HANDLE_NUMERIC(name, tmp)) {
name = NULL;
}
}
}

Expand Down
5 changes: 5 additions & 0 deletions Zend/zend_vm_execute.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions ext/reflection/php_reflection.c
Original file line number Diff line number Diff line change
Expand Up @@ -6403,7 +6403,7 @@ ZEND_METHOD(ReflectionProperty, getSettableType)
/* Get-only virtual property can never be written to. */
if (prop->hooks && (prop->flags & ZEND_ACC_VIRTUAL) && !prop->hooks[ZEND_PROPERTY_HOOK_SET]) {
zend_type never_type = ZEND_TYPE_INIT_CODE(IS_NEVER, 0, 0);
reflection_type_factory(never_type, return_value, 0);
reflection_type_factory(never_type, return_value, 1);
return;
}

Expand All @@ -6413,15 +6413,15 @@ ZEND_METHOD(ReflectionProperty, getSettableType)
if (!ZEND_TYPE_IS_SET(arg_info->type)) {
RETURN_NULL();
}
reflection_type_factory(arg_info->type, return_value, 0);
reflection_type_factory(arg_info->type, return_value, 1);
return;
}

/* Fall back to property type */
if (!ZEND_TYPE_IS_SET(ref->prop->type)) {
RETURN_NULL();
}
reflection_type_factory(ref->prop->type, return_value, 0);
reflection_type_factory(ref->prop->type, return_value, 1);
}

/* {{{ Returns whether property has a type */
Expand Down
Loading