mirror of
https://github.com/php/php-src.git
synced 2025-08-15 13:38:49 +02:00
Fix GH-9186 @strict-properties can be bypassed using unserialization (#9354)
* Emit deprecation warnings when adding dynamic properties to classes during unserialization - this will become an Error in php 9.0. (Adding dynamic properties in other contexts was already a deprecation warning - the use case of unserialization was overlooked) * Throw an error when attempting to add a dynamic property to a `readonly` class when unserializing * Add new serialization methods `__serialize`/`__unserialize` for SplFixedArray to avoid creating deprecated dynamic properties that would then be added to the backing fixed-size array * Don't add named dynamic/declared properties (e.g. $obj->foo) of SplFixedArray to the backing array when unserializing * Update tests to declare properties or to expect the deprecation warning * Add news entry Co-authored-by: Tyson Andre <tysonandre775@hotmail.com>
This commit is contained in:
parent
8d78dce902
commit
adb45a63c0
36 changed files with 271 additions and 22 deletions
2
NEWS
2
NEWS
|
@ -16,6 +16,8 @@ PHP NEWS
|
||||||
(cmb)
|
(cmb)
|
||||||
. Fixed bug GH-9285 (Traits cannot be used in readonly classes).
|
. Fixed bug GH-9285 (Traits cannot be used in readonly classes).
|
||||||
(kocsismate)
|
(kocsismate)
|
||||||
|
. Fixed bug GH-9186 (@strict-properties can be bypassed using
|
||||||
|
unserialization). (kocsismate)
|
||||||
|
|
||||||
- Date:
|
- Date:
|
||||||
. Fixed bug GH-9431 (DateTime::getLastErrors() not returning false when no
|
. Fixed bug GH-9431 (DateTime::getLastErrors() not returning false when no
|
||||||
|
|
|
@ -8,7 +8,8 @@ STR;
|
||||||
var_dump(unserialize($s));
|
var_dump(unserialize($s));
|
||||||
gc_collect_cycles();
|
gc_collect_cycles();
|
||||||
?>
|
?>
|
||||||
--EXPECT--
|
--EXPECTF--
|
||||||
|
Deprecated: Creation of dynamic property RegexIterator::$5 is deprecated in %s on line %d
|
||||||
object(stdClass)#1 (2) {
|
object(stdClass)#1 (2) {
|
||||||
["5"]=>
|
["5"]=>
|
||||||
object(SplStack)#2 (2) {
|
object(SplStack)#2 (2) {
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
--TEST--
|
||||||
|
Fix GH-9186 Readonly classes can have dynamic properties created by unserialize()
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
readonly class C {}
|
||||||
|
|
||||||
|
try {
|
||||||
|
$readonly = unserialize('O:1:"C":1:{s:1:"x";b:1;}');
|
||||||
|
} catch (Error $exception) {
|
||||||
|
echo $exception->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Cannot create dynamic property C::$x
|
|
@ -1628,6 +1628,15 @@ ZEND_API void object_properties_load(zend_object *object, HashTable *properties)
|
||||||
zend_hash_update(object->properties, key, &tmp);
|
zend_hash_update(object->properties, key, &tmp);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (UNEXPECTED(object->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) {
|
||||||
|
zend_throw_error(NULL, "Cannot create dynamic property %s::$%s",
|
||||||
|
ZSTR_VAL(object->ce->name), property_info != ZEND_WRONG_PROPERTY_INFO ? zend_get_unmangled_property_name(key): "");
|
||||||
|
return;
|
||||||
|
} else if (!(object->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) {
|
||||||
|
zend_error(E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated",
|
||||||
|
ZSTR_VAL(object->ce->name), property_info != ZEND_WRONG_PROPERTY_INFO ? zend_get_unmangled_property_name(key): "");
|
||||||
|
}
|
||||||
|
|
||||||
if (!object->properties) {
|
if (!object->properties) {
|
||||||
rebuild_object_properties(object);
|
rebuild_object_properties(object);
|
||||||
}
|
}
|
||||||
|
@ -1635,6 +1644,14 @@ ZEND_API void object_properties_load(zend_object *object, HashTable *properties)
|
||||||
zval_add_ref(prop);
|
zval_add_ref(prop);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
if (UNEXPECTED(object->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) {
|
||||||
|
zend_throw_error(NULL, "Cannot create dynamic property %s::$" ZEND_LONG_FMT, ZSTR_VAL(object->ce->name), h);
|
||||||
|
return;
|
||||||
|
} else if (!(object->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) {
|
||||||
|
zend_error(E_DEPRECATED, "Creation of dynamic property %s::$" ZEND_LONG_FMT " is deprecated",
|
||||||
|
ZSTR_VAL(object->ce->name), h);
|
||||||
|
}
|
||||||
|
|
||||||
if (!object->properties) {
|
if (!object->properties) {
|
||||||
rebuild_object_properties(object);
|
rebuild_object_properties(object);
|
||||||
}
|
}
|
||||||
|
|
24
ext/gmp/tests/gmp_dynamic_property.phpt
Normal file
24
ext/gmp/tests/gmp_dynamic_property.phpt
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
--TEST--
|
||||||
|
GH-9186 Dynamic property unserialization should trigger a deprecated notice
|
||||||
|
--EXTENSIONS--
|
||||||
|
gmp
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$g = new GMP();
|
||||||
|
$g->{1} = 123;
|
||||||
|
|
||||||
|
$serialized = serialize($g);
|
||||||
|
var_dump(unserialize($serialized));
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECTF--
|
||||||
|
Deprecated: Creation of dynamic property GMP::$1 is deprecated in %s on line %d
|
||||||
|
|
||||||
|
Deprecated: Creation of dynamic property GMP::$1 is deprecated in %s on line %d
|
||||||
|
object(GMP)#%d (%d) {
|
||||||
|
[1]=>
|
||||||
|
int(123)
|
||||||
|
["num"]=>
|
||||||
|
string(1) "0"
|
||||||
|
}
|
|
@ -54,6 +54,8 @@ object(GMP)#%d (1) {
|
||||||
|
|
||||||
Deprecated: Creation of dynamic property GMP::$foo is deprecated in %s on line %d
|
Deprecated: Creation of dynamic property GMP::$foo is deprecated in %s on line %d
|
||||||
string(56) "O:3:"GMP":2:{i:0;s:1:"d";i:1;a:1:{s:3:"foo";s:3:"bar";}}"
|
string(56) "O:3:"GMP":2:{i:0;s:1:"d";i:1;a:1:{s:3:"foo";s:3:"bar";}}"
|
||||||
|
|
||||||
|
Deprecated: Creation of dynamic property GMP::$foo is deprecated in %s on line %d
|
||||||
object(GMP)#%d (2) {
|
object(GMP)#%d (2) {
|
||||||
["foo"]=>
|
["foo"]=>
|
||||||
string(3) "bar"
|
string(3) "bar"
|
||||||
|
|
|
@ -365,6 +365,10 @@ PHP_METHOD(Random_Engine_Mt19937, __unserialize)
|
||||||
RETURN_THROWS();
|
RETURN_THROWS();
|
||||||
}
|
}
|
||||||
object_properties_load(&engine->std, Z_ARRVAL_P(t));
|
object_properties_load(&engine->std, Z_ARRVAL_P(t));
|
||||||
|
if (EG(exception)) {
|
||||||
|
zend_throw_exception_ex(NULL, 0, "Invalid serialization data for %s object", ZSTR_VAL(engine->std.ce->name));
|
||||||
|
RETURN_THROWS();
|
||||||
|
}
|
||||||
|
|
||||||
/* state */
|
/* state */
|
||||||
t = zend_hash_index_find(d, 1);
|
t = zend_hash_index_find(d, 1);
|
||||||
|
|
|
@ -90,7 +90,7 @@ PHP_METHOD(Random_Randomizer, __construct)
|
||||||
|
|
||||||
/* {{{ Generate positive random number */
|
/* {{{ Generate positive random number */
|
||||||
PHP_METHOD(Random_Randomizer, nextInt)
|
PHP_METHOD(Random_Randomizer, nextInt)
|
||||||
{
|
{
|
||||||
php_random_randomizer *randomizer = Z_RANDOM_RANDOMIZER_P(ZEND_THIS);
|
php_random_randomizer *randomizer = Z_RANDOM_RANDOMIZER_P(ZEND_THIS);
|
||||||
uint64_t result;
|
uint64_t result;
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ PHP_METHOD(Random_Randomizer, nextInt)
|
||||||
zend_throw_exception(random_ce_Random_RandomException, "Generated value exceeds size of int", 0);
|
zend_throw_exception(random_ce_Random_RandomException, "Generated value exceeds size of int", 0);
|
||||||
RETURN_THROWS();
|
RETURN_THROWS();
|
||||||
}
|
}
|
||||||
|
|
||||||
RETURN_LONG((zend_long) (result >> 1));
|
RETURN_LONG((zend_long) (result >> 1));
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
@ -278,6 +278,10 @@ PHP_METHOD(Random_Randomizer, __unserialize)
|
||||||
RETURN_THROWS();
|
RETURN_THROWS();
|
||||||
}
|
}
|
||||||
object_properties_load(&randomizer->std, Z_ARRVAL_P(members_zv));
|
object_properties_load(&randomizer->std, Z_ARRVAL_P(members_zv));
|
||||||
|
if (EG(exception)) {
|
||||||
|
zend_throw_exception(NULL, "Invalid serialization data for Random\\Randomizer object", 0);
|
||||||
|
RETURN_THROWS();
|
||||||
|
}
|
||||||
|
|
||||||
zengine = zend_read_property(randomizer->std.ce, &randomizer->std, "engine", strlen("engine"), 1, NULL);
|
zengine = zend_read_property(randomizer->std.ce, &randomizer->std, "engine", strlen("engine"), 1, NULL);
|
||||||
if (Z_TYPE_P(zengine) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(zengine), random_ce_Random_Engine)) {
|
if (Z_TYPE_P(zengine) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(zengine), random_ce_Random_Engine)) {
|
||||||
|
|
14
ext/random/tests/03_randomizer/gh_9186_unserialize.phpt
Normal file
14
ext/random/tests/03_randomizer/gh_9186_unserialize.phpt
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
--TEST--
|
||||||
|
Fix GH-9186 @strict-properties can be bypassed using unserialization
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
try {
|
||||||
|
unserialize('O:17:"Random\Randomizer":1:{i:0;a:2:{s:3:"foo";N;s:6:"engine";O:32:"Random\Engine\Xoshiro256StarStar":2:{i:0;a:0:{}i:1;a:4:{i:0;s:16:"7520fbc2d6f8de46";i:1;s:16:"84d2d2b9d7ba0a34";i:2;s:16:"d975f36db6490b32";i:3;s:16:"c19991ee16785b94";}}}}');
|
||||||
|
} catch (Exception $error) {
|
||||||
|
echo $error->getMessage() . "\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
Invalid serialization data for Random\Randomizer object
|
|
@ -16,6 +16,7 @@ error_reporting(E_ALL);
|
||||||
|
|
||||||
class foo {
|
class foo {
|
||||||
public $bar = "ok";
|
public $bar = "ok";
|
||||||
|
public $yes;
|
||||||
function method() { $this->yes++; }
|
function method() { $this->yes++; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -52,6 +52,7 @@ $hnd = new handler;
|
||||||
|
|
||||||
class foo {
|
class foo {
|
||||||
public $bar = "ok";
|
public $bar = "ok";
|
||||||
|
public $yes;
|
||||||
function method() { $this->yes++; }
|
function method() { $this->yes++; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ $hnd = new handler;
|
||||||
|
|
||||||
class foo {
|
class foo {
|
||||||
public $bar = "ok";
|
public $bar = "ok";
|
||||||
|
public $yes;
|
||||||
function method() { $this->yes++; }
|
function method() { $this->yes++; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,6 +16,7 @@ error_reporting(E_ALL);
|
||||||
|
|
||||||
class foo {
|
class foo {
|
||||||
public $bar = "ok";
|
public $bar = "ok";
|
||||||
|
public $yes;
|
||||||
function method() { $this->yes++; }
|
function method() { $this->yes++; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -53,6 +53,7 @@ $hnd = new handler;
|
||||||
|
|
||||||
class foo {
|
class foo {
|
||||||
public $bar = "ok";
|
public $bar = "ok";
|
||||||
|
public $yes;
|
||||||
function method() { $this->yes++; }
|
function method() { $this->yes++; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -54,6 +54,7 @@ $hnd = new handler;
|
||||||
|
|
||||||
class foo {
|
class foo {
|
||||||
public $bar = "ok";
|
public $bar = "ok";
|
||||||
|
public $yes;
|
||||||
function method() { $this->yes++; }
|
function method() { $this->yes++; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,6 +4,8 @@ Bug #70388 (SOAP serialize_function_call() type confusion / RCE)
|
||||||
soap
|
soap
|
||||||
--FILE--
|
--FILE--
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
#[AllowDynamicProperties]
|
||||||
class MySoapClient extends SoapClient {
|
class MySoapClient extends SoapClient {
|
||||||
public function __doRequest($request, $location, $action, $version, $one_way = 0): string {
|
public function __doRequest($request, $location, $action, $version, $one_way = 0): string {
|
||||||
echo $request, "\n";
|
echo $request, "\n";
|
||||||
|
|
|
@ -7,6 +7,7 @@ soap.wsdl_cache_enabled=0
|
||||||
--FILE--
|
--FILE--
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
#[AllowDynamicProperties]
|
||||||
class MySoapClient extends SoapClient {
|
class MySoapClient extends SoapClient {
|
||||||
public function __doRequest($request, $location, $action, $version, $one_way = 0): string {
|
public function __doRequest($request, $location, $action, $version, $one_way = 0): string {
|
||||||
echo $request, "\n";
|
echo $request, "\n";
|
||||||
|
|
|
@ -1740,6 +1740,9 @@ PHP_METHOD(ArrayObject, __unserialize)
|
||||||
}
|
}
|
||||||
|
|
||||||
object_properties_load(&intern->std, Z_ARRVAL_P(members_zv));
|
object_properties_load(&intern->std, Z_ARRVAL_P(members_zv));
|
||||||
|
if (EG(exception)) {
|
||||||
|
RETURN_THROWS();
|
||||||
|
}
|
||||||
|
|
||||||
if (iterator_class_zv && Z_TYPE_P(iterator_class_zv) == IS_STRING) {
|
if (iterator_class_zv && Z_TYPE_P(iterator_class_zv) == IS_STRING) {
|
||||||
zend_class_entry *ce = zend_lookup_class(Z_STR_P(iterator_class_zv));
|
zend_class_entry *ce = zend_lookup_class(Z_STR_P(iterator_class_zv));
|
||||||
|
|
|
@ -102,13 +102,18 @@ static void spl_fixedarray_init_elems(spl_fixedarray *array, zend_long from, zen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void spl_fixedarray_init_non_empty_struct(spl_fixedarray *array, zend_long size)
|
||||||
|
{
|
||||||
|
array->size = 0; /* reset size in case ecalloc() fails */
|
||||||
|
array->elements = size ? safe_emalloc(size, sizeof(zval), 0) : NULL;
|
||||||
|
array->size = size;
|
||||||
|
array->should_rebuild_properties = true;
|
||||||
|
}
|
||||||
|
|
||||||
static void spl_fixedarray_init(spl_fixedarray *array, zend_long size)
|
static void spl_fixedarray_init(spl_fixedarray *array, zend_long size)
|
||||||
{
|
{
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
array->size = 0; /* reset size in case ecalloc() fails */
|
spl_fixedarray_init_non_empty_struct(array, size);
|
||||||
array->elements = safe_emalloc(size, sizeof(zval), 0);
|
|
||||||
array->size = size;
|
|
||||||
array->should_rebuild_properties = true;
|
|
||||||
spl_fixedarray_init_elems(array, 0, size);
|
spl_fixedarray_init_elems(array, 0, size);
|
||||||
} else {
|
} else {
|
||||||
spl_fixedarray_default_ctor(array);
|
spl_fixedarray_default_ctor(array);
|
||||||
|
@ -582,6 +587,78 @@ PHP_METHOD(SplFixedArray, __wakeup)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PHP_METHOD(SplFixedArray, __serialize)
|
||||||
|
{
|
||||||
|
spl_fixedarray_object *intern = Z_SPLFIXEDARRAY_P(ZEND_THIS);
|
||||||
|
zval *current;
|
||||||
|
zend_string *key;
|
||||||
|
|
||||||
|
if (zend_parse_parameters_none() == FAILURE) {
|
||||||
|
RETURN_THROWS();
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t property_num = zend_hash_num_elements(intern->std.properties);
|
||||||
|
array_init_size(return_value, intern->array.size + property_num);
|
||||||
|
|
||||||
|
/* elements */
|
||||||
|
for (zend_long i = 0; i < intern->array.size; i++) {
|
||||||
|
current = &intern->array.elements[i];
|
||||||
|
zend_hash_next_index_insert(Z_ARRVAL_P(return_value), current);
|
||||||
|
Z_TRY_ADDREF_P(current);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* members */
|
||||||
|
ZEND_HASH_FOREACH_STR_KEY_VAL(intern->std.properties, key, current) {
|
||||||
|
zend_hash_add(Z_ARRVAL_P(return_value), key, current);
|
||||||
|
Z_TRY_ADDREF_P(current);
|
||||||
|
} ZEND_HASH_FOREACH_END();
|
||||||
|
}
|
||||||
|
|
||||||
|
PHP_METHOD(SplFixedArray, __unserialize)
|
||||||
|
{
|
||||||
|
spl_fixedarray_object *intern = Z_SPLFIXEDARRAY_P(ZEND_THIS);
|
||||||
|
HashTable *data;
|
||||||
|
zval members_zv, *elem;
|
||||||
|
zend_string *key;
|
||||||
|
zend_long size;
|
||||||
|
|
||||||
|
if (zend_parse_parameters(ZEND_NUM_ARGS(), "h", &data) == FAILURE) {
|
||||||
|
RETURN_THROWS();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (intern->array.size == 0) {
|
||||||
|
size = zend_hash_num_elements(data);
|
||||||
|
spl_fixedarray_init_non_empty_struct(&intern->array, size);
|
||||||
|
if (!size) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
array_init(&members_zv);
|
||||||
|
|
||||||
|
intern->array.size = 0;
|
||||||
|
ZEND_HASH_FOREACH_STR_KEY_VAL(data, key, elem) {
|
||||||
|
if (key == NULL) {
|
||||||
|
ZVAL_COPY(&intern->array.elements[intern->array.size], elem);
|
||||||
|
intern->array.size++;
|
||||||
|
} else {
|
||||||
|
Z_TRY_ADDREF_P(elem);
|
||||||
|
zend_hash_add(Z_ARRVAL(members_zv), key, elem);
|
||||||
|
}
|
||||||
|
} ZEND_HASH_FOREACH_END();
|
||||||
|
|
||||||
|
if (intern->array.size != size) {
|
||||||
|
if (intern->array.size) {
|
||||||
|
intern->array.elements = erealloc(intern->array.elements, sizeof(zval) * intern->array.size);
|
||||||
|
} else {
|
||||||
|
efree(intern->array.elements);
|
||||||
|
intern->array.elements = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object_properties_load(&intern->std, Z_ARRVAL(members_zv));
|
||||||
|
zval_ptr_dtor(&members_zv);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
PHP_METHOD(SplFixedArray, count)
|
PHP_METHOD(SplFixedArray, count)
|
||||||
{
|
{
|
||||||
zval *object = ZEND_THIS;
|
zval *object = ZEND_THIS;
|
||||||
|
|
|
@ -9,6 +9,10 @@ class SplFixedArray implements IteratorAggregate, ArrayAccess, Countable, JsonSe
|
||||||
/** @tentative-return-type */
|
/** @tentative-return-type */
|
||||||
public function __wakeup(): void {}
|
public function __wakeup(): void {}
|
||||||
|
|
||||||
|
public function __serialize(): array {}
|
||||||
|
|
||||||
|
public function __unserialize(array $data): void {}
|
||||||
|
|
||||||
/** @tentative-return-type */
|
/** @tentative-return-type */
|
||||||
public function count(): int {}
|
public function count(): int {}
|
||||||
|
|
||||||
|
|
16
ext/spl/spl_fixedarray_arginfo.h
generated
16
ext/spl/spl_fixedarray_arginfo.h
generated
|
@ -1,5 +1,5 @@
|
||||||
/* This is a generated file, edit the .stub.php file instead.
|
/* This is a generated file, edit the .stub.php file instead.
|
||||||
* Stub hash: 79a13a549d91f0e79c78a125de65fbac4795339f */
|
* Stub hash: 0b508ad6499b70c92bf25960b30fefa913532a3c */
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SplFixedArray___construct, 0, 0, 0)
|
ZEND_BEGIN_ARG_INFO_EX(arginfo_class_SplFixedArray___construct, 0, 0, 0)
|
||||||
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, size, IS_LONG, 0, "0")
|
ZEND_ARG_TYPE_INFO_WITH_DEFAULT_VALUE(0, size, IS_LONG, 0, "0")
|
||||||
|
@ -8,6 +8,13 @@ ZEND_END_ARG_INFO()
|
||||||
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SplFixedArray___wakeup, 0, 0, IS_VOID, 0)
|
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SplFixedArray___wakeup, 0, 0, IS_VOID, 0)
|
||||||
ZEND_END_ARG_INFO()
|
ZEND_END_ARG_INFO()
|
||||||
|
|
||||||
|
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_SplFixedArray___serialize, 0, 0, IS_ARRAY, 0)
|
||||||
|
ZEND_END_ARG_INFO()
|
||||||
|
|
||||||
|
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_SplFixedArray___unserialize, 0, 1, IS_VOID, 0)
|
||||||
|
ZEND_ARG_TYPE_INFO(0, data, IS_ARRAY, 0)
|
||||||
|
ZEND_END_ARG_INFO()
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SplFixedArray_count, 0, 0, IS_LONG, 0)
|
ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_SplFixedArray_count, 0, 0, IS_LONG, 0)
|
||||||
ZEND_END_ARG_INFO()
|
ZEND_END_ARG_INFO()
|
||||||
|
|
||||||
|
@ -45,12 +52,13 @@ ZEND_END_ARG_INFO()
|
||||||
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_SplFixedArray_getIterator, 0, 0, Iterator, 0)
|
ZEND_BEGIN_ARG_WITH_RETURN_OBJ_INFO_EX(arginfo_class_SplFixedArray_getIterator, 0, 0, Iterator, 0)
|
||||||
ZEND_END_ARG_INFO()
|
ZEND_END_ARG_INFO()
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_class_SplFixedArray_jsonSerialize, 0, 0, IS_ARRAY, 0)
|
#define arginfo_class_SplFixedArray_jsonSerialize arginfo_class_SplFixedArray___serialize
|
||||||
ZEND_END_ARG_INFO()
|
|
||||||
|
|
||||||
|
|
||||||
ZEND_METHOD(SplFixedArray, __construct);
|
ZEND_METHOD(SplFixedArray, __construct);
|
||||||
ZEND_METHOD(SplFixedArray, __wakeup);
|
ZEND_METHOD(SplFixedArray, __wakeup);
|
||||||
|
ZEND_METHOD(SplFixedArray, __serialize);
|
||||||
|
ZEND_METHOD(SplFixedArray, __unserialize);
|
||||||
ZEND_METHOD(SplFixedArray, count);
|
ZEND_METHOD(SplFixedArray, count);
|
||||||
ZEND_METHOD(SplFixedArray, toArray);
|
ZEND_METHOD(SplFixedArray, toArray);
|
||||||
ZEND_METHOD(SplFixedArray, fromArray);
|
ZEND_METHOD(SplFixedArray, fromArray);
|
||||||
|
@ -67,6 +75,8 @@ ZEND_METHOD(SplFixedArray, jsonSerialize);
|
||||||
static const zend_function_entry class_SplFixedArray_methods[] = {
|
static const zend_function_entry class_SplFixedArray_methods[] = {
|
||||||
ZEND_ME(SplFixedArray, __construct, arginfo_class_SplFixedArray___construct, ZEND_ACC_PUBLIC)
|
ZEND_ME(SplFixedArray, __construct, arginfo_class_SplFixedArray___construct, ZEND_ACC_PUBLIC)
|
||||||
ZEND_ME(SplFixedArray, __wakeup, arginfo_class_SplFixedArray___wakeup, ZEND_ACC_PUBLIC)
|
ZEND_ME(SplFixedArray, __wakeup, arginfo_class_SplFixedArray___wakeup, ZEND_ACC_PUBLIC)
|
||||||
|
ZEND_ME(SplFixedArray, __serialize, arginfo_class_SplFixedArray___serialize, ZEND_ACC_PUBLIC)
|
||||||
|
ZEND_ME(SplFixedArray, __unserialize, arginfo_class_SplFixedArray___unserialize, ZEND_ACC_PUBLIC)
|
||||||
ZEND_ME(SplFixedArray, count, arginfo_class_SplFixedArray_count, ZEND_ACC_PUBLIC)
|
ZEND_ME(SplFixedArray, count, arginfo_class_SplFixedArray_count, ZEND_ACC_PUBLIC)
|
||||||
ZEND_ME(SplFixedArray, toArray, arginfo_class_SplFixedArray_toArray, ZEND_ACC_PUBLIC)
|
ZEND_ME(SplFixedArray, toArray, arginfo_class_SplFixedArray_toArray, ZEND_ACC_PUBLIC)
|
||||||
ZEND_ME(SplFixedArray, fromArray, arginfo_class_SplFixedArray_fromArray, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
ZEND_ME(SplFixedArray, fromArray, arginfo_class_SplFixedArray_fromArray, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
|
||||||
|
|
|
@ -13,6 +13,8 @@ $array[2] = 42;
|
||||||
$array[3] = $obj;
|
$array[3] = $obj;
|
||||||
$array[4] = range(1, 5);
|
$array[4] = range(1, 5);
|
||||||
|
|
||||||
|
$array->foo = "bar";
|
||||||
|
|
||||||
$ser = serialize($array);
|
$ser = serialize($array);
|
||||||
echo "$ser\n";
|
echo "$ser\n";
|
||||||
$unser = unserialize($ser);
|
$unser = unserialize($ser);
|
||||||
|
@ -24,10 +26,24 @@ var_dump($unser[0], $unser[1], $unser[2], $unser[3], $unser[4]);
|
||||||
|
|
||||||
$unser[4] = 'quux';
|
$unser[4] = 'quux';
|
||||||
var_dump($unser[4]);
|
var_dump($unser[4]);
|
||||||
|
var_dump($unser->foo);
|
||||||
|
|
||||||
|
// __unserialize is a no-op on a non-empty SplFixedArray
|
||||||
|
$array = new SplFixedArray(1);
|
||||||
|
$array->__unserialize([
|
||||||
|
[1],
|
||||||
|
[
|
||||||
|
"foo" => "bar",
|
||||||
|
],
|
||||||
|
]);
|
||||||
|
var_dump($array);
|
||||||
|
|
||||||
?>
|
?>
|
||||||
--EXPECT--
|
--EXPECTF--
|
||||||
O:13:"SplFixedArray":5:{i:0;s:3:"foo";i:1;N;i:2;i:42;i:3;O:8:"stdClass":1:{s:4:"prop";s:5:"value";}i:4;a:5:{i:0;i:1;i:1;i:2;i:2;i:3;i:3;i:4;i:4;i:5;}}
|
Deprecated: Creation of dynamic property SplFixedArray::$foo is deprecated in %s on line %d
|
||||||
|
O:13:"SplFixedArray":6:{i:0;s:3:"foo";i:1;N;i:2;i:42;i:3;O:8:"stdClass":1:{s:4:"prop";s:5:"value";}i:4;a:5:{i:0;i:1;i:1;i:2;i:2;i:3;i:3;i:4;i:4;i:5;}s:3:"foo";s:3:"bar";}
|
||||||
|
|
||||||
|
Deprecated: Creation of dynamic property SplFixedArray::$foo is deprecated in %s on line %d
|
||||||
count: 5
|
count: 5
|
||||||
getSize(): 5
|
getSize(): 5
|
||||||
string(3) "foo"
|
string(3) "foo"
|
||||||
|
@ -50,3 +66,8 @@ array(5) {
|
||||||
int(5)
|
int(5)
|
||||||
}
|
}
|
||||||
string(4) "quux"
|
string(4) "quux"
|
||||||
|
string(3) "bar"
|
||||||
|
object(SplFixedArray)#5 (1) {
|
||||||
|
[0]=>
|
||||||
|
NULL
|
||||||
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ $data = unserialize($exploit);
|
||||||
var_dump($data);
|
var_dump($data);
|
||||||
?>
|
?>
|
||||||
--EXPECTF--
|
--EXPECTF--
|
||||||
|
Deprecated: Creation of dynamic property ArrayObject::$0 is deprecated in %s on line %d
|
||||||
|
|
||||||
Fatal error: Uncaught InvalidArgumentException: Overloaded object of type DateInterval is not compatible with ArrayObject in %s
|
Fatal error: Uncaught InvalidArgumentException: Overloaded object of type DateInterval is not compatible with ArrayObject in %s
|
||||||
Stack trace:
|
Stack trace:
|
||||||
%s
|
%s
|
||||||
|
|
|
@ -105,6 +105,8 @@ object(SelfArray)#9 (1) {
|
||||||
string(3) "bar"
|
string(3) "bar"
|
||||||
}
|
}
|
||||||
string(77) "O:9:"SelfArray":4:{i:0;i:16777216;i:1;N;i:2;a:1:{s:3:"foo";s:3:"bar";}i:3;N;}"
|
string(77) "O:9:"SelfArray":4:{i:0;i:16777216;i:1;N;i:2;a:1:{s:3:"foo";s:3:"bar";}i:3;N;}"
|
||||||
|
|
||||||
|
Deprecated: Creation of dynamic property SelfArray::$foo is deprecated in %s on line %d
|
||||||
object(SelfArray)#9 (1) {
|
object(SelfArray)#9 (1) {
|
||||||
["foo"]=>
|
["foo"]=>
|
||||||
string(3) "bar"
|
string(3) "bar"
|
||||||
|
|
|
@ -343,6 +343,7 @@ const PHP_ROUND_HALF_EVEN = UNKNOWN;
|
||||||
*/
|
*/
|
||||||
const PHP_ROUND_HALF_ODD = UNKNOWN;
|
const PHP_ROUND_HALF_ODD = UNKNOWN;
|
||||||
|
|
||||||
|
#[AllowDynamicProperties]
|
||||||
final class __PHP_Incomplete_Class
|
final class __PHP_Incomplete_Class
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
8
ext/standard/basic_functions_arginfo.h
generated
8
ext/standard/basic_functions_arginfo.h
generated
|
@ -1,5 +1,5 @@
|
||||||
/* This is a generated file, edit the .stub.php file instead.
|
/* This is a generated file, edit the .stub.php file instead.
|
||||||
* Stub hash: 0411f358f211eb9173272c6f296899d349ab5971 */
|
* Stub hash: 4df5576b4e03b18896abf58e6c70d9fd6ae76687 */
|
||||||
|
|
||||||
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0)
|
ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(arginfo_set_time_limit, 0, 1, _IS_BOOL, 0)
|
||||||
ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0)
|
ZEND_ARG_TYPE_INFO(0, seconds, IS_LONG, 0)
|
||||||
|
@ -3578,7 +3578,11 @@ static zend_class_entry *register_class___PHP_Incomplete_Class(void)
|
||||||
|
|
||||||
INIT_CLASS_ENTRY(ce, "__PHP_Incomplete_Class", class___PHP_Incomplete_Class_methods);
|
INIT_CLASS_ENTRY(ce, "__PHP_Incomplete_Class", class___PHP_Incomplete_Class_methods);
|
||||||
class_entry = zend_register_internal_class_ex(&ce, NULL);
|
class_entry = zend_register_internal_class_ex(&ce, NULL);
|
||||||
class_entry->ce_flags |= ZEND_ACC_FINAL;
|
class_entry->ce_flags |= ZEND_ACC_FINAL|ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES;
|
||||||
|
|
||||||
|
zend_string *attribute_name_AllowDynamicProperties_class___PHP_Incomplete_Class = zend_string_init_interned("AllowDynamicProperties", sizeof("AllowDynamicProperties") - 1, 1);
|
||||||
|
zend_add_class_attribute(class_entry, attribute_name_AllowDynamicProperties_class___PHP_Incomplete_Class, 0);
|
||||||
|
zend_string_release(attribute_name_AllowDynamicProperties_class___PHP_Incomplete_Class);
|
||||||
|
|
||||||
return class_entry;
|
return class_entry;
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,8 @@ class Foo
|
||||||
$class = unserialize(base64_decode($serialized));
|
$class = unserialize(base64_decode($serialized));
|
||||||
var_dump($class);
|
var_dump($class);
|
||||||
?>
|
?>
|
||||||
--EXPECT--
|
--EXPECTF--
|
||||||
|
Deprecated: Creation of dynamic property Foo::$notThere is deprecated in %s on line %d
|
||||||
object(Foo)#1 (4) {
|
object(Foo)#1 (4) {
|
||||||
["public"]=>
|
["public"]=>
|
||||||
int(3)
|
int(3)
|
||||||
|
|
|
@ -33,7 +33,8 @@ class Foo
|
||||||
$class = unserialize(base64_decode($serialized));
|
$class = unserialize(base64_decode($serialized));
|
||||||
var_dump($class);
|
var_dump($class);
|
||||||
?>
|
?>
|
||||||
--EXPECT--
|
--EXPECTF--
|
||||||
|
Deprecated: Creation of dynamic property Foo::$notThere is deprecated in %s on line %d
|
||||||
object(Foo)#1 (4) {
|
object(Foo)#1 (4) {
|
||||||
["public":protected]=>
|
["public":protected]=>
|
||||||
int(3)
|
int(3)
|
||||||
|
|
|
@ -33,7 +33,8 @@ class Foo
|
||||||
$class = unserialize(base64_decode($serialized));
|
$class = unserialize(base64_decode($serialized));
|
||||||
var_dump($class);
|
var_dump($class);
|
||||||
?>
|
?>
|
||||||
--EXPECT--
|
--EXPECTF--
|
||||||
|
Deprecated: Creation of dynamic property Foo::$notThere is deprecated in %s on line %d
|
||||||
object(Foo)#1 (4) {
|
object(Foo)#1 (4) {
|
||||||
["public":"Foo":private]=>
|
["public":"Foo":private]=>
|
||||||
int(3)
|
int(3)
|
||||||
|
|
|
@ -5,7 +5,7 @@ Bug #62836 (Seg fault or broken object references on unserialize())
|
||||||
$serialized_object='O:1:"A":4:{s:1:"b";O:1:"B":0:{}s:2:"b1";r:2;s:1:"c";O:1:"B":0:{}s:2:"c1";r:4;}';
|
$serialized_object='O:1:"A":4:{s:1:"b";O:1:"B":0:{}s:2:"b1";r:2;s:1:"c";O:1:"B":0:{}s:2:"c1";r:4;}';
|
||||||
spl_autoload_register(function ($name) {
|
spl_autoload_register(function ($name) {
|
||||||
unserialize("i:4;");
|
unserialize("i:4;");
|
||||||
eval("class $name {} ");
|
eval("#[AllowDynamicProperties] class $name {} ");
|
||||||
});
|
});
|
||||||
|
|
||||||
print_r(unserialize($serialized_object));
|
print_r(unserialize($serialized_object));
|
||||||
|
|
|
@ -8,7 +8,7 @@ ini_set('unserialize_callback_func','mycallback');
|
||||||
|
|
||||||
function mycallback($classname) {
|
function mycallback($classname) {
|
||||||
unserialize("i:4;");
|
unserialize("i:4;");
|
||||||
eval ("class $classname {} ");
|
eval ("#[AllowDynamicProperties] class $classname {} ");
|
||||||
}
|
}
|
||||||
|
|
||||||
print_r(unserialize($serialized_object));
|
print_r(unserialize($serialized_object));
|
||||||
|
|
|
@ -3,6 +3,7 @@ Bug #72663 (1): Don't call __destruct if __wakeup not called or fails
|
||||||
--FILE--
|
--FILE--
|
||||||
<?php
|
<?php
|
||||||
|
|
||||||
|
#[AllowDynamicProperties]
|
||||||
class Test1 {
|
class Test1 {
|
||||||
public function __wakeup() {
|
public function __wakeup() {
|
||||||
echo "Wakeup\n";
|
echo "Wakeup\n";
|
||||||
|
@ -12,6 +13,7 @@ class Test1 {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[AllowDynamicProperties]
|
||||||
class Test2 {
|
class Test2 {
|
||||||
public function __wakeup() {
|
public function __wakeup() {
|
||||||
throw new Exception('Unserialization forbidden');
|
throw new Exception('Unserialization forbidden');
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
--TEST--
|
||||||
|
Check behaviour of incomplete class
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
$incomplete = unserialize('O:1:"C":1:{s:1:"p";i:1;}');
|
||||||
|
var_dump($incomplete);
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
object(__PHP_Incomplete_Class)#1 (2) {
|
||||||
|
["__PHP_Incomplete_Class_Name"]=>
|
||||||
|
string(1) "C"
|
||||||
|
["p"]=>
|
||||||
|
int(1)
|
||||||
|
}
|
|
@ -12,7 +12,8 @@ O:4:"Test":2:{s:4:"\0*\0x";N;s:4:"\0*\0x";N;}
|
||||||
STR;
|
STR;
|
||||||
var_dump(unserialize($str));
|
var_dump(unserialize($str));
|
||||||
?>
|
?>
|
||||||
--EXPECT--
|
--EXPECTF--
|
||||||
|
Deprecated: Creation of dynamic property Test::$x is deprecated in %s on line %d
|
||||||
object(Test)#1 (2) {
|
object(Test)#1 (2) {
|
||||||
["foo"]=>
|
["foo"]=>
|
||||||
NULL
|
NULL
|
||||||
|
|
|
@ -3,10 +3,10 @@ Trying to create a reference to an overwritten declared property
|
||||||
--FILE--
|
--FILE--
|
||||||
<?php
|
<?php
|
||||||
$str = <<<STR
|
$str = <<<STR
|
||||||
O:5:"Error":2:{S:8:"previous";N;S:8:"previous";R:2;}
|
O:9:"Attribute":1:{s:5:"flags";i:63;s:5:"flags";R:2}
|
||||||
STR;
|
STR;
|
||||||
var_dump(unserialize($str));
|
var_dump(unserialize($str));
|
||||||
?>
|
?>
|
||||||
--EXPECTF--
|
--EXPECTF--
|
||||||
Notice: unserialize(): Error at offset 51 of 52 bytes in %s on line %d
|
Notice: unserialize(): Error at offset 36 of 52 bytes in %s on line %d
|
||||||
bool(false)
|
bool(false)
|
||||||
|
|
|
@ -641,6 +641,18 @@ declared_property:
|
||||||
int ret = is_property_visibility_changed(obj->ce, &key);
|
int ret = is_property_visibility_changed(obj->ce, &key);
|
||||||
|
|
||||||
if (EXPECTED(!ret)) {
|
if (EXPECTED(!ret)) {
|
||||||
|
if (UNEXPECTED(obj->ce->ce_flags & ZEND_ACC_NO_DYNAMIC_PROPERTIES)) {
|
||||||
|
zend_throw_error(NULL, "Cannot create dynamic property %s::$%s",
|
||||||
|
ZSTR_VAL(obj->ce->name), zend_get_unmangled_property_name(Z_STR_P(&key)));
|
||||||
|
goto failure;
|
||||||
|
} else if (!(obj->ce->ce_flags & ZEND_ACC_ALLOW_DYNAMIC_PROPERTIES)) {
|
||||||
|
zend_error(E_DEPRECATED, "Creation of dynamic property %s::$%s is deprecated",
|
||||||
|
ZSTR_VAL(obj->ce->name), zend_get_unmangled_property_name(Z_STR_P(&key)));
|
||||||
|
if (EG(exception)) {
|
||||||
|
goto failure;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
data = zend_hash_add_new(ht, Z_STR(key), &EG(uninitialized_zval));
|
data = zend_hash_add_new(ht, Z_STR(key), &EG(uninitialized_zval));
|
||||||
} else if (ret < 0) {
|
} else if (ret < 0) {
|
||||||
goto failure;
|
goto failure;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue