1
0
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:
Niels Dossche
2023-09-23 20:53:07 +02:00
parent c9cc68b9ed
commit f6f17484ab
4 changed files with 103 additions and 1 deletions

4
NEWS
View File

@@ -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:

View 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;}}}

View 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;}}}

View File

@@ -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;
}