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
Anyone can comment on a bug. Have a simpler test case? Does it work for you on a different platform? Let us know!
Just going to say 'Me too!'? Don't clutter the database with that please — but make sure to vote on the bug!
Your email address:
MUST BE VALID
Solve the problem:
40 + 25 = ?
Subscribe to this entry?

 
 [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-2024 The PHP Group
All rights reserved.
Last updated: Fri Apr 26 12:01:30 2024 UTC