php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #62634 Incorrect serialization with circular references
Submitted: 2012-07-22 21:54 UTC Modified: 2017-12-09 14:13 UTC
From: phplists at stanvassilev dot com Assigned:
Status: Wont fix Package: Scripting Engine problem
PHP Version: 5.4.5 OS: Any
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: phplists at stanvassilev dot com
New email:
PHP Version: OS:

 

 [2012-07-22 21:54 UTC] phplists at stanvassilev dot com
Description:
------------
The documentation says references and circular references should serialize 
properly. I've found that serialize would first copy the referenced variable, 
before detecting the reference.

This not only doubles the serialized output, but produced incorrect copy when 
unserialized.

Test script:
---------------
$original = array('hello');
$original[] = & $original;

echo serialize($original);
// Output (notice the duplication):
// "a:2:{i:0;s:5:"hello";i:1;a:2:{i:0;s:5:"hello";i:1;R:3;}}"

$duplicate = unserialize(serialize($x));

// Now I modify both the original and the duplicate in an identical way.
// But I get different results, because the duplicate points to a copy of
// itself, instead of pointing to itself.

$original[0] = 'world';
$duplicate[0] = 'world';

var_dump($original);
// Produces (notice it says "world" both times, i.e. it points to itself):
// array(2) { [0]=> string(5) "world" [1]=> &array(2) { [0]=> string(5) "world" [1]=> *RECURSION* } } 

var_dump($duplicate);
// Produces (notice the second time it says "hello" i.e. it's a copy):
// array(2) { [0]=> string(5) "world" [1]=> &array(2) { [0]=> string(5) "hello" [1]=> *RECURSION* } }

Expected result:
----------------
There should be NO copies of "hello" left:

array(2) { [0]=> string(5) "world" [1]=> &array(2) { [0]=> string(5) "world" [1]=> 
*RECURSION* } }

There should be NO duplication in the serialized output:

"a:2:{i:0;s:5:"hello";i:1;???;}" (Fill-in the "???" appropriately :) )

Actual result:
--------------
A copy of "hello" is left:

array(2) { [0]=> string(5) "world" [1]=> &array(2) { [0]=> string(5) "hello" [1]=> 
*RECURSION* } }

There is duplication in the serialized output:

"a:2:{i:0;s:5:"hello";i:1;a:2:{i:0;s:5:"hello";i:1;R:3;}}"

Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2012-07-22 21:58 UTC] phplists at stanvassilev dot com
There's a small error in my code example, please replace this line:

    $duplicate = unserialize(serialize($x));

With this line:

    $duplicate = unserialize(serialize($original));
 [2012-07-25 13:25 UTC] fa@php.net
Maybe related to https://bugs.php.net/bug.php?id=62189
 [2013-03-16 18:09 UTC] nikic@php.net
The reason this happens is that serialize accepts by value, and as such the outer array will be a separated and will be different from the one that is references from within the array.

This can be fixed by marking the serialize argument as ZEND_SEND_PREFER_REF. Not sure if this should be done or not.
 [2013-10-04 14:23 UTC] mike@php.net
-Status: Open +Status: Analyzed
 [2017-12-09 14:13 UTC] nikic@php.net
-Status: Analyzed +Status: Wont fix
 [2017-12-09 14:13 UTC] nikic@php.net
serialize() accepts the argument by-value and unserialize() returns by-value, so it's not possible to preserve references at the outermost level. I doubt that we're going to change the function signatures to support this edge-case, so I'm closing this issue.
 
PHP Copyright © 2001-2017 The PHP Group
All rights reserved.
Last updated: Sun Nov 19 01:31:42 2017 UTC