Edit report at https://bugs.php.net/bug.php?id=55801&edit=1
ID: 55801 Comment by: mapi at pdepend dot org Reported by: mapi at pdepend dot org Summary: Behavior of unserialize has changed Status: Analyzed Type: Bug Package: Variables related Operating System: Linux (Fedora 15) PHP Version: 5.4.0beta1 Assigned To: mike Block user comment: N Private report: N New Comment: Cool that you came up with a reproducable, I have tried it for a couple of hours and didn't get a working reproducable outside of PHP_Depend. But is it such an uncommon use case to serialize/unserialize additional data in an object's __sleep() or __wakeup() method? Previous Comments: ------------------------------------------------------------------------ [2011-10-04 14:20:46] m...@php.net So, after digging a lot, I can only see two solutions: - either disallow serialize/unserialize in __sleep/__wakeup - or revert r299770 which introduced a "persistent" state for serialize() which allowed objects which implement the Serializable interface to keep reference info through recursive calls to serialize(), see FR #36424 The issue can probably be seen as follows: serialize(obj) -> obj->__sleep does serialize() (in your code) -> then internally serialize(obj->prop) happens unserialize(obj) -> internally unserialize(obj->prop) is done -> obj->__wakeup is called which does unserialize() (your code) As you can see the IDs of the referenced objects when unserializing cannot match the IDs at serialization time, because of the mixed up call order. ------------------------------------------------------------------------ [2011-10-04 08:25:40] m...@php.net Ok, now got a reproduce case: <?php class node { protected $parent; protected $nodes = array(); protected $path; protected $temp; function __toString() { return $this->parent ? $this->parent . "/" . $this->path : $this->path; } function __construct(node $parent = null, $path = ".") { $this->parent = $parent; $this->path = $path; if (is_dir($this)) foreach (scandir($this) as $p) { if ($p[0] != ".") { $this->nodes[] = new node($this, $p); } } } function __sleep() { $this->temp = serialize($this->nodes); return array("path", "temp"); } function __wakeup() { $this->nodes = unserialize($this->temp); $this->temp = null; foreach ($this->nodes as $n) { $n->parent = $this; } } function createWeirdConnections() { foreach ($this->nodes as $n) { $a = $this->nodes; shuffle($a); $n->nodes[] = current($a); } } } $tree = new node(null, @$_SERVER["argv"][1] ?: "."); $tree->createWeirdConnections(); $s = serialize($tree); $temp = unserialize($s); ------------------------------------------------------------------------ [2011-10-03 11:41:36] m...@php.net OTOH, the following working script suggests that this is not the source of failure: <?php class node { public $parent; public $nodes = array(); public $path; public $temp; function __toString() { return $this->parent ? $this->parent . "/" . $this->path : $this->path; } function __construct(node $parent = null, $path = ".") { $this->parent = $parent; $this->path = $path; if (is_dir($this)) foreach (scandir($this) as $p) { if ($p[0] != ".") { $this->nodes[] = new node($this, $p); } } } function __sleep() { $this->temp = serialize($this->nodes); return array("path", "temp"); } function __wakeup() { $this->nodes = unserialize($this->temp); $this->temp = null; foreach ($this->nodes as $n) { $n->parent = $this; } } } $tree = new node(null, @$_SERVER["argv"][1] ?: "."); $s = serialize($tree); var_dump($s); $temp = unserialize($s); print_r($temp); ------------------------------------------------------------------------ [2011-10-03 11:15:26] m...@php.net Ok, I think I found the problematic POC: in line 486 of PHP_Depend_Code_AbstractCallable you call serialize() while another (the prime) serialize calls __sleep() on an instance of this class. What's the intention of this __temp__ thing? ------------------------------------------------------------------------ [2011-10-03 09:45:19] m...@php.net Obviously I did, but it's unclear how... The reproduce case doesn't help much either. ------------------------------------------------------------------------ The remainder of the comments for this report are too long. To view the rest of the comments, please view the bug report online at https://bugs.php.net/bug.php?id=55801 -- Edit this bug report at https://bugs.php.net/bug.php?id=55801&edit=1