php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #64206 Serialized object becomes r:2, which breaks unserialization
Submitted: 2013-02-13 22:17 UTC Modified: 2013-08-19 20:48 UTC
Votes:1
Avg. Score:4.0 ± 0.0
Reproduced:1 of 1 (100.0%)
Same Version:0 (0.0%)
Same OS:0 (0.0%)
From: cameron dot junge at sella dot co dot nz Assigned: mike (profile)
Status: Wont fix Package: Scripting Engine problem
PHP Version: 5.4.11 OS: Ubuntu 12.10
Private report: No CVE-ID: None
View Add Comment Developer Edit
Welcome! If you don't have a Git account, you can't do anything here.
You can add a comment by following this link or if you reported this bug, you can edit this bug over here.
(description)
Block user comment
Status: Assign to:
Package:
Bug Type:
Summary:
From: cameron dot junge at sella dot co dot nz
New email:
PHP Version: OS:

 

 [2013-02-13 22:17 UTC] cameron dot junge at sella dot co dot nz
Description:
------------
When trying to serialize an inherited object, PHP 5.4 serializes the inherited object as a reference to the parent object, when there is no parent object to reference.

This works fine in PHP 5.3.

See test script for an example.

Test script:
---------------
class A implements \Serializable {

    public function serialize()
    {
        $s = new \stdClass();
        $s->id = 1;
        var_dump($s);
        return serialize($s);
    }
    public function unserialize($s)
    {
    }

}
class B extends A {

    public function serialize()
    {
        $p = parent::serialize();
        $s = unserialize($p);
        $s->foo = 'bar';
        $s2 = serialize($s);
        var_dump($p, $s, $s2); // $s2 = 'r:2'
        //var_dump(unserialize($s2)); // will throw error as can't unserialize
        die;
        //return serialize($s);
    }
}

$b = new B;
serialize($b);

Expected result:
----------------
// PHP5.3.6

object(stdClass)[794]
  public 'id' => int 1

string 'O:8:"stdClass":1:{s:2:"id";i:1;}' (length=32)

object(stdClass)[794]
  public 'id' => int 1
  public 'foo' => string 'bar' (length=3)

string 'O:8:"stdClass":2:{s:2:"id";i:1;s:3:"foo";s:3:"bar";}' (length=52)



Actual result:
--------------
// PHP 5.4.11
object(stdClass)[794]
  public 'id' => int 1

string 'O:8:"stdClass":1:{s:2:"id";i:1;}' (length=32)

object(stdClass)[794]
  public 'id' => int 1
  public 'foo' => string 'bar' (length=3)

string 'r:2;' (length=4)


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2013-02-17 02:33 UTC] laruence@php.net
-Status: Open +Status: Verified -Assigned To: +Assigned To: mike
 [2013-02-20 03:33 UTC] laruence@php.net
I tried to fix this by lock the serialize hash before calling ce->serialize, but 
it break #36424, result a stack overflow segfault.
 [2013-02-20 09:07 UTC] mike@php.net
After a quick look, I think the problem is rather the unserialize() call in the 
serialize() callback and vice-versa.
 [2013-02-20 10:42 UTC] mike@php.net
As the var_hash is kept between recursive serialize() calls, the serializer 
thinks the object is already serialized, but in fact, your hacky code replaces 
the previously serialized object.

I see two options:

- deny unserialize() in serialize()
- reset the serialize var_hash on unserialize() (which may break other things)
 [2013-02-20 14:47 UTC] laruence@php.net
I think deny unserialize in serialize is not a choice. it need a dynamic check and 
make no sense.

reseting one need to be test with...
 [2013-02-20 14:56 UTC] mike@php.net
What dynamic check? 

I guess a differentiated BG(serialize_lock)/BG(unserialize_lock) should do it.
 [2013-02-20 15:03 UTC] laruence@php.net
oh, then I understand wrongly about your "deny" word, hehe
 [2013-02-20 22:02 UTC] cameron dot junge at sella dot co dot nz
If unserialize is blocked inside serialize, then either the inherited class(es) need to know all the required properties from the parent class(es), which might cause a bit of a maintenance headache (one field changed in a base class means all inherited classes need to be updated).

A "solution" would be to use get_object_vars() in the base class and filter the properties returned, but that seems to me like a bit of a kludge. Would mean only serializing once, without the unserialize.

The use-case I've got is to prevent serializing a PDO connection inside classes that need to be persisted to memcache.
 [2013-08-19 20:48 UTC] mike@php.net
-Status: Verified +Status: Wont fix
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Sun Apr 28 23:01:32 2024 UTC