Edit report at https://bugs.php.net/bug.php?id=55801&edit=1

 ID:                 55801
 Updated by:         m...@php.net
 Reported by:        mapi at pdepend dot org
 Summary:            Behavior of unserialize has changed
-Status:             Assigned
+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:

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.


Previous Comments:
------------------------------------------------------------------------
[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.

------------------------------------------------------------------------
[2011-10-01 13:58:26] johan...@php.net

mike, seems like you broke this. Please take a look.

------------------------------------------------------------------------


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

Reply via email to