mirror of
https://github.com/php/php-src.git
synced 2026-03-24 00:02:20 +01:00
Fix GH-12265: Cloning an object breaks serialization recursion
Closes GH-12287.
This commit is contained in:
4
NEWS
4
NEWS
@@ -6,6 +6,10 @@ PHP NEWS
|
||||
. Fixed bug GH-19765 (object_properties_load() bypasses readonly property
|
||||
checks). (timwolla)
|
||||
|
||||
- Standard:
|
||||
. Fixed bug GH-12265 (Cloning an object breaks serialization recursion).
|
||||
(nielsdos)
|
||||
|
||||
25 Sep 2025, PHP 8.3.26
|
||||
|
||||
- Core:
|
||||
|
||||
47
ext/standard/tests/serialize/gh12265.phpt
Normal file
47
ext/standard/tests/serialize/gh12265.phpt
Normal file
@@ -0,0 +1,47 @@
|
||||
--TEST--
|
||||
GH-12265 (Cloning an object breaks serialization recursion) - __serialize variation
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class A {
|
||||
public function __construct(public B $x) {
|
||||
}
|
||||
}
|
||||
|
||||
class B {
|
||||
public A $a;
|
||||
|
||||
public function __serialize()
|
||||
{
|
||||
return ['a' => new A($this)];
|
||||
}
|
||||
}
|
||||
|
||||
class C {
|
||||
public B $b;
|
||||
|
||||
public function __construct() {
|
||||
$this->b = new B;
|
||||
}
|
||||
}
|
||||
|
||||
$b = new B();
|
||||
$sb = serialize($b);
|
||||
$stb = serialize(new B);
|
||||
|
||||
printf("serialized original: %s\n", $sb);
|
||||
printf("serialized temp : %s\n", $stb);
|
||||
|
||||
$c = new C;
|
||||
$sc = serialize($c);
|
||||
$stc = serialize(new C);
|
||||
|
||||
printf("serialized original: %s\n", $sc);
|
||||
printf("serialized temp : %s\n", $stc);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
serialized original: O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:1;}}
|
||||
serialized temp : O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:1;}}
|
||||
serialized original: O:1:"C":1:{s:1:"b";O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:2;}}}
|
||||
serialized temp : O:1:"C":1:{s:1:"b";O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:2;}}}
|
||||
48
ext/standard/tests/serialize/gh12265b.phpt
Normal file
48
ext/standard/tests/serialize/gh12265b.phpt
Normal file
@@ -0,0 +1,48 @@
|
||||
--TEST--
|
||||
GH-12265 (Cloning an object breaks serialization recursion) - __sleep variation
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
class A {
|
||||
public function __construct(public B $x) {
|
||||
}
|
||||
}
|
||||
|
||||
class B {
|
||||
public A $a;
|
||||
|
||||
public function __sleep()
|
||||
{
|
||||
$this->a = new A($this);
|
||||
return ['a'];
|
||||
}
|
||||
}
|
||||
|
||||
class C {
|
||||
public B $b;
|
||||
|
||||
public function __construct() {
|
||||
$this->b = new B;
|
||||
}
|
||||
}
|
||||
|
||||
$b = new B();
|
||||
$sb = serialize($b);
|
||||
$stb = serialize(new B);
|
||||
|
||||
printf("serialized original: %s\n", $sb);
|
||||
printf("serialized temp : %s\n", $stb);
|
||||
|
||||
$c = new C;
|
||||
$sc = serialize($c);
|
||||
$stc = serialize(new C);
|
||||
|
||||
printf("serialized original: %s\n", $sc);
|
||||
printf("serialized temp : %s\n", $stc);
|
||||
|
||||
?>
|
||||
--EXPECT--
|
||||
serialized original: O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:1;}}
|
||||
serialized temp : O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:1;}}
|
||||
serialized original: O:1:"C":1:{s:1:"b";O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:2;}}}
|
||||
serialized temp : O:1:"C":1:{s:1:"b";O:1:"B":1:{s:1:"a";O:1:"A":1:{s:1:"x";r:2;}}}
|
||||
@@ -681,7 +681,10 @@ static inline zend_long php_add_var_hash(php_serialize_data_t data, zval *var, b
|
||||
return 0;
|
||||
} else if (!in_rcn_array
|
||||
&& Z_REFCOUNT_P(var) == 1
|
||||
&& (Z_OBJ_P(var)->properties == NULL || GC_REFCOUNT(Z_OBJ_P(var)->properties) == 1)) {
|
||||
&& (Z_OBJ_P(var)->properties == NULL || GC_REFCOUNT(Z_OBJ_P(var)->properties) == 1)
|
||||
/* __serialize and __sleep may arbitrarily increase the refcount */
|
||||
&& Z_OBJCE_P(var)->__serialize == NULL
|
||||
&& zend_hash_find_known_hash(&Z_OBJCE_P(var)->function_table, ZSTR_KNOWN(ZEND_STR_SLEEP)) == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user