mirror of
https://github.com/php/php-src.git
synced 2025-08-16 22:18:50 +02:00
Merge branch 'PHP-7.4'
* PHP-7.4: Throw Error when referencing uninit typed prop in __sleep
This commit is contained in:
commit
b22daa3a06
2 changed files with 99 additions and 9 deletions
|
@ -0,0 +1,60 @@
|
||||||
|
--TEST--
|
||||||
|
Referencing an uninitialized typed property in __sleep() should result in Error
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Test {
|
||||||
|
public int $x;
|
||||||
|
protected int $y;
|
||||||
|
private int $z;
|
||||||
|
|
||||||
|
public function __sleep() {
|
||||||
|
return ['x', 'y', 'z'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __set($name, $val) {
|
||||||
|
$this->$name = $val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$t = new Test;
|
||||||
|
try {
|
||||||
|
serialize($t);
|
||||||
|
} catch (Error $e) {
|
||||||
|
echo $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$t->x = 1;
|
||||||
|
try {
|
||||||
|
serialize($t);
|
||||||
|
} catch (Error $e) {
|
||||||
|
echo $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$t->y = 2;
|
||||||
|
try {
|
||||||
|
serialize($t);
|
||||||
|
} catch (Error $e) {
|
||||||
|
echo $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
$t->z = 3;
|
||||||
|
try {
|
||||||
|
var_dump(unserialize(serialize($t)));
|
||||||
|
} catch (Error $e) {
|
||||||
|
echo $e->getMessage(), "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Typed property Test::$x must not be accessed before initialization (in __sleep)
|
||||||
|
Typed property Test::$y must not be accessed before initialization (in __sleep)
|
||||||
|
Typed property Test::$z must not be accessed before initialization (in __sleep)
|
||||||
|
object(Test)#3 (3) {
|
||||||
|
["x"]=>
|
||||||
|
int(1)
|
||||||
|
["y":protected]=>
|
||||||
|
int(2)
|
||||||
|
["z":"Test":private]=>
|
||||||
|
int(3)
|
||||||
|
}
|
|
@ -765,7 +765,7 @@ static int php_var_serialize_call_magic_serialize(zval *retval, zval *obj) /* {{
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
static int php_var_serialize_try_add_sleep_prop(
|
static int php_var_serialize_try_add_sleep_prop(
|
||||||
HashTable *ht, HashTable *props, zend_string *name, zend_string *error_name) /* {{{ */
|
HashTable *ht, HashTable *props, zend_string *name, zend_string *error_name, zval *struc) /* {{{ */
|
||||||
{
|
{
|
||||||
zval *val = zend_hash_find(props, name);
|
zval *val = zend_hash_find(props, name);
|
||||||
if (val == NULL) {
|
if (val == NULL) {
|
||||||
|
@ -775,6 +775,12 @@ static int php_var_serialize_try_add_sleep_prop(
|
||||||
if (Z_TYPE_P(val) == IS_INDIRECT) {
|
if (Z_TYPE_P(val) == IS_INDIRECT) {
|
||||||
val = Z_INDIRECT_P(val);
|
val = Z_INDIRECT_P(val);
|
||||||
if (Z_TYPE_P(val) == IS_UNDEF) {
|
if (Z_TYPE_P(val) == IS_UNDEF) {
|
||||||
|
zend_property_info *info = zend_get_typed_property_info_for_slot(Z_OBJ_P(struc), val);
|
||||||
|
if (info) {
|
||||||
|
zend_throw_error(NULL,
|
||||||
|
"Typed property %s::$%s must not be accessed before initialization (in __sleep)",
|
||||||
|
ZSTR_VAL(Z_OBJCE_P(struc)->name), ZSTR_VAL(error_name));
|
||||||
|
}
|
||||||
return FAILURE;
|
return FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -790,14 +796,17 @@ static int php_var_serialize_try_add_sleep_prop(
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
static void php_var_serialize_get_sleep_props(
|
static int php_var_serialize_get_sleep_props(
|
||||||
HashTable *ht, zval *struc, HashTable *sleep_retval) /* {{{ */
|
HashTable *ht, zval *struc, HashTable *sleep_retval) /* {{{ */
|
||||||
{
|
{
|
||||||
zend_class_entry *ce = Z_OBJCE_P(struc);
|
zend_class_entry *ce = Z_OBJCE_P(struc);
|
||||||
HashTable *props = zend_get_properties_for(struc, ZEND_PROP_PURPOSE_SERIALIZE);
|
HashTable *props = zend_get_properties_for(struc, ZEND_PROP_PURPOSE_SERIALIZE);
|
||||||
zval *name_val;
|
zval *name_val;
|
||||||
|
int retval = SUCCESS;
|
||||||
|
|
||||||
zend_hash_init(ht, zend_hash_num_elements(sleep_retval), NULL, ZVAL_PTR_DTOR, 0);
|
zend_hash_init(ht, zend_hash_num_elements(sleep_retval), NULL, ZVAL_PTR_DTOR, 0);
|
||||||
|
/* TODO: Rewrite this by fetching the property info instead of trying out different
|
||||||
|
* name manglings? */
|
||||||
ZEND_HASH_FOREACH_VAL(sleep_retval, name_val) {
|
ZEND_HASH_FOREACH_VAL(sleep_retval, name_val) {
|
||||||
zend_string *name, *tmp_name, *priv_name, *prot_name;
|
zend_string *name, *tmp_name, *priv_name, *prot_name;
|
||||||
|
|
||||||
|
@ -808,36 +817,56 @@ static void php_var_serialize_get_sleep_props(
|
||||||
}
|
}
|
||||||
|
|
||||||
name = zval_get_tmp_string(name_val, &tmp_name);
|
name = zval_get_tmp_string(name_val, &tmp_name);
|
||||||
if (php_var_serialize_try_add_sleep_prop(ht, props, name, name) == SUCCESS) {
|
if (php_var_serialize_try_add_sleep_prop(ht, props, name, name, struc) == SUCCESS) {
|
||||||
zend_tmp_string_release(tmp_name);
|
zend_tmp_string_release(tmp_name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (EG(exception)) {
|
||||||
|
zend_tmp_string_release(tmp_name);
|
||||||
|
retval = FAILURE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
priv_name = zend_mangle_property_name(
|
priv_name = zend_mangle_property_name(
|
||||||
ZSTR_VAL(ce->name), ZSTR_LEN(ce->name),
|
ZSTR_VAL(ce->name), ZSTR_LEN(ce->name),
|
||||||
ZSTR_VAL(name), ZSTR_LEN(name), ce->type & ZEND_INTERNAL_CLASS);
|
ZSTR_VAL(name), ZSTR_LEN(name), ce->type & ZEND_INTERNAL_CLASS);
|
||||||
if (php_var_serialize_try_add_sleep_prop(ht, props, priv_name, name) == SUCCESS) {
|
if (php_var_serialize_try_add_sleep_prop(ht, props, priv_name, name, struc) == SUCCESS) {
|
||||||
zend_tmp_string_release(tmp_name);
|
zend_tmp_string_release(tmp_name);
|
||||||
zend_string_release(priv_name);
|
zend_string_release(priv_name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
zend_string_release(priv_name);
|
zend_string_release(priv_name);
|
||||||
|
|
||||||
|
if (EG(exception)) {
|
||||||
|
zend_tmp_string_release(tmp_name);
|
||||||
|
retval = FAILURE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
prot_name = zend_mangle_property_name(
|
prot_name = zend_mangle_property_name(
|
||||||
"*", 1, ZSTR_VAL(name), ZSTR_LEN(name), ce->type & ZEND_INTERNAL_CLASS);
|
"*", 1, ZSTR_VAL(name), ZSTR_LEN(name), ce->type & ZEND_INTERNAL_CLASS);
|
||||||
if (php_var_serialize_try_add_sleep_prop(ht, props, prot_name, name) == SUCCESS) {
|
if (php_var_serialize_try_add_sleep_prop(ht, props, prot_name, name, struc) == SUCCESS) {
|
||||||
zend_tmp_string_release(tmp_name);
|
zend_tmp_string_release(tmp_name);
|
||||||
zend_string_release(prot_name);
|
zend_string_release(prot_name);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
zend_string_release(prot_name);
|
zend_string_release(prot_name);
|
||||||
|
|
||||||
|
if (EG(exception)) {
|
||||||
|
zend_tmp_string_release(tmp_name);
|
||||||
|
retval = FAILURE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
php_error_docref(NULL, E_NOTICE,
|
php_error_docref(NULL, E_NOTICE,
|
||||||
"\"%s\" returned as member variable from __sleep() but does not exist", ZSTR_VAL(name));
|
"\"%s\" returned as member variable from __sleep() but does not exist", ZSTR_VAL(name));
|
||||||
zend_hash_add(ht, name, &EG(uninitialized_zval));
|
zend_hash_add(ht, name, &EG(uninitialized_zval));
|
||||||
zend_tmp_string_release(tmp_name);
|
zend_tmp_string_release(tmp_name);
|
||||||
} ZEND_HASH_FOREACH_END();
|
} ZEND_HASH_FOREACH_END();
|
||||||
|
|
||||||
zend_release_properties(props);
|
zend_release_properties(props);
|
||||||
|
return retval;
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
@ -893,10 +922,11 @@ static void php_var_serialize_nested_data(smart_str *buf, zval *struc, HashTable
|
||||||
static void php_var_serialize_class(smart_str *buf, zval *struc, zval *retval_ptr, php_serialize_data_t var_hash) /* {{{ */
|
static void php_var_serialize_class(smart_str *buf, zval *struc, zval *retval_ptr, php_serialize_data_t var_hash) /* {{{ */
|
||||||
{
|
{
|
||||||
HashTable props;
|
HashTable props;
|
||||||
php_var_serialize_get_sleep_props(&props, struc, HASH_OF(retval_ptr));
|
if (php_var_serialize_get_sleep_props(&props, struc, HASH_OF(retval_ptr)) == SUCCESS) {
|
||||||
php_var_serialize_class_name(buf, struc);
|
php_var_serialize_class_name(buf, struc);
|
||||||
php_var_serialize_nested_data(
|
php_var_serialize_nested_data(
|
||||||
buf, struc, &props, zend_hash_num_elements(&props), /* incomplete_class */ 0, var_hash);
|
buf, struc, &props, zend_hash_num_elements(&props), /* incomplete_class */ 0, var_hash);
|
||||||
|
}
|
||||||
zend_hash_destroy(&props);
|
zend_hash_destroy(&props);
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue