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
Welcome back! If you're the original bug submitter, here's where you can edit the bug or add additional notes.
If this is not your bug, you can add a comment by following this link.
If this is your bug, but you forgot your password, you can retrieve your password here.
Password:
Status:
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: Mon May 13 21:01:31 2024 UTC